📄 htrencftr.cpp
字号:
return VFW_S_NO_MORE_ITEMS;
}
// Convert wrapper videoType to GUID and FOURCC
const GUID* pVideoTypeGuid;
DWORD videoTypeFourcc;
if( m_settings.videoType == CHantroEncoderWrapper::VIDEOTYPE_MPEG4 )
{
pVideoTypeGuid = &ENCOUTPUT_MP4V;
videoTypeFourcc = MAKEFOURCC('M', 'P', '4', 'V');
}
else
{
pVideoTypeGuid = &ENCOUTPUT_H263;
videoTypeFourcc = MAKEFOURCC('H', '2', '6', '3');
}
pMediaType->InitMediaType();
pMediaType->SetType( &MEDIATYPE_Video );
pMediaType->SetSubtype( pVideoTypeGuid );
pMediaType->SetFormatType( &FORMAT_VideoInfo );
pMediaType->SetVariableSize();
pMediaType->SetTemporalCompression(TRUE);
VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*)pMediaType->AllocFormatBuffer( sizeof(VIDEOINFOHEADER) );
if( pVih == NULL )
{
HTRENC_DEBUG( "CHtrEncFltr::GetMediaType: FAILED allocating format buffer!\n" );
return E_OUTOFMEMORY;
}
// Use cached avgTimePerFrame is present. Otherwise calculate from frameRate.
pVih->AvgTimePerFrame = m_cachedAvgFrameTime != 0 ? m_cachedAvgFrameTime :
HTRENC_FRAMERATE2TIME(m_settings.frameRate);
pVih->bmiHeader.biBitCount = 0;
pVih->bmiHeader.biClrImportant = 0;
pVih->bmiHeader.biClrUsed = 0;
pVih->bmiHeader.biCompression = videoTypeFourcc;
pVih->bmiHeader.biWidth = m_settings.frameWidth;
pVih->bmiHeader.biHeight = m_settings.frameHeight;
pVih->bmiHeader.biPlanes = 1;
pVih->bmiHeader.biSize = 0;
pVih->bmiHeader.biSizeImage = 0;
pVih->bmiHeader.biXPelsPerMeter = 0;
pVih->bmiHeader.biYPelsPerMeter = 0;
pVih->dwBitRate = m_settings.bitrate;
pVih->dwBitErrorRate = 0;
pVih->rcSource.bottom = 0;
pVih->rcSource.left = 0;
pVih->rcSource.right = 0;
pVih->rcSource.top = 0;
pVih->rcTarget.bottom = 0;
pVih->rcTarget.left = 0;
pVih->rcTarget.right = 0;
pVih->rcTarget.top = 0;
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::GetMediaType Ok\n" );
return S_OK;
}
HRESULT CHtrEncFltr::SetMediaType( PIN_DIRECTION direction, const CMediaType* pmt )
{
// No action when setting input format, settings are already
// incorporated in CheckInputType
if( direction == PINDIR_INPUT ) return S_OK;
// One assumes that SetMediaType is called after type has been checked,
// so *no* duplicated check is done here!
VIDEOINFOHEADER* vih = reinterpret_cast<VIDEOINFOHEADER*>(pmt->Format());
BITMAPINFOHEADER* bh = &vih->bmiHeader;
m_settings.videoType = *pmt->Subtype() == ENCOUTPUT_MP4V || *pmt->Subtype() == ENCOUTPUT_mp4v ?
CHantroEncoderWrapper::VIDEOTYPE_MPEG4 :
CHantroEncoderWrapper::VIDEOTYPE_H263;
if( vih->AvgTimePerFrame != 0 )
{
m_settings.frameRate = (LONG)HTRENC_FRAMETIME2RATE(vih->AvgTimePerFrame);
m_cachedAvgFrameTime = vih->AvgTimePerFrame;
}
if( vih->dwBitRate != 0 )
{
m_settings.bitrate = vih->dwBitRate;
}
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::SetMediaType (diretion=%d) Ok\n", direction );
return S_OK;
}
HRESULT CHtrEncFltr::Transform(IMediaSample* pIn, IMediaSample* pOut)
{
HRESULT hr;
BYTE* pInputBuffer;
BYTE* pOutputBuffer;
LONG outputBufSize;
DWORD pInputBufferBusAddr, pOutputBufferBusAddr;
REFERENCE_TIME start, end;
BOOL keyFrame = FALSE;
// Get the pointer to the input buffer & the physical address
hr = pIn->GetPointer(&pInputBuffer);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform failed to get the input buffer\n" );
return hr;
}
// Get bus address for input buffer
hr = ((CHtrEncInputPin*)m_pInput)->m_pHtrAlloc->MapToPhysicalAddr(pInputBuffer, &pInputBufferBusAddr);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform failed to map the virtual address to physical\n" );
return hr;
}
// Get the pointer to the output buffer, size of the output buffer & the physical address
hr = pOut->GetPointer(&pOutputBuffer);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform failed to get the output buffer\n" );
return hr;
}
outputBufSize = pOut->GetSize();
// Get bus address for output buffer
hr = ((CHtrEncOutputPin*)m_pOutput)->m_pHtrAlloc->MapToPhysicalAddr(pOutputBuffer, &pOutputBufferBusAddr);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform failed to map the virtual address to physical\n" );
return hr;
}
// Get the timing for the sample
hr = pIn->GetTime(&start, &end);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform failed to get timing for the sample\n" );
return hr;
}
// Encode the stream
hr = m_pWrapper->Encode( pInputBufferBusAddr, &start, &end, pOutputBuffer, pOutputBufferBusAddr, &outputBufSize, &keyFrame );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform failed to encode the frame\n" );
return hr;
}
// Set the timestamp according to start and end times
hr = pOut->SetTime(&start, &end);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform setting the time stamp failed\n" );
return hr;
}
hr = pOut->SetActualDataLength(outputBufSize);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::Transform failed to set actual data length\n" );
return hr;
}
return S_OK;
}
HRESULT CHtrEncFltr::StartStreaming()
{
// Get the downstream buffer to fill (downstream filter should be already running)
IMediaSample* pOutSample;
BYTE* pBuffer;
LONG size;
HRESULT hr;
hr = m_pOutput->GetDeliveryBuffer( &pOutSample, NULL, NULL, 0 );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::StartStreaming: FAILED getting delivery buffer for stream headers!\n" );
return hr;
}
size = pOutSample->GetSize();
hr = pOutSample->GetPointer(&pBuffer);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::StartStreaming: pOutSample->GetPointer FAILED!\n" );
pOutSample->Release();
return hr;
}
// Create the encoder wrapper instance
m_pWrapper = new CHantroEncoderWrapper();
if( m_pWrapper == NULL )
{
HTRENC_DEBUG( "CHtrEncFltr::StartStreaming: FAILED creating encoder wrapper!\n" );
return E_OUTOFMEMORY;
}
// Initialize the encoder
hr = m_pWrapper->Init( &m_settings );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::StartStreaming: pWrapper->Init FAILED!\n" );
pOutSample->Release();
return hr;
}
// Generate the stream headers and set the output correctly
hr = m_pWrapper->StartStream( pBuffer, &size );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::StartStreaming: pWrapper->StartStream FAILED!\n" );
pOutSample->Release();
return hr;
}
// Output only if headers were in fact generated
if( size>0 )
{
hr = pOutSample->SetActualDataLength(size);
// Deliver the sample downstream
hr = m_pOutput->Deliver( pOutSample );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::StartStreaming: pOutSample->Deliver FAILED!\n" );
pOutSample->Release();
return hr;
}
}
// Release the sample
pOutSample->Release();
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::StartStreaming: Ok!\n" );
return S_OK;
}
HRESULT CHtrEncFltr::EndOfStream()
{
// Get the downstream buffer
IMediaSample* pOutSample;
HRESULT hr;
hr = m_pOutput->GetDeliveryBuffer( &pOutSample, NULL, NULL, 0 );
if (FAILED(hr)) {
return hr;
}
BYTE* pBuffer;
LONG size;
size = pOutSample->GetSize();
hr = pOutSample->GetPointer(&pBuffer);
if (FAILED(hr)) {
pOutSample->Release();
return hr;
}
hr = m_pWrapper->EndStream(pBuffer, &size);
if( FAILED(hr) )
{
// Release the sample
pOutSample->Release();
return hr;
}
// Output only if "footers" were generated
if( size>0 )
{
// Fix size for sample
hr = pOutSample->SetActualDataLength( size );
// Deliver the sample downstream
hr = m_pOutput->Deliver( pOutSample );
if( FAILED(hr) )
{
// Release the sample
pOutSample->Release();
return hr;
}
}
// Release the sample
pOutSample->Release();
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::EndOfStream Ok!\n" );
return CTransformFilter::EndOfStream();
}
CBasePin* CHtrEncFltr::GetPin(int n)
{
HRESULT hr = S_OK;
// Test for input pin
if( n == 0 )
{
// Create pin if necessary
if( m_pInput == NULL )
{
m_pInput = new CHtrEncInputPin( NAME("Hantro Encoder Input Pin"),
this, &hr, L"HtrEnc In" );
}
// Workaround: make sure GetPin does not fail, otherwise the destruction of
// the graph filter gets stucked.
ASSERT( m_pInput && SUCCEEDED(hr) );
// if( m_pInput == NULL )
// {
// HTRENC_DEBUG( "CHtrEncFltr::GetPin: FAILED creating input pin (memory allocation?)\n" );
// return NULL;
// }
// if( FAILED(hr) )
// {
// HTRENC_DEBUG( "CHtrEncFltr::GetPin: FAILED creating input pin (wrong parameters?)\n" );
// delete m_pInput;
// m_pInput = NULL;
// return NULL;
// }
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::GetPin Ok!\n" );
return m_pInput;
}
// Test output pin
else if( n == 1 )
{
// Create pin if necessary
if( m_pOutput == NULL )
{
m_pOutput = new CHtrEncOutputPin( NAME("Hantro Encoder Output Pin"),
this, &hr, L"HtrEnc Out" );
}
// Workaround: make sure GetPin does not fail, otherwise the destruction of
// the graph filter gets stucked.
ASSERT( m_pOutput && SUCCEEDED(hr) );
// if( m_pOutput == NULL )
// {
// HTRENC_DEBUG( "CHtrEncFltr::GetPin: FAILED creating output pin\n" );
// return NULL;
// }
// if( FAILED(hr) )
// {
// HTRENC_DEBUG( "CHtrEncFltr::GetPin: FAILED creating output pin\n" );
// delete m_pOutput;
// m_pOutput = NULL;
// return NULL;
// }
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::GetPin (n=1, outputPin) Ok!\n" );
return m_pOutput;
}
HTRENC_DEBUG( "CHtrEncFltr::GetPin: FAILED, unkown pin index %d\n", n );
return NULL;
}
/*------------------------------------------------------------------------------
5. CHtrEncPhysicalAllocator class
------------------------------------------------------------------------------*/
CHtrEncPhysicalAllocator::CHtrEncPhysicalAllocator(HRESULT* phr)
: CBaseAllocator(NAME("Hantro Custom Physical Memory Allocator"), NULL, phr),
m_pMappingsList(NULL)
{
}
STDMETHODIMP CHtrEncPhysicalAllocator::NonDelegatingQueryInterface(REFIID iid, void **ppv)
{
if (iid == IID_IHtrAllocator ) {
return GetInterface(static_cast<IHtrAllocator*>(this), ppv);
}
return CBaseAllocator::NonDelegatingQueryInterface(iid,ppv);
}
HRESULT CHtrEncPhysicalAllocator::MapToPhysicalAddr(LPVOID pVirAddr, DWORD* pPhysAddr)
{
Mapping* map;
// Find the mapping
map = FindMapping(pVirAddr);
if( map != NULL )
{
*pPhysAddr = map->pPhysAddr;
HTRENC_DEBUG_EXTRA( "CHtrEncPhysicalAllocator::MapToPhysicalAddr Ok\n" );
return S_OK;
}
// No mapping found
HTRENC_DEBUG( "CHtrEncPhysicalAllocator::MapToPhysicalAddr FAILED, no mapping from virtual to physical address found\n" );
// Can't return E_FAIL because the graph will hang if we do
return S_FALSE;
}
HRESULT CHtrEncPhysicalAllocator::AddMapping(LPVOID pVirAddr, DWORD physAddr)
{
// Create a new mapping
Mapping* mapping = new Mapping( pVirAddr, physAddr );
if( NULL == mapping )
{
HTRENC_DEBUG( "CHtrEncPhysicalAllocator::AddMapping FAILED, out of memory\n" );
return E_OUTOFMEMORY;
}
// Add it to our list of mappings
if( NULL == m_pMappingsList )
{
m_pMappingsList = mapping;
HTRENC_DEBUG_EXTRA( "CHtrEncPhysicalAllocator::AddMapping Ok\n" );
return S_OK;
}
Mapping* pNext = m_pMappingsList;
while( pNext->p_next != NULL )
{
pNext = pNext->p_next;
}
pNext->p_next = mapping;
HTRENC_DEBUG_EXTRA( "CHtrEncPhysicalAllocator::AddMapping Ok\n" );
return S_OK;
}
CHtrEncPhysicalAllocator::Mapping* CHtrEncPhysicalAllocator::FindMapping(LPVOID pVirAddr)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -