DirectShow Transform Filter开发几个重要函数详解
1、CheckPointer(ppv,E_POINTER); 检查空指针异常
#define CheckPointer(p,ret) {if((p)==NULL) return (ret);}
#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L)
2、GetMediaType(int iPosition, CMediaType *pMediaType)两个参数,第一个参数iPosition代表什么含义呢?
在你的output pin上可以提供多种不同的media type。pin连接的时候,这些media type会被一种一种取出来进行试连接,直到找到一个双方pin都能接受的media type。
iPosition表示你支持的所有media type“数组”中的索引。
比如你的output pin支持3种media type,那么,GetMediaType可能会被如下调用。
GetMediaType(0, pmt);
// ...
GetMediaType(1, pmt);
// ...
GetMediaType(2, pmt);
// ...
GetMediaType(3, pmt);
// ...
GetMediaType(4, pmt);
// ...
在实现GetMediaType函数时,你应该检查iPosition的取值范围,如果超出取值范围,你应该返回一个错误值。上例中,iPosition必须为0-3之间;当iPosition为4时,你应该直接return E_FAIL。
3、 开发DirectShow transform filter中比较重要的5个函数:
五个重载的纯虚函数做详细介绍。 这才是最关键的地方。
HRESULT CheckInputType(const
CMediaType *mtIn);
HRESULT CheckTransform(const
CMediaType *mtIn, const CMediaType *mtOut);
HRESULT DecideBufferSize(IMemAllocator
*pAlloc, ALLOCATOR_PROPERTIES *pProp);
HRESULT GetMediaType(int
iPosition, CMediaType *pMediaType);
HRESULT Transform(IMediaSample
*pIn, IMediaSample *pOut);
这五个函数全部是都纯虚函数 ,是CTransformFilter为我们提供的接口,必须重载他们才能实例化。
初学者最大的困扰莫过于,是谁调用了这些函数。这些函数调用的时候实参是从哪来的。我一开始就被这些问题困扰。其实DX的帮助文档里就讲的很清楚了只是我一开始没认真看;
CheckInputType是由tranformfiltr的输入pin调用的用来检查本Filter的输入媒体是否合法;
CheckTransform是由tranformfiltr的输出pin调用的用来检查本filter的输出是否和合法;
GetMediaType是有由tranformfiltr的输出pin调用的用来获取该输出端口支持的媒体格式供下游filter的枚举
DecideBufferSize是由tranformfiltr的输出pin调用的来确定buffer的数量和大小
上游filter通过调用filter上输入pin上的IMemInputPin::Receive方法,将sample传递到filter,filter调用CTransformFilter::Transform方法来处理数据
整个过程就是
输入pin调用CheckInputType来筛选上游过来的媒体类型,如果可以接受 就有输出pin通GetMediaType来枚举输出媒体类型,进一步通过输出pin的CheckTransform来找到与输入媒体类型相融合的输出媒体类型并选中。在通过DecideBufferSize确定输出buffer的属性,所有的检查和筛选通过以后就可以连接了, 并通过tranform
将输入pin上的sample 传个输出pin输出媒体的类型是由GetMediaType来确定的, 只要媒体类型对应了就可以成功连接但是数据的传送还是要通过transform来实现。理论上对于没有压缩的视频, 一个sample就是一帧的数据,可以精确的量化处理。
要实现输出pin上媒体格式的转化 就必须在在GetMediaType函数中修改新的媒体格式,然后在checkTransform中确认 输出的媒体格式是不是期望的输出。例如 要将YUY2 16bit的媒体格式改为RGB8 8bit的媒体格式 就要做如下修改: