3.3. 构建Filter Graph
3.3.1. 用于构建Graph的组件
DirectShow提供了一系列用于构建filter graph的组件,包括:
*Filter Graph Manager。 这个对象用于控制filter graph,支持IGraphBuilder、IMediaControl和IMediaEventEx等许多接口。所有的directshow应用程序 都需要在某些地方用到这个对象,虽然在有些情况下,是其它的对象为应用程序创建了filter graph manager。
*Capture Graph Builder。这个对象为构建filter graph提供附加的方法。它最初是为构建提供视频采集的graph而设计的(这正是它的名字由来),但是对于构建许多另外类型的filter graph也是很有用的。它支持ICaptureGraphBuilder2接口。
*Filter Mapper和System Device Enumerator。这些对象用于查找在系统中注册的或代表硬件驱动的filter。
*DVD Graph Builder。这个对象构建用以回放和导航DVD的filter graph。它支持IDvdGraphBuilder接口。基于脚本的应用程序能够使用MSWebDVD ActiveX控件来控制DVD回放。
*Video Control。WinXP提供这个ActiveX控件,用于操纵directshow中的数据和模拟电视。
智能连接(Intelligent Connect)
智能连接这个术语覆盖了一系列Filter Graph Manager用于构建所有或部份filter graph的算法。任何时候,当Filter Graph Manager需要添加filter来完成graph时,它大致做以下几件事情:
1.如果有一个filter存在于graph中,而且这个filter有至少一个没有连接的input pin,Filter Graph Manager试着去试用这个filter。
2.否则,Filter Graph Manager在已注册的filter中寻找连接时可以接受合适的媒体类型的filter。每一个filter都注册有一个Merit值,这个值用以标记 哪个filter最容易被Filter Graph Manager选中来完成graph。Filter Graph Manager按Merit值的顺序来选择filter,Merit值越大,被选中的机会越大。对于每种流类型(如音频、视频、MIDI),默认的 renderer具有一个很高的Merit值,解码器同样是,专用filter具有低Merit值。
如果Filter Graph Manager因选择的filter不合适而被困,它会返回来尝试另外的filter组合。
3.3.2 Grap构建概述
创建一个filter graph,从创建一个Filter Graph Manager实例开始:
IGraphBuilder* pIGB; HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder,(void **)&pIGB); |
3.3.3. 智能连接
智能连接是filter graph manager用以构建filter graph的机制。它包含了一系列相关的用以选择filter和将它们添加到graph中去的算法。作为应用程序开发者,你并不需要很具体地了解智能连接 的细节。如果你在构建某个filter graph时遇到问题并希望能解决它,或者你正在编写你自己的filter并希望它能自动地被graph构建,请阅读这一节。
智能连接涉及以下IGraphBuilder方法:
*IGraphBuilder::Render
*IGraphBuilder::AddSourceFilter
*IGraphBuilder::RenderFile
*IGraphBuilder::Connect
Render方法构建一部分graph,它从一个尚未连接的输出pin开始顺着数据流的方向往下,添加必要的filter,起始的那个filter必须已 被添加到了graph中。Render方法每一步都搜索一个能够连接到前一个filter的filter,如果新连接上的filter有多个输出pin, 数据流能自动分流,搜索直到每个流都被renderer为止。如果Render方法搜索到的filter无法使用,它会返回去尝试另一个filter。
要连接每一个输出pin,Render方法做以下工作:
1.如果pin支持IStreamBuilder接口,Filter Graph Manager让pin的IStreamBuilder::Render方法来完成整过程。通过暴露这个接口,pin承担了构建graph剩余部分的全部 工作。但是,只有很少数的filter支持此接口。
2.Filter Graph Manager尝试使用任何在缓存中的filter。在智能连接的整个过程中,filter graph manager可以在早期将filter缓存起来。
3.如果filter graph包含了任何有未连接的输入pin的filter,filter graph manager会将其当作下一个filter来尝试连接。你可以通过在调用Render之前添加特定的filter来强制让Render方法来尝试这个 filter。
4.最后,filter graph manager使用IFilterMapper2::EnumMatchingFilters方法在所有注册的filter中寻找,依据已注册的媒体类型列表来逐个试着匹配输出pin的各个媒体类型(按优先级高低排列)。
每个已注册的filter都有一个merit值,这是一个用来表示filter优先级的数字,最大优先级越高,EnumMatchingFilters方 法返回的filter集依据merit值来排列,直至最小的merit值MERIT_DO_NOT_USE+1,它忽略merit为 MERIT_DO_NOT_USR或更小的filter。filter也通过GUID来归类,类别本身也有merit值, EnumMatchingFilters方法忽略任何merit值为MERIT_DO_NOT_USE或更小的类别,即使在那个类别中的filter有较 高的merit值。
总结一下,Render方法以下列步骤尝试filter
1.使用IStreamBuilder
2.尝试被缓存的filter
3.尝试已添加在graph中的filter
4.在已注册的filter中寻找
AddSourceFilter方法添加一个能render特定文件的source filter。首先,它依据协议名(如Http://)、文件扩展名、或文件头在已注册的filter中寻找匹配的那个。如果此方法定位到了一个合适的 source filter,它便立刻创建一个这个filter的实例,并将其添加到graph中,然后调用filter的IFileSourceFilter:: Load方法。
RenderFile方法依据一个文件名来构建一个默认的回放graph,在其内部,RenderFile方法调用AddSourceFilter来定位source filter,并且用Render来构建Graph的余下部分。
Connect方法将输出pin连接到输入pin上去,这个方法自动添加必要的中间filter到graph中去,使用在Render方法中描述的那一系列算法:
1.使用IStreamBuilder
2.尝试被缓存的filter
3.尝试已添加在graph中的filter
4.在已注册的filter中寻找