assert(mt.formattype == format_videoinfo);
bitmapinfoheader *pbmi = header(mt.pbformat);
pprop->cbbuffer = dibsize(*pbmi) * 2;
if (pprop->cbalign == 0)
{
pprop->cbalign = 1;
}
if (pprop->cbuffers == 0)
{
pprop->cbuffers = 1;
}
// release the format block.
freemediatype(mt);
// set allocator properties.
allocator_properties actual;
hr = palloc->setproperties(pprop, &actual);
if (failed(hr))
{
return hr;
}
// even when it succeeds, check the actual result.
if (pprop->cbbuffer > actual.cbbuffer)
{
return e_fail;
}
return s_ok;
}
即使setproperties函数成功,你也要检查结果,以确保满足你的需要
缺省的情况下,所有的filter都采用cmemallocator类类分配内存,这个类从客户进程的虚拟地址中分配内存,如果你的filter需要其它的内存,比如,directdraw表面,你可以派生一个通用的allocator,你可以从cbaseallocator类派生一个新的类,根据不同的pin使用你的派生的新的allocator类,你需要继承不同的函数,
input pin: cbaseinputpin::getallocator and cbaseinputpin::notifyallocator.
output pin: cbaseoutputpin::decideallocator.
如果其它的filter拒绝使用你的custom allocator,你的filter和其它filter连接的时候就会失败,
第五步 传递媒体数据
上游filter通过调用filter上输入pin上的imeminputpin::receive方法,将sample传递到filter,filter调用ctransformfilter::transform方法来处理数据,注意,这个方法也是一个纯虚的函数,你要是想用,你必须提供函数实现。
ctransformfilter::transform有两个指针,一个指向输入sample,一直只想输出smaple,再调用这个方法之前,要将sample从输入sample拷贝到输出sample。
如果transform返回s_ok,filter就将sample传递到下游的filter。下面的代码演示了rle encoder如何实现这个函数的,你可以参考一下,当然你的函数和这个是不一样的。要注意
hresult crlefilter::transform(imediasample *psource, imediasample *pdest)
{
// get pointers to the underlying buffers.
byte *pbufferin, *pbufferout;
hr = psource->getpointer(&pbufferin);
if (failed(hr))
{
return hr;
}
hr = pdest->getpointer(&pbufferout);
if (failed(hr))
{
return hr;
}
// process the data.
dword cbdest = encodeframe(pbufferin, pbufferout);
kassert((long)cbdest <= pdest->getsize());
pdest->setactualdatalength(cbdest);
pdest->setsyncpoint(true);
return s_ok;
}
需要注意的几个问题
1 时间戳,ctransformfilter在调用transform方法之前就给输出sample打上了时间戳,它仅仅是从输入的stample上讲时间戳拷贝过来,不做任何的改动,如果你的filter需要改动时间戳,你可以调用输出sample上的imediasample::settime方法
2 数据格式的改变
上游的filter可以 动态的改变数据的格式,在改动数据的格式之前,它要调用你的输入pin上的ipin::queryaccept方法,在filter上,这个方法的调用会引起checkinputtype,和checktransform的方法的调用。下游的filter也可以改变数据格式,机理和这个一样。
在你的filter中,需要做两件事情
1 )要确保queryaccept返回正确
2 )如果你的filter不接受数据格式的改变,那么就在你的filter的transform方法中调用imediasample::getmediatype.方法,如果这个方法返回s_ok,那么你的filter就要适用数据的改变。
3线程,
在ctransformfilter中,filter在receive方法同步的发送输出sample。filter没有创建任何的线程来处理数据。
第六步支持com特性
最后一步是支持com属性
添加com支持的步骤和前面一样,并且在前面也讲述的很清楚了,下面列出必须的几个要素
1 引用计数reference counting,接口查询queryinterface
很简单,从基类派生即可
cmyfilter : public cbasefilter, public imycustominterface
{
public:
declare_iunknown
stdmethodimp nondelegatingqueryinterface(refiid iid, void **ppv);
};
stdmethodimp cmyfilter::nondelegatingqueryinterface(refiid iid, void **ppv)
{
if (riid == iid_imycustominterface) {
return getinterface(static_cast<imycustominterface*>(this), ppv);
}
return cbasefilter::nondelegatingqueryinterface(riid,ppv);
}
2对象的创建object creation
cunknown * winapi crlefilter::createinstance(lpunknown punk, hresult *phr)
{
crlefilter *pfilter = new crlefilter();
if (pfilter== null)
{
*phr = e_outofmemory;
}
return pfilter;
}
模板数组
static wchar g_wszname[] = l"my rle encoder";
cfactorytemplate g_templates[] =
{
{
g_wszname,
&clsid_rlefilter,
crlefilter::createinstance,
null,
null
}
};
int g_ctemplates = sizeof(g_templates) / sizeof(g_templates[0]);
3组件的注册
// declare media type information.
fourccmap fccmap = fcc('mrle');
regpintypes sudinputtypes = { &mediatype_video, &guid_null };
regpintypes sudoutputtypes = { &mediatype_video, (guid*)&fccmap };
// declare pin information.
regfilterpins sudpinreg[] = {
// input pin.
{ 0, false, // rendered?
false, // output?
false, // zero?
false, // many?
0, 0,
1, &sudinputtypes // media types.
},
// output pin.
{ 0, false, // rendered?
true, // output?
false, // zero?
false, // many?
0, 0,
1, &sudoutputtypes // media types.
}
};
// declare filter information.
regfilter2 rf2filterreg = {
1, // version number.
merit_do_not_use, // merit.
2, // number of pins.
sudpinreg // pointer to pin information.
};