DirectShow研究总结
关菊要求的视频播放功能,终于在花费了N天研究、查阅无数MSDN资料、翻阅各种例子之后愣是搞出来了。再次感谢保济丸的大力支持和帮助。
视频播放功能会集成在f2d 0.3中,现在离发布0.3版还早,先发个帖子以示后人。
1、为了将DirectShow和f2d的流系统结合起来费了一番功夫,最后只要抄袭下WindowsSDK中的memfile实现,覆写CAsyncStream和CAsyncReader两个类即可。实现这个SourceFilter(源过滤器)时需要向下游递交媒体类型,一般而言只要让主类型为Stream,次类型为NULL即可。然后IGraphBuilder会自行去挂接整个图。但是对于AVI格式需要特殊处理。根据MSDN上面说的,AVI分割过滤器只识别次类型为Avi的Stream,所以要手动解析下文件,看看是不是AVI,如果是,则设置子类型为AVI。之后,在初始化完IGraphBuilder后将我们自己的SourceFilter挂接到其中,再调用Render对其Pin进行渲染。整个渲染图将由IGraphBuilder自行创建。
2、引擎最终的目的要求能将视频渲染到纹理。查阅MSDN发现一篇《Direct3D环境中的DirectShow电影》(http://msdn.microsoft.com/zh-cn/library/ms867211.aspx),文章推荐使用VMR9渲染器来完成这一过程。但实际操作过程中发现,一旦使用VMR9渲染器则要开启D3D的多线程模式,其次,当设备丢失的时候,VMR9没有一个接口可以释放掉内部的D3D对象,这使得无法重置D3D(IDirect3DDevice9::Reset要求释放所有D3DPOOL_DEFAULT资源)。查阅SDK的方法是直接释放了整个D3D设备重新创建一个新的D3D设备,显然不符合引擎的构架。为此重新编写了一个VideoRenderer(感谢WINAPI提供的一份参考源码)。
3、VideoRenderer需要实现接收YUY2格式的视频原数据。我拿到的样例中只实现了RGB24,这使得很多解码器无法和我的渲染器挂钩。最后找到一份代码成功转换YUY2到RGB数据。测试中发现仅YUY2一种格式基本可以支持N多个解码器。换言之没必要实现接收RGB格式,仅一种格式足矣。
4、使用GraphEdit可以远程获取程序的过滤器图,通常认为不支持WinVista或更高,实际百度发现只要注册WindowsSDK下某个DLL即可使用该调试功能。
5、实际测试发现微软自带的Microsoft DTV-DVD Video Decoder解码时无法使用put_Rate来设置播放速率,一旦设置会导致渲染器无数据。同时发现该解码器无法工作在VS挂接状态下(无论DEBUG还是RELEASE)。当在VS调试时解码器会输出乱码,原因不明。
6、IGraphBuilder自带的IBasicVideo和IVideoFrameStep接口要求Renderer必须有所实现,由于没有找到如何实现这两个接口,这部分研究空白。
7、由于D3D多线程时因未知原因导致死锁在了nVidia驱动程序中,最终导致驱动程序崩溃,最后实现时切换回了单线程模式,即需要时从渲染器拷贝视频数据到纹理。由于拷贝耗时,在一定程度上损失了FPS。