directshow 学习要点

本文详细介绍了DirectShowFilter开发中的关键技术点,包括Pin连接过程、数据传输模式(推模式和拉模式)、内存分配器的协商及流媒体的定位。通过深入分析基类源代码,帮助开发者更好地理解和应用DirectShow。
摘要由CSDN通过智能技术生成
学习DirectShow Filter的开发,不外乎以下几种方法:看帮助文档、看示例代码和看SDK基类源代码。看帮助文档,应着重于总体概念上的理解;看示例代码应与基类源代码的
研究同步进行,因为自己写Filter,关键的第一步是选择一个合适的Filter基类和Pin的基类。对于Filter的把握,一般认为要掌握以下三方面的内容:Filter之间Pin的连接、
Filter之间的数据传输以及流媒体的随机访问(或者说流的定位)。下面就开始分别进行阐述。
  所谓的Filter Pin之间的连接,实际上是Pin之间Media Type(媒体类型)的一个协商过程。连接总是从输出Pin指向输入Pin的。要想深入了解具体的连接过程,就必须认真研读
SDK的基类源代码(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/amfilter.cpp,类CBasePin的Connect方法)。连接的大致过程为,枚举欲连接的输入Pin上所有的媒
体类型,逐一用这些媒体类型与输出Pin进行连接,如果输出Pin也接受这种媒体类型,则Pin之间的连接宣告成功;如果所有输入Pin上枚举的媒体类型输出Pin都不支持,则枚举输
出Pin上的所有媒体类型,并逐一用这些媒体类型与输入Pin进行连接。如果输入Pin接受其中的一种媒体类型,则Pin之间的连接到此也宣告成功;如果输出Pin上的所有媒体类型,
输入Pin都不支持,则这两个Pin之间的连接过程宣告失败。
  有一点需要注意的是,上述的输入Pin与输出Pin一般不属于同一个Filter,典型的是上一级Filter(也叫Upstream Filter)的输出Pin连向下一级Filter(也叫Downstream
Filter)的输入Pin。
  当Filter的Pin之间连接完成,也就是说,连接双方通过协商取得了一种大家都支持的媒体类型之后,即开始为数据传输做准备。这些准备工作中,最重要的是Pin上的内存分配
器的协商,一般也是由输出Pin发起。在DirectShow Filter之间,数据是通过一个一个数据包传送的,这个数据包叫做Sample。Sample本身是一个COM对象,拥有一段内存用以装载
数据,Sample就由内存分配器(Allocator)来统一管理。已成功连接的一对输出、输入Pin使用同一个内存分配器,所以数据从输出Pin传送到输入Pin上是无需内存拷贝的。而典
型的数据拷贝,一般发生在Filter内部,从Filter的输入Pin上读取数据后,进行一定意图的处理,然后在Filter的输出Pin上填充数据,然后继续往下传输。下面,我们就具体阐
述一下Filter之间的数据传送。
  首先,大家要区分一下Filter的两种主要的数据传输模式:推模式(Push Model)和拉模式(Pull Model)。
  所谓推模式,即源Filter(Source Filter)自己能够产生数据,并且一般在它的输出Pin上有独立的子线程负责将数据发送出去,常见的情况如代表WDM模型的采集卡的Live
Source Filter;而所谓拉模式,即源Filter不具有把自己的数据送出去的能力,这种情况下,一般源Filter后紧跟着接一个Parser Filter或Splitter Filter,这种Filter一般在
输入Pin上有个独立的子线程,负责不断地从源Filter索取数据,然后经过处理后将数据传送下去,常见的情况如文件源。推模式下,源Filter是主动的;拉模式下,源Filter是被
动的。而事实上,如果将上图拉模式中的源Filter和Splitter Filter看成另一个虚拟的源Filter,则后面的Filter之间的数据传输也与推模式完全相同。
  那么,数据到底是怎么通过连接着的Pin传输的呢?首先来看推模式。在源Filter后面的Filter输入Pin上,一定实现了一个IMemInputPin接口,数据正是通过上一级Filter调用
这个接口的Receive方法进行传输的。值得注意的是(上面已经提到过),数据从输出Pin通过Receive方法调用传输到输入Pin上,并没有进行内存拷贝,它只是一个相当于数据到
达的“通知”。再看一下拉模式。拉模式下的源Filter的输出Pin上,一定实现了一个IAsyncReader接口;其后面的Splitter Filter,就是通过调用这个接口的Request方法或者
SyncRead方法来获得数据。Splitter Filter然后像推模式一样,调用下一级Filter输入Pin上的IMemInputPin接口Receive方法实现数据的往下传送。深入了解这部分内容,请认真
研读SDK的基类源代码(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/source.cpp和pullpin.cpp)。 
  下面,我们来讲一下流的定位(Media Seeking)。在GraphEdit中,当我们成功构建了一个Filter Graph之后,我们就可以播放它。在播放中,我们可以看到进度条也在相应地
前进。当然,我们也可以通过拖动进度条,实现随机访问。要做到这一点,在应用程序级别应该可以知道Filter Graph总共要播放多长时间,当前播放到什么位置等等。那么,在
Filter级别,这一点是怎么实现的呢?
  我们知道,若干个Filter通过Pin的相互连接组成了Filter Graph。而这个Filter Graph是由另一个COM对象Filter Graph Manager来管理的。通过Filter Graph Manager,我们
就可以得到一个IMediaSeeking的接口来实现对流媒体的定位。在Filter级别,我们可以看到,Filter Graph Manager首先从最后一个Filter(Renderer Filter)开始,询问上一
级Filter的输出Pin是否支持IMediaSeeking接口。如果支持,则返回这个接口;如果不支持,则继续往上一级Filter询问,直到源Filter。一般在源Filter的输出Pin上实现
IMediaSeeking接口,它告诉调用者总共有多长时间的媒体内容,当前播放位置等信息。(如果是文件源,一般在Parser Filter或Splitter Filter实现这个接口。)对于Filter开
发者来说,如果我们写的是源Filter,我们就要在Filter的输出Pin上实现IMediaSeeking这个接口;如果写的是中间的传输Filter,只需要在输出Pin上将用户的获得接口请求往上
传递给上一级Filter的输出Pin;如果写的是Renderer Filter,需要在Filter上将用户的获得接口请求往上传递给上一级Filter的输出Pin。进一步的了解,请认真研读SDK的基类
源代码(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/transfrm.cpp的 类方法CTransformOutputPin::NonDelegatingQueryInterface实现和ctlutil.cpp中类
CPosPassThru的实现)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值