目标编写一个transform filter,功能是对图像进行翻转。
一、选择基类
从cbasefilter派生出三个用于编写transform filter的类,分别是:ctransformfilter 、ctransinplacefilter 和cvideotransformfilter ,三个基类的区别可以看msdn的说明,我们选择ctransformfilter类。
选择好基类,我们就创建一个空的dll工程,添加三个文件,分别是:flipfilter.h、flipfilter.cpp和flipfilter.def。
二、声明filter类
在flipfilter.h中添加下列代码声明
#include <streams.h>
extern "c" const guid clsid_flipfilter;
class cflipfilter : public ctransformfilter
{
private:
cflipfilter(tchar *tszname, lpunknown punk, hresult *phr);
public:
static cunknown * winapi createinstance(lpunknown punk, hresult *phr);
hresult checkinputtype(const cmediatype *mtin);
hresult getmediatype(int iposition, cmediatype *pmediatype);
hresult checktransform(const cmediatype *mtin, const cmediatype *mtout);
hresult decidebuffersize(imemallocator * pallocator, allocator_properties *pprop);
hresult transform(imediasample *pin, imediasample *pout);
};
三、媒体类型协商
这一步是filter的pin在连接的时候必须进行的步骤,主要重载三个函数:
1、hresult checkinputtype(const cmediatype *mtin);
hresult cflipfilter::checkinputtype(const cmediatype *mtin)
if (mtin->majortype != mediatype_video ||
mtin->subtype != mediasubtype_rgb24 ||
mtin->formattype != format_videoinfo )
{
return vfw_e_type_not_accepted;
}
videoinfo* pvi = (videoinfo*)mtin->format();
if (pvi->bmiheader.bibitcount != 24)
return s_ok;
}
ctransformfilter使用ctransforminputpin类作为输入pin,ctransforminputpin::checkmediatype(const cmediatype* pmt)中调用m_ptransformfilter->checkinputtype(pmt);因此我们可以简单的认为checkinputtype就是输入pin的checkmediatype。这样设计的是为了不需要重新定义输入pin类,只需要定义filter类,简化编写transform filter的步骤,另外的几个接口也是这样的一个设计原理。
2、hresult getmediatype(int iposition, cmediatype *pmediatype);
hresult cflipfilter::getmediatype(int iposition, cmediatype *pmediatype)
if (m_pinput->isconnected() == false) {
return e_unexpected;
if (iposition < 0) {
return e_invalidarg;
if (iposition > 0) {
return vfw_s_no_more_items;
checkpointer(pmediatype,e_pointer);
*pmediatype = m_pinput->currentmediatype();
return noerror;
同样的,这个函数也是为输入pin所写。
3、hresult checktransform(const cmediatype *mtin, const cmediatype *mtout);
hresult cflipfilter::checktransform(const cmediatype *mtin, const cmediatype *mtout)
if (*mtin == *mtout)
return noerror;
return e_fail;
这个函数是输出pin调用。ctransformoutputpin::checkmediatype(const cmediatype* pmtout)中调用m_ptransformfilter->checktransform。
四、协商分配器的属性,决定数据的属性
hresult cflipfilter::decidebuffersize(imemallocator * pallocator, allocator_properties *pprop)
checkpointer(pallocator,e_pointer);
checkpointer(pprop,e_pointer);
hresult hr = noerror;
pprop->cbuffers = 1;
pprop->cbbuffer = m_pinput->currentmediatype().getsamplesize();
assert(pprop->cbbuffer);
allocator_properties actual;
hr = pallocator->setproperties(pprop,&actual);
if (failed(hr)) {
return hr;
assert( actual.cbuffers == 1 );
if (pprop->cbuffers > actual.cbuffers ||
pprop->cbbuffer > actual.cbbuffer) {
return e_fail;
这个函数由ctransformoutputpin::decidebuffersize调用。
五、实现数据转换
hresult cflipfilter::transform(imediasample *pin, imediasample *pout)
checkpointer(pin,e_pointer);
checkpointer(pout,e_pointer);
byte *psourcebuffer, *pdestbuffer;
long lsourcesize = pin->getactualdatalength();
pin->getpointer(&psourcebuffer);
pout->getpointer(&pdestbuffer);
//翻转图像
cmediatype pmediatype1 = m_pinput->currentmediatype();
videoinfoheader* pvi = (videoinfoheader*)pmediatype1.pbformat;
int nwidth = widthbytes(pvi->bmiheader.biwidth * pvi->bmiheader.bibitcount);
for (int i = 0; i < pvi->bmiheader.biheight; i ++)
copymemory((pvoid) (pdestbuffer + nwidth * i),
(pvoid) (psourcebuffer + nwidth * (pvi->bmiheader.biheight - i - 1)),
nwidth);
}
reference_time timestart, timeend;
if(noerror == pin->gettime(&timestart, &timeend))
pout->settime(&timestart, &timeend);
longlong mediastart, mediaend;
if(pin->getmediatime(&mediastart,&mediaend) == noerror)
pout->setmediatime(&mediastart,&mediaend);
hresult hr = pin->issyncpoint();
if(hr == s_ok)
pout->setsyncpoint(true);
else if(hr == s_false)
pout->setsyncpoint(false);
else
hr = pin->ispreroll();
pout->setpreroll(true);
pout->setpreroll(false);
{
hr = pin->isdiscontinuity();
pout->setdiscontinuity(true);
pout->setdiscontinuity(false);
long ldatalength = pin->getactualdatalength();
pout->setactualdatalength(ldatalength);
六、添加com信息,使dll成为filter
1、创建filter实例,这是标准格式
cunknown* cflipfilter::createinstance(lpunknown punk, hresult *phr)
assert(phr);
cflipfilter *pnewobject = new cflipfilter(name("flipfilter"), punk, phr);
if (pnewobject == null) {
if (phr)
*phr = e_outofmemory;
return pnewobject;
2、声明工厂类模版
const amoviesetup_mediatype sudinputpintypes =
&mediatype_video,
&mediasubtype_null
const amoviesetup_mediatype sudoutputpintypes =
&mediatype_video,
const amoviesetup_pin sudppins[] =
{ l"input",
false,
&clsid_null,
null,
1,
&sudinputpintypes
},
{ l"output",
false,
true,
false,
&clsid_null,
null,
1,
&sudoutputpintypes
const amoviesetup_filter sudflipfilter =
&clsid_flipfilter,
l"flipfilter",
merit_do_not_use,
2,
sudppins
cfactorytemplate g_templates[] = {
{ l"flipfilter"
, &clsid_flipfilter
, cflipfilter::createinstance
, null
, &sudflipfilter }
int g_ctemplates = sizeof(g_templates) / sizeof(g_templates[0]);
regfilter2 rf2filterreg = {
merit_do_not_use,
2,
sudppins
3、注册和注销filter,dll的全局入口
bool apientry dllmain(handle hmodule,
dword dwreason,
lpvoid lpreserved)
return dllentrypoint((hinstance)(hmodule), dwreason, lpreserved);
stdapi dllregisterserver()
return amoviedllregisterserver2( true );
}
stdapi dllunregisterserver()
return amoviedllregisterserver2( false );
filter编写完成。