第一步写了个自己的Filter,但只是一个空架子,接下来就要动真格的了~~
首先实现上一步的两个接口
HRESULT CheckInputType(const CMediaType* mtIn);
HRESULT Transform(IMediaSample *pSample);
其中
HRESULT CheckInputType(const CMediaType* mtIn);
不需要处理,直接用CFilterTitleOverlay的CheckInputType
重点就是
HRESULT Transform(IMediaSample *pSample);
查看CFilterTitleOverlay会发现它的简易工作流程是
接收一帧数据,在这帧数据上,根据设置在对应位置添加字幕,输出到outpin
随着视频播放,字幕的位置不停变化,从而实现滚动字幕的功能
它其实是改变了sample的数据,而不是真正意义上的在Overlay显示滚动字幕
而这正是为什么在CheckInputType中一定要求输入类型为RGB格式的原因了。
根据这个工作原理,要在视频上显示半透明滚动字幕,第一步应该先显示半透明的背景,我选择的是黑色的背景。
通过pSample->GetPointer可以获得sample的视频数据的内存指针,使用这个指针,手动进行alpha就可以达到目的了,
但是存在一个问题:输入视频的类型各不相同,
根据之前 CheckInputType接口的定义,它可以是RGB32/24/555/565,显然输入格式不同,alpha的算法肯定也有所区别,
那么,CFilterTitleOverlay是如何解决这个问题的呢?
查看CFilterTitleOverlay的源代码,发现它有很多Pixel的类,其中CBasePixel为基类,CPixelRGB24等作为子类处理具体的像素。
那么它是怎么实现的根据不同输入调用不同的类呢?
在COverlayController类中有这个一个接口
SideEffectColorSpaceChanged()
它的功能是根据输入color space的不同,初始化不同的子类,赋给CBasePixel这个基类指针,并设置每隔像素占用的字节数。
这样就可以实现用统一的接口处理不同color space的数据。
那么是在哪里调用SideEffectColorSpaceChanged的呢,一路向上,发现最终是由SetInputVideoInfoToController()调用的,而
SetInputVideoInfoToController()在两个地方被调用,分别是
HRESULT CFilterTitleOverlay::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin)
和
void CFilterTitleOverlay::SideEffectOverlayTypeChanged(void)
其中
void CFilterTitleOverlay::SideEffectOverlayTypeChanged(void)是由接口
put_TitleOverlayType()调用,也就是说外部手动修改输入类型,暂时先不管
查找CompleteConnect,发现这个接口调用的时机是在CheckInputType之后
这样,根据不同输入类型调用不同类处理的原理就理清了。
理清了这个问题,就知道要如何实现alpha了
在CBasePixel类中添加实现alpha的函数
void ConverByAlpha(unsigned char* inPixel , unsigned int color)
然后在各个子类中实现这个接口
在Transform接口中,遍历需要alpha的像素,并调用ConverByAlpha,这样,就实现了半透明背景的功能了~~