发信人: mem (Memory for ever), 信区: VideoCoding
标 题: 最近写DirectShow filter的一点经验
发信站: BBS 水木清华站 (Thu Dec 23 00:50:02 2004), 站内
最近需要做个DirectShow filter,使我们自己定义的一种视频格式的
文件能够在PC上播放,当然最好能够在Windows Media Player上播放。
以前一直做嵌入式,对DirectShow一点都不明白。所以第一步是进行
饿补。
第一步是补VC,以前学过VC,但是好几年不用了,有点生疏了。
但是功底还不错,在网上找了些例子练了几天,感觉找回感觉了。我
认为既然是用VC++编程,C++、OOP的概念一定要清晰,具备一定的源代码
阅读能力。毕竟DirectShow filter的代码看起来比一般的代码要略复杂
一点。如果你随便打开一个DirectX SDK的例子完全摸不着北的话,建议
先补补基础知识吧。磨刀不误砍柴工!
第二步补COM,DirectX是基于COM技术的,不说要精通COM技术,但是
基本的概念还是要具备的。网上有不少关于COM的文章,很多都比较浅显。
我没有太深入的去研究COM,自我感觉COM基本的思想掌握了就放下了。毕竟任务
比较紧,直接杀向最核心内容吧!
第三步补DirectX,最基本的工具这时候应该都具备了,比如MSDN、SourceInsight、
Visual assist X、DirectX SDK等等。说到DirectX SDK不得不说的是安装的时候
一定要选用DirectX SDK 9.0b,而不要用9.0c。9.0c里面没有DirectShow的例子,我
开始就是安装的9.0c,差点没ft死。然后就是收集各种资料,补相关知识。DirectX SDK的
帮助是最基本的,一定要花时间看,毕竟是最权威的。另外很重要的是要买本书看。
现在网络发达了,很多人都不看书直接到网上找资料了。但是我认为如果你对一个
领域很不熟悉的话,最好是先买本书。一般书上介绍的比较全面,对于入门是相当
好的,而且现在都有光盘,带例子。我看到版上不少人还没开始动手就开始问问题,
其实不如先买本书看看,不要开始就看英文书,中文书很多也不错的。毕竟我们可以
用两三天就一本中文书看个大概,看完了再去看英文书会更容易理解,尤其是对一些
专业词汇不熟悉的情况下。另外网上的一些经典文章也可以看看,全面了解一些。
然后可以开始看一些例子。其实不用费心去找,DirectX SDK自带的例子就已经很
丰富了。DirectShow分两个层次,一个是用DirectShow写应用程序,一个是写filter。
用DirectShow写应用程序比较简单。以播放一个视频文件来说,首先是初始化,得到
IGraphBuilder、IMediaControl、IMediaSeeking、IVideoWindow等一堆interface.
用IGraphBuilder的RenderFile告诉需要DirectShow播放的视频文件的文件名称,用
IVideoWindow设置好显示窗口的属性。然后就可以IMediaControl控制run()、pause()、
stop(),用IMediaSeeking来seek。整个播放过程就完成了!当然这是最基本的,如果
要更改filter,或者加入一些自己定义的filter,会稍微复杂一些。这个很有点像拚图,
把这个filter拿下来,换另一个filter上去。它们之间连接的好不好就要看连接的PIN了。
熟悉了之后,该写自己的filter了。还是先把一些概念吃透吧,然后还是先看DirectX
SDK的例子,其实里面各种filter的例子都有(开始有些我还没注意到)。但是有一个
至关重要,就是BaseClasses。几乎所有的filter的例子都是基于这个例子中的类的。
你要是把这个例子搞懂了,后面就很容易了。我因为比较着急,看了个大概,就寻了
个例子开始了。后面我就照葫芦画瓢,按照一个splitter filter来做我的filter了。
我这个splitter filter前级是个source filter,后级有两个PIN,一个接video的render
filter(我把解码部分直接做到splitter filter里去了,这样就不用写两个filter了,偷
懒了^_^ ),另一个接audio decoder,后面是audio output filter. 我的splitter filter
工作在pull模式,负责把数据从source filter读出来,解码,然后打上time stamp,包装
成一个一个packet送给后面的filter. 整个流程基本上是初始化,检测source filter送
过来的文件(流)的头,是否是自己识别的格式。初始化基本的参数,并且根据检测到的信息
动态建立output PIN. 如果有既有视频又音频流就需要建立两个PIN,否则只需建立一个PIN。
然后就进入上面的传递packet的循环了。不断的CheckRequest(),如果有的话就DeliverPacket().
整个过程就这么简单!
最后一个问题是如何让Filter Graph Manager把你的视频文件和一个source filter对应起来。
这个问题我前面问过。在DirectX SDK帮助里有,我直接贴在下面了。
To locate a source filter from a given file name, the Filter Graph Manager attempts to do the following, in order:
1. Match the protocol, if any.
2. Match the file extension.
3. Match patterns of bytes within the file, called check bytes.
直接在注册表中加入一项就可以完成上面的功能了,具体看SDK的文档吧,我就不费口舌了。不过我后来发现,即使在注册表中找不到任何信息的 话,Filter Graph Manager会企图匹配每一个在系统中注册的source filter。也就是说在splitter filter里 的匹配检查才是最重要。如果我不在splitter filter做任何匹配检查的话,这样任何不能被系统里注册的filter识别的文件都将通过这个 splitter filter来播放,然后就天下大乱了,:(
好了,希望这些能对大家有些帮助。
另外,在写这篇文章之前,我的filter已经完全搞定了,可以交差啦!
Lai
2004.23.晚