📄 htrencftr.cpp
字号:
/*------------------------------------------------------------------------------
-- --
-- This software is confidential and proprietary and may be used --
-- only as expressly authorized by a licensing agreement from --
-- --
-- Hantro Products Oy. --
-- --
-- In the event of publication, the following notice is applicable: --
-- --
-- (C) COPYRIGHT 2005 HANTRO PRODUCTS OY --
-- ALL RIGHTS RESERVED --
-- --
-- The entire notice above must be reproduced on all copies. --
-- --
--------------------------------------------------------------------------------
--
-- Abstract : Transform filter for Hantro HW encoder in DirectShow integration
--
-------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
Table of context
1. Include headers
2. Module defines
3. DLL entry points
4. CHtrEncFltr class
5. CHtrEncPhysicalAllocator class
6. CHtrEncInputPin class
7. CHtrEncOutputPin class
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
1. Include headers
------------------------------------------------------------------------------*/
#include "stdafx.h"
#include <stdio.h>
#include "htrencftr.h"
#include "htrencwrapper.h"
#ifdef UNDER_CE
#include "pkfuncs.h" // For AllocPhysMem
#endif /* UNDER_CE */
/*------------------------------------------------------------------------------
2. Module defines
------------------------------------------------------------------------------*/
#define HTRENC_DEBUG printf
#define HTRENC_DEBUG_EXTRA //printf
// t = frameDuration ; REFERENCE_TIME, 100ns units (10.000.000 units in 1s)
// fr = 10.000.000 / (t/1000) ; frame/1000s
// fr = (fr+999)/1000 ; rounded frame/s
#define HTRENC_FRAMETIME2RATE(t) ( ((REFERENCE_TIME)10000000000 / (REFERENCE_TIME)(t) + 999)/1000 )
// r = frameRate ; frame/s
// t = 10.000.000/r ; duration, in 100ns units
#define HTRENC_FRAMERATE2TIME(r) ((REFERENCE_TIME)10000000/(REFERENCE_TIME)(r))
static const WCHAR g_wszName[] = L"Hantro MPEG-4/H.263 Video Encoder Filter";
AMOVIESETUP_MEDIATYPE inputMediaTypes[] = {
{ &MEDIATYPE_Video, &MEDIASUBTYPE_IYUV }
};
AMOVIESETUP_MEDIATYPE outputMediaTypes[] = {
{ &MEDIATYPE_Video, &ENCOUTPUT_MP4V }, // MPEG-4
{ &MEDIATYPE_Video, &ENCOUTPUT_mp4v }, // mpeg-4
{ &MEDIATYPE_Video, &ENCOUTPUT_H263 }, // H.263
{ &MEDIATYPE_Video, &ENCOUTPUT_h263 } // h.263
};
AMOVIESETUP_PIN inputPin = {
L"", // Obsolete, not used.
FALSE, // Is this pin rendered?
FALSE, // Is it an output pin?
FALSE, // Can the filter create zero instances?
FALSE, // Does the filter create multiple instances?
&GUID_NULL, // Obsolete.
NULL, // Obsolete.
1, // Number of media types.
inputMediaTypes // Pointer to media types.
};
AMOVIESETUP_PIN outputPin = {
L"", // Obsolete, not used.
FALSE, // Is this pin rendered?
TRUE, // Is it an output pin?
FALSE, // Can the filter create zero instances?
FALSE, // Does the filter create multiple instances?
&GUID_NULL, // Obsolete.
NULL, // Obsolete.
4, // Number of media types.
outputMediaTypes // Pointer to media types.
};
AMOVIESETUP_PIN pins[2] =
{
inputPin,
outputPin
};
AMOVIESETUP_FILTER encFilterReg = {
&CLSID_HtrEncFltr, // Filter CLSID.
g_wszName, // Filter name.
MERIT_NORMAL, // Merit.
2, // Number of pin types.
pins // Pointer to pin information.
};
#ifndef UNDER_CE
// Declare filter information.
REGFILTER2 rf2EncFilterReg = {
1, // Version number.
MERIT_NORMAL, // Merit.
2, // Number of pins.
pins // Pointer to pin information.
};
#endif /* UNDER_CE */
CFactoryTemplate g_Templates[1] =
{
{
L"Hantro MPEG-4/H.263 Video Encoder Filter", // Name
&CLSID_HtrEncFltr, // CLSID
CHtrEncFltr::CreateInstance, // Method to create an instance of CHtrEncFltr
NULL, // Initialization function
&encFilterReg // Set-up information (for filters)
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
/*------------------------------------------------------------------------------
2. DLL entry points
------------------------------------------------------------------------------*/
// Entry point for the DLL
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
STDAPI DllRegisterServer()
{
HRESULT hr = AMovieDllRegisterServer2( TRUE );
if (FAILED(hr))
{
return hr;
}
#ifndef UNDER_CE
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->RegisterFilter(
CLSID_HtrEncFltr, // Filter CLSID.
g_wszName, // Filter name.
NULL, // Device moniker.
&CLSID_VideoCompressorCategory, // Video compressor category.
g_wszName, // Instance data.
&rf2EncFilterReg // Filter information.
);
pFM2->Release();
}
#endif /* UNDER_CE */
return hr;
}
STDAPI DllUnregisterServer()
{
HRESULT hr = AMovieDllRegisterServer2(FALSE);
if (FAILED(hr))
{
return hr;
}
#ifndef UNDER_CE
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory,
g_wszName, CLSID_HtrEncFltr);
pFM2->Release();
}
#endif /* UNDER_CE */
return hr;
}
/*------------------------------------------------------------------------------
4. CHtrEncFltr class
------------------------------------------------------------------------------*/
// Public method that returns a new instance.
CUnknown * WINAPI CHtrEncFltr::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CHtrEncFltr* pNewEnc = new CHtrEncFltr(NAME("Hantro MPEG-4/H.263 Video Encoder Filter"), pUnk, pHr);
if (pNewEnc == NULL) {
*pHr = E_OUTOFMEMORY;
}
return pNewEnc;
}
CHtrEncFltr::CHtrEncFltr(TCHAR* pObjectName, LPUNKNOWN pUnk, HRESULT *pHr)
: CTransformFilter(pObjectName, pUnk, CLSID_HtrEncFltr)
, m_pWrapper(NULL), m_cachedAvgFrameTime(0)
{
// Set default encoding settings, overridable by output and/or input pin.
// Frame rate is taken from input format, if present, and also exposed
// on output pin for correct settings. Video size must be taken from
// from input format.
m_settings.videoType = CHantroEncoderWrapper::VIDEOTYPE_MPEG4;
// m_settings.videoType = CHantroEncoderWrapper::VIDEOTYPE_H263;
m_settings.bitrate = 384000;
m_settings.frameRate = 30;
m_settings.intraRefreshRate = 90;
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::CHtrEncFltr Ok\n" );
}
CHtrEncFltr::~CHtrEncFltr(void)
{
delete m_pWrapper;
}
HRESULT CHtrEncFltr::CheckInputType(const CMediaType* mtIn)
{
// Check that input type is video of IYUV format
if( *mtIn->Type() != *((GUID*)inputMediaTypes[0].clsMajorType) ||
*mtIn->Subtype() != *((GUID*)inputMediaTypes[0].clsMinorType) )
{
HTRENC_DEBUG( "CHtrEncFltr::CheckInputType FAILED, input major or subtype mismatch\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
// Check the format type (could be that it is not defined as well)
if( !mtIn->IsPartiallySpecified() )
{
const GUID* formatType = mtIn->FormatType();
if( *formatType != FORMAT_VideoInfo )
{
HTRENC_DEBUG( "CHtrEncFltr::CheckInputType FAILED, invalid format description\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
VIDEOINFOHEADER* vih = reinterpret_cast<VIDEOINFOHEADER*>(mtIn->Format());
BITMAPINFOHEADER bh = vih->bmiHeader;
HRESULT hr = S_OK;
// Double check color space 'iyuv' (FourCC)
if( bh.biCompression != MAKEFOURCC('I', 'Y', 'U', 'V') &&
bh.biCompression != MAKEFOURCC('i', 'y', 'u', 'v') )
{
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, invalid compression type in format description\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
// Validate and use settings from input format: video size and frame rate (if present).
// Important! Default values for encoder settings must be carefuly chosen as validation
// is done using new input settings *and* default values
CHantroEncoderWrapper::Settings inputSettings = m_settings;
inputSettings.frameWidth = bh.biWidth;
inputSettings.frameHeight = bh.biHeight;
if( vih->AvgTimePerFrame != 0 )
{
inputSettings.frameRate = (LONG)HTRENC_FRAMETIME2RATE(vih->AvgTimePerFrame);
}
hr = CHantroEncoderWrapper::ValidateSettings( &inputSettings );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::CheckInputType FAILED, invalid video size and/or frame rate\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
// Incorporate new encoder settings and make a cache copy of
// avgTimePerFrame to avoid rounding errors
m_settings = inputSettings;
m_cachedAvgFrameTime = vih->AvgTimePerFrame;
}
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::CheckInputType Ok\n" );
return S_OK;
}
HRESULT CHtrEncFltr::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
{
// Firstly validate the input
if( FAILED(CheckInputType(mtIn)) )
{
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, input type mismatch\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
// Check that desired output type is either MPEG-4 or H.263
for( int i=0; i<sizeof(inputMediaTypes)/sizeof(inputMediaTypes[0]); i++ )
{
if( *mtOut->Type() == *((GUID*)outputMediaTypes[i].clsMajorType) ||
*mtOut->Subtype() == *((GUID*)outputMediaTypes[i].clsMinorType) )
{
if( !mtOut->IsPartiallySpecified() )
{
const GUID* formatType = mtOut->FormatType();
if( *formatType == FORMAT_VideoInfo )
{
VIDEOINFOHEADER* vih = reinterpret_cast<VIDEOINFOHEADER*>(mtOut->Format());
BITMAPINFOHEADER& bh = vih->bmiHeader;
// We'll ignore the biCompression flag in the bitmap header as the
// submediatype is more reliable and it has been checked already.
// Compare source & target rectangles (only cropping allowed, no scaling)
// Format should be video info(verified in checkinputtype), let's assert to be sure
ASSERT(mtIn->formattype == FORMAT_VideoInfo);
RECT rcImg;
BITMAPINFOHEADER *pBmiOut = HEADER(mtOut->pbFormat);
BITMAPINFOHEADER *pBmiIn = HEADER(mtIn->pbFormat);
SetRect(&rcImg, 0, 0, m_settings.frameWidth, m_settings.frameHeight);
RECT *prcSrc = &((VIDEOINFOHEADER*)(mtIn->pbFormat))->rcSource;
RECT *prcTarget = &((VIDEOINFOHEADER*)(mtOut->pbFormat))->rcTarget;
// Cropping should be allowed, not allowed at the moment
// Currently we allow no scaling or cropping
if (!IsRectEmpty(prcSrc) && !EqualRect(prcSrc, &rcImg))
{
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, no cropping allowed\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
if (!IsRectEmpty(prcTarget) && !EqualRect(prcTarget, &rcImg))
{
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, no scaling allowed\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
// Check video type, bitrate and frame rate settings but do *not* set them
CHantroEncoderWrapper::Settings checkSettings = m_settings;
checkSettings.videoType = bh.biCompression == MAKEFOURCC('M', 'P', '4', 'V') ||
bh.biCompression == MAKEFOURCC('m', 'p', '4', 'v') ?
CHantroEncoderWrapper::VIDEOTYPE_MPEG4 :
CHantroEncoderWrapper::VIDEOTYPE_H263;
if( vih->AvgTimePerFrame != 0 )
{
checkSettings.frameRate = (LONG)HTRENC_FRAMETIME2RATE(vih->AvgTimePerFrame);
}
if( vih->dwBitRate != 0 )
{
checkSettings.bitrate = vih->dwBitRate;
}
HRESULT hr = CHantroEncoderWrapper::ValidateSettings( &checkSettings );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, invalid video type, bit and/or frame rate\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
// Everything OK, let's accept this
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::CheckTransform Ok\n" );
return S_OK;
}
else
{
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, invalid format description\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
else
{
// If format is not specified, don't accept the type
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, no format description\n" );
return S_OK;
}
}
}
HTRENC_DEBUG( "CHtrEncFltr::CheckTransform FAILED, transform type mismatch\n" );
return VFW_E_TYPE_NOT_ACCEPTED;
}
HRESULT CHtrEncFltr::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* ppropInputRequest)
{
// Ask minimum size for output stream buffer from encoder wrapper, based
// on current encoding settings
LONG minOutputStreamSize;
HRESULT hr = CHantroEncoderWrapper::GetMinOutputStreamSize( &m_settings, &minOutputStreamSize );
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::DecideBufferSize: GetMinOutputStreamSize FAILED, wrong settings?\n" );
return E_FAIL;
}
ALLOCATOR_PROPERTIES pReq, pAct;
pReq.cbAlign = 1;
pReq.cbBuffer = minOutputStreamSize;
pReq.cBuffers = 1;
pReq.cbPrefix = 0;
// Setup allocator with buffer requirements
hr = pAlloc->SetProperties(&pReq, &pAct);
if( FAILED(hr) )
{
HTRENC_DEBUG( "CHtrEncFltr::DecideBufferSize: Allocator SetProperties FAILED!\n" );
return hr;
}
// Check properties actually set
if( pAct.cbBuffer < minOutputStreamSize )
{
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::DecideBufferSize WARNING: stream buffer size smaller than required (%d<%d)\n", pAct.cbBuffer, minOutputStreamSize );
// Not a critical error, encoder wrapper *may* be able to use smaller buffer
}
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::DecideBufferSize Ok\n" );
return S_OK;
}
HRESULT CHtrEncFltr::GetMediaType(int iPosition, CMediaType* pMediaType)
{
if( iPosition > 0 )
{
HTRENC_DEBUG_EXTRA( "CHtrEncFltr::GetMediaType: WARNING, received invalid iPosition\n" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -