//------------------------------------------------------------------- // Write the sample // HRESULT VidWriter::writeFrame(BYTE *pData) { HRESULT hr; IMFSample *pSample = NULL; const DWORD cbBuffer = 4 * m_width * m_height; // Unlock the buffer if (m_pBuffer) m_pBuffer->Unlock(); // Set the data length of the buffer hr = m_pBuffer->SetCurrentLength(cbBuffer); if (FAILED(hr)) goto done; // Create a media sample and add the buffer to it hr = MFCreateSample(&pSample); if (FAILED(hr)) goto done; hr = pSample->AddBuffer(m_pBuffer); if (FAILED(hr)) goto done; // Set the time stamp and the duration hr = pSample->SetSampleTime(m_rtStart); if (FAILED(hr)) goto done; hr = pSample->SetSampleDuration(m_frametime); if (FAILED(hr)) goto done; // increment the time stamp m_rtStart += m_frametime; // Send the sample to the Sink Writer hr = m_pWriter->WriteSample(m_streamIndex, pSample); done: SafeRelease(&pSample); return hr; }
IMFMediaBuffer * CDecWMV9MFT::CreateMediaBuffer(const BYTE * pData, DWORD dwDataLen) { HRESULT hr; IMFMediaBuffer *pBuffer = nullptr; hr = MF.CreateAlignedMemoryBuffer(dwDataLen, MF_16_BYTE_ALIGNMENT, &pBuffer); if (FAILED(hr)) { DbgLog((LOG_ERROR, 10, L"Unable to allocate MF Media Buffer, hr: 0x%x", hr)); goto done; } BYTE * pOutBuffer = nullptr; hr = pBuffer->Lock(&pOutBuffer, NULL, NULL); if (FAILED(hr)) { SafeRelease(&pBuffer); DbgLog((LOG_ERROR, 10, L"Unable to lock MF Media Buffer, hr: 0x%x", hr)); goto done; } memcpy(pOutBuffer, pData, dwDataLen); pBuffer->Unlock(); pBuffer->SetCurrentLength(dwDataLen); done: return pBuffer; }
HRESULT VideoEncoder::WriteTransitionSample(UINT64 sampleDuration, TransitionBase* pTransition, DWORD streamIndex, LONGLONG* startTime) { HRESULT hr = S_OK; IMFMediaBuffer* pMediaBuffer = nullptr; BYTE* pFrameBuffer = nullptr; IMFSample* pSample = nullptr; BYTE* pOutputFrame = nullptr; for (DWORD i = 0; i < sampleDuration; i++) { CheckHR(MFCreateMemoryBuffer(this->m_frameBufferSize, &pMediaBuffer)); pMediaBuffer->Lock(&pFrameBuffer, nullptr, nullptr); float time = (float)i / (float)sampleDuration; pOutputFrame = pTransition->GetOutputFrame(time); CheckHR(MFCopyImage(pFrameBuffer, this->m_frameStride, pOutputFrame, this->m_frameStride, this->m_frameStride, this->m_frameHeight)); CheckHR(pMediaBuffer->Unlock()); CheckHR(pMediaBuffer->SetCurrentLength(this->m_frameBufferSize)); CheckHR(MFCreateSample(&pSample)); CheckHR(pSample->AddBuffer(pMediaBuffer)); CheckHR(pSample->SetSampleTime(*startTime)); CheckHR(pSample->SetSampleDuration(this->GetFrameDuration())); CheckHR(this->m_pSinkWriter->WriteSample(streamIndex, pSample)); (*startTime) += this->GetFrameDuration(); // 释放示例资源. SafeRelease(&pMediaBuffer); SafeRelease(&pSample); if (pOutputFrame != nullptr) { delete pOutputFrame; pOutputFrame = nullptr; } } cleanup: if (!SUCCEEDED(hr)) { DWORD error = GetLastError(); this->m_logFileStream << "意外错误: " << error << endl; } SafeRelease(&pMediaBuffer); SafeRelease(&pSample); if (pOutputFrame != nullptr) { delete pOutputFrame; pOutputFrame = nullptr; } return hr; }
HRESULT CASFManager::ReadDataIntoBuffer( IMFByteStream *pStream, // Pointer to the byte stream. DWORD cbOffset, // Offset at which to start reading DWORD cbToRead, // Number of bytes to read IMFMediaBuffer **ppBuffer // Receives a pointer to the buffer. ) { HRESULT hr = S_OK; BYTE *pData = NULL; DWORD cbRead = 0; // Actual amount of data read IMFMediaBuffer *pBuffer = NULL; // Create the media buffer. This function allocates the memory. CHECK_HR(hr = MFCreateMemoryBuffer(cbToRead, &pBuffer)); // Access the buffer. CHECK_HR(hr = pBuffer->Lock(&pData, NULL, NULL)); //Set the offset CHECK_HR(hr = pStream->SetCurrentPosition(cbOffset)); // Read the data from the byte stream. CHECK_HR(hr = pStream->Read(pData, cbToRead, &cbRead)); CHECK_HR(hr = pBuffer->Unlock()); pData = NULL; // Update the size of the valid data. CHECK_HR(hr = pBuffer->SetCurrentLength(cbRead)); // Return the pointer to the caller. *ppBuffer = pBuffer; (*ppBuffer)->AddRef(); TRACE((L"Read data from the ASF file into a media buffer.\n")); done: LOG_MSG_IF_FAILED(L"CASFManager::ReadDataIntoBuffer failed.\n", hr); if (pData) { pBuffer->Unlock(); } SAFE_RELEASE(pBuffer); return hr; }
IMFSample* create_sample(void *data, DWORD len, DWORD alignment, LONGLONG duration) { HRESULT hr = S_OK; IMFMediaBuffer *buf = NULL; IMFSample *sample = NULL; hr = MFCreateSample(&sample); if (FAILED(hr)) { ReportError(L"Unable to allocate a sample", hr); return NULL; } // Yes, the argument for alignment is the actual alignment - 1 hr = MFCreateAlignedMemoryBuffer(len, alignment - 1, &buf); if (FAILED(hr)) { ReportError(L"Unable to allocate a memory buffer for sample", hr); return NULL; } if (data) { BYTE *buffer; // lock the MediaBuffer // this is actually not a thread-safe lock hr = buf->Lock(&buffer, NULL, NULL); if (FAILED(hr)) { SafeRelease(&sample); SafeRelease(&buf); return NULL; } memcpy(buffer, data, len); buf->SetCurrentLength(len); buf->Unlock(); } sample->AddBuffer(buf); hr = sample->SetSampleDuration(duration); SafeRelease(&buf); return sample; }
// Process any pending output from the decoder (until all output is // processed). // // Thread context: decoder thread bool DecoderMF::DoProcessOutput() { bool ret = false; HRESULT hr; MFT_OUTPUT_DATA_BUFFER mftDataBuffer; DWORD mftStatus; bool moreOutput; if (m_outputSample == NULL) { if (! CreateOutputSample()) return false; } do { // Since we could be looping inside this method for a while, // if a whole stack of frames arrive at once, we want to exit // if the thread has been asked to die. So check on each // iteration of the loop. if (! m_decoderThreadRunning) return true; moreOutput = false; mftDataBuffer.dwStreamID = 0; mftDataBuffer.pSample = m_outputSample; mftDataBuffer.dwStatus = 0; mftDataBuffer.pEvents = NULL; mftStatus = 0; // Looks like we have to reset the sample before use: IMFMediaBuffer* mediaBuffer; hr = m_outputSample->GetBufferByIndex(0, &mediaBuffer); if (FAILED(hr)) goto bail; hr = mediaBuffer->SetCurrentLength(0); if (FAILED(hr)) goto bail; mediaBuffer->Release(); hr = m_h264Decoder->ProcessOutput(0, 1, &mftDataBuffer, &mftStatus); // Check return code if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) break; EnterCriticalSection(&m_criticalSection); if (hr == MF_E_TRANSFORM_STREAM_CHANGE || !m_previewConfigured) { // If the output format has changed, we need to handle // the stream change. This will happen after the first // few packets have been delivered. moreOutput = HandleStreamChange(); LeaveCriticalSection(&m_criticalSection); if (!moreOutput) goto bail; continue; } LeaveCriticalSection(&m_criticalSection); if (FAILED(hr)) goto bail; if (mftDataBuffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE) moreOutput = true; // Process each event: if (mftDataBuffer.pEvents != NULL) { DWORD numElements; hr = mftDataBuffer.pEvents->GetElementCount(&numElements); if (SUCCEEDED(hr)) { for (DWORD i = 0; i < numElements; i++) { IUnknown* iunk = NULL; hr = mftDataBuffer.pEvents->GetElement(i, &iunk); if (SUCCEEDED(hr)) { IMFMediaEvent* mediaEvent = NULL; hr = iunk->QueryInterface(IID_IMFMediaEvent, (void**)&mediaEvent); if (SUCCEEDED(hr)) { OutputDebugString(_T("FIXME: process event!\n")); mediaEvent->Release(); } iunk->Release(); } } } mftDataBuffer.pEvents = NULL; } // Process sample: if (mftDataBuffer.pSample != NULL) { IMFMediaBuffer* mediaBuffer; hr = mftDataBuffer.pSample->GetBufferByIndex(0, &mediaBuffer); if (FAILED(hr)) goto bail; EnterCriticalSection(&m_criticalSection); if (m_previewWindow != NULL && m_previewConfigured) m_previewWindow->DrawFrame(mediaBuffer); LeaveCriticalSection(&m_criticalSection); mediaBuffer->Release(); } } while(moreOutput); ret = true; bail: if (ret == false) OutputDebugString(_T("ERROR: failed to process output...\n")); return ret; }
// Process the incomming NAL from the queue: wraps it up into a // IMFMediaSample, sends it to the decoder. // // Thread context: decoder thread bool DecoderMF::DoProcessInputNAL(IBMDStreamingH264NALPacket* nalPacket) { bool ret = false; HRESULT hr; IMFMediaBuffer* newBuffer = NULL; BYTE* newBufferPtr; void* nalPacketPtr; // IMFSample* newSample = NULL; ULONGLONG nalPresentationTime; const BYTE nalPrefix[] = {0, 0, 0, 1}; // Get a pointer to the NAL data hr = nalPacket->GetBytes(&nalPacketPtr); if (FAILED(hr)) goto bail; // Create the MF media buffer (+ 4 bytes for the NAL Prefix (0x00 0x00 0x00 0x01) // which MF requires. hr = MFCreateMemoryBuffer(nalPacket->GetPayloadSize()+4, &newBuffer); if (FAILED(hr)) goto bail; // Lock the MF media buffer hr = newBuffer->Lock(&newBufferPtr, NULL, NULL); if (FAILED(hr)) goto bail; // Copy the prefix and the data memcpy(newBufferPtr, nalPrefix, 4); memcpy(newBufferPtr+4, nalPacketPtr, nalPacket->GetPayloadSize()); // Unlock the MF media buffer hr = newBuffer->Unlock(); if (FAILED(hr)) goto bail; // Update the current length of the MF media buffer hr = newBuffer->SetCurrentLength(nalPacket->GetPayloadSize()+4); if (FAILED(hr)) goto bail; // We now have a IMFMediaBuffer with the contents of the NAL // packet. We now construct a IMFSample with the buffer hr = MFCreateSample(&newSample); if (FAILED(hr)) goto bail; hr = newSample->AddBuffer(newBuffer); if (FAILED(hr)) goto bail; // Get the presentation (display) time in 100-nanosecond units // TODO: this is pretty meaningless without setting the start time. hr = nalPacket->GetDisplayTime(1000 * 1000 * 10, &nalPresentationTime); if (FAILED(hr)) goto bail; // Set presentation time on the sample hr = newSample->SetSampleTime(nalPresentationTime); if (FAILED(hr)) goto bail; // Now parse it to the decoder for (;;) { hr = m_h264Decoder->ProcessInput(0, newSample, 0); if (hr == S_OK) break; if (hr != MF_E_NOTACCEPTING || DoProcessOutput() == false) goto bail; } ret = true; bail: if (newBuffer != NULL) newBuffer->Release(); if (newSample != NULL) newSample->Release(); return ret; }
HRESULT WavStream::CreateAudioSample(IMFSample **ppSample) { HRESULT hr = S_OK; IMFMediaBuffer *pBuffer = NULL; IMFSample *pSample = NULL; DWORD cbBuffer = 0; BYTE *pData = NULL; LONGLONG duration = 0; // Start with one second of data, rounded up to the nearest block. cbBuffer = AlignUp<DWORD>(m_pRiff->Format()->nAvgBytesPerSec, m_pRiff->Format()->nBlockAlign); // Don't request any more than what's left. cbBuffer = min(cbBuffer, m_pRiff->BytesRemainingInChunk()); // Create the buffer. hr = MFCreateMemoryBuffer(cbBuffer, &pBuffer); // Get a pointer to the buffer memory. if (SUCCEEDED(hr)) { hr = pBuffer->Lock(&pData, NULL, NULL); } // Fill the buffer if (SUCCEEDED(hr)) { hr = m_pRiff->ReadDataFromChunk(pData, cbBuffer); } // Unlock the buffer. if (SUCCEEDED(hr)) { hr = pBuffer->Unlock(); pData = NULL; } // Set the size of the valid data in the buffer. if (SUCCEEDED(hr)) { hr = pBuffer->SetCurrentLength(cbBuffer); } // Create a new sample and add the buffer to it. if (SUCCEEDED(hr)) { hr = MFCreateSample(&pSample); } if (SUCCEEDED(hr)) { hr = pSample->AddBuffer(pBuffer); } // Set the time stamps, duration, and sample flags. if (SUCCEEDED(hr)) { hr = pSample->SetSampleTime(m_rtCurrentPosition); } if (SUCCEEDED(hr)) { duration = AudioDurationFromBufferSize(m_pRiff->Format(), cbBuffer); hr = pSample->SetSampleDuration(duration); } // Set the discontinuity flag. if (SUCCEEDED(hr)) { if (m_discontinuity) { hr = pSample->SetUINT32(MFSampleExtension_Discontinuity, TRUE); } } if (SUCCEEDED(hr)) { // Update our current position. m_rtCurrentPosition += duration; // Give the pointer to the caller. *ppSample = pSample; (*ppSample)->AddRef(); } if (pData && pBuffer) { hr = pBuffer->Unlock(); } SafeRelease(&pBuffer); SafeRelease(&pSample); return hr; }
void VideoCompressor::AudioSample32Bit2Channel(float *Samples, UINT FrameCount, UINT64 CaptureStartTime) { //double TimeInSeconds = _Clock->Elapsed(); const UINT SamplesPerSecond = 44100; const UINT ChannelCount = 2; const UINT SampleCount = FrameCount * ChannelCount; const UINT BitsPerSample = 16; const UINT BufferLength = BitsPerSample / 8 * ChannelCount * FrameCount; const LONGLONG SampleDuration = LONGLONG(FrameCount) * LONGLONG(10000000) / SamplesPerSecond; // in hns // // Write some data // IMFSample *spSample; IMFMediaBuffer *spBuffer; BYTE *pbBuffer = NULL; // // Create a media sample // HRESULT hr = MFCreateSample( &spSample ); hr = spSample->SetSampleDuration( SampleDuration ); //hr = spSample->SetSampleTime( LONGLONG( TimeInSeconds * 10000000.0 ) ); //CaptureStartTime = 10,000,000 * t / f; //t = CaptureStartTime * f / 10,000,000 LONGLONG FileStartCounter = _Clock->StartTime(); LONGLONG CaptureStartCounter = CaptureStartTime * _Clock->TicksPerSecond() / LONGLONG(10000000); hr = spSample->SetSampleTime( ( CaptureStartCounter - FileStartCounter ) * LONGLONG(10000000) / _Clock->TicksPerSecond() ); // // Add a media buffer filled with random data // hr = MFCreateMemoryBuffer( BufferLength, &spBuffer ); hr = spBuffer->SetCurrentLength( BufferLength ); hr = spSample->AddBuffer( spBuffer ); hr = spBuffer->Lock( &pbBuffer, NULL, NULL ); __int16 *OutputAudioBuffer = (__int16 *)pbBuffer; for(UINT SampleIndex = 0; SampleIndex < SampleCount; SampleIndex++) { // // Floats are in the range -1 to 1 // OutputAudioBuffer[SampleIndex] = int(Samples[SampleIndex] * 32768.0f); } hr = spBuffer->Unlock(); // // Write the media sample // hr = _Writer->WriteSample( 1, spSample ); PersistentAssert(SUCCEEDED(hr), "WriteSample failed"); spSample->Release(); spBuffer->Release(); }