视频特效滤镜 via DirectShow Filter
视频特效定义
视频特效(Video effects 或 Visual effects)是对每帧图像进行各种数字化处理达到的效果。如对画面的尺寸、位置、亮度及色度等参数进行处理,就可获得缩放、旋转、黑白、油画等各种效果。
常见的特效技术有:缩放、旋转、裁剪、叠加、老电影、黑白、淡入淡出、水印、去噪、慢动作、2D 转 3D 等等。
DirectShow Filter
DShow 中插件是以 Filter 的形式创建的,需要继承自下面两个接口之一:
- CTransformFilter:拷贝原始 sample 的 buffer 再修改,一般输入输出格式不一样
- CTransInPlaceFilter:直接修改原始 sample 的 buffer,输入输出格式一样。该接口其实继承自上面的接口。
下面我们以比较通用的 Transform Filter 说明,相对简单的 In Place Filter 请参考我的另一篇文章:音频特效插件 via DirectShow。
代码包含在 Windows SDK 7.x 的 samples\multimedia\directshow\filters\ 目录下。
CEZrgb24 Filter
下面的视频插件实现了颜色滤镜,如 R/G/B 单通道、模糊、灰度等:
class CEZrgb24 : public CTransformFilter,
public IIPEffect,
public ISpecifyPropertyPages,
public CPersistStream
{
DECLARE_IUNKNOWN;
static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
// Overrriden from CTransformFilter base class
HRESULT CheckInputType(const CMediaType *mtIn);
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);
// These implement the custom IIPEffect interface
STDMETHODIMP get_IPEffect(int *IPEffect, REFTIME *StartTime, REFTIME *Length);
STDMETHODIMP put_IPEffect(int IPEffect, REFTIME StartTime, REFTIME Length);
// ISpecifyPropertyPages interface
STDMETHODIMP GetPages(CAUUID *pPages);
// CPersistStream override
STDMETHODIMP GetClassID(CLSID *pClsid);
// CPersistStream stuff
HRESULT ScribbleToStream(IStream *pStream);
HRESULT ReadFromStream(IStream *pStream);
};
CTransformFilter::CheckInputType 函数
本 filter 要求输入类型为 RGB24。
HRESULT CEZrgb24::CheckInputType(const CMediaType *mtIn)
{
CheckPointer(mtIn, E_POINTER);
if (*mtIn->FormatType() != FORMAT_VideoInfo)
return E_INVALIDARG;
if (CanPerformEZrgb24(mtIn))
return NOERROR;
return E_FAIL;
}
BOOL CEZrgb24::CanPerformEZrgb24(const CMediaType *pMediaType) const
{
CheckPointer(pMediaType, FALSE);
if (IsEqualGUID(*pMediaType->Type(), MEDIATYPE_Video)) {