DirectShow的基本单元:Filter

来源:互联网 发布:怎么注册淘宝客 编辑:程序博客网 时间:2024/06/06 20:05

概念

DirectShow所采用的是一种模块化的结构,其基本单元是一类成为filter的COM对象。DirectShow提供了多种预定义的标准filter组件,同时开发者也可以根据需要开发自己的个性化filter。常用的filter一般可分为以下不同类别:

(1)Source Filter——为整个Filter Graph提供数据来源,这些数据可能来自硬盘文件、网络流媒体或者音视频采集设备等。不同的数据来源由不同的Source Filter负责处理。

(2)Transform Filter——负责数据的变换处理,获取输入数据并对其进行相应处理后,生成输出数据并传递到下一个filter。典型的如编码、解码Filter等。

(3)Render-er Filter——位于Filter Graph的末尾,用于处理数据的渲染等操作。如视频渲染器、音频渲染器和写入文件filter等。

(4)Splitter Filter——用于分离数据流。如AVI视频流复用了音频和视频信号,AVI Splitter filter的作用就是将一路AVI数据流分离成视频流和音频流。

(5)Mux Filter——用于复用数据流,作用与Splitter Filter相反。

每一个Filter都至少实现了IBaseFilter接口用于实现Filter Graph中的统一操作。每一个实现Filter的文件都是动态链接库,可能是dll但更多的是ax文件。在代码中,一个Filter也与其他COM对象一样,通过API: CoCreateInstance()创建。


Filter的注册和注销:

作为一个COM组件,注册和卸载均通过regsvr32.exe程序实现。一般的filter工程会定义一下四个导出函数:DllGetClassObject,用于创建对象时调用,根据CLSID返回对应的类厂对象;DllCanUnloadNow,用于判断是否可以从内存中卸载;DllRegisterServer和DllUnRegisterServer用于组件的自注册,可以在程序中通过LoadLibrary加载DLL库后导出执行之实现自注册。所谓“注册”,就是将Filter的基本COM信息写入注册表的操作。


Filter的媒体类型Media Type:

媒体类型用于规定Filter所处理的数据的格式。其定义实际上是一个AM_MEDIA_TYPE结构体:

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. typedef struct _MediaType  
  2. {  
  3.         GUID majortype;  
  4.         GUID subtype;  
  5.         BOOL bFixSizeSamples;  
  6.         BOOL bTemporalCompression;  
  7.         ULONG lSampleSize;  
  8.         GUID formattype;  
  9.         IUknown *pUnk;  
  10.         ULONG cbFormat;  
  11.         BYTE *pbFormat;  
  12. }AM_MEDIA_TYPE;  

该结构体中描述媒体类型的成员主要有majortype, subtype和formattype三部分,分别用于描述媒体类型、具体格式和格式的细节等。


Filter的连接:

任何两个filter之间的相互联系通过一个COM对象Pin实现,Pin的连接实际上是输出Pin和输入Pin之间关于媒体类型的“协商”过程。每一个Pin都实现了IPin接口,Pin对象也是通过这个接口实现连接的。连接过程大致为:

Step 1:Filter Graph Manager在输出Pin(上级Pin)上调用IPin::Connect()方法,用输入Pin指针和指定的连接用的媒体类型作为参数;

Step 2:若输出Pin接受连接,则调用输入Pin的IPin::ReceiveConnection()方法;如果输入Pin接受连接,则本次连接成功;

在IPin::Connect()的实现函数CBasePin::Connect中,首先检查参数和状态(如Pin是否已经被链接、Filter是否是停止状态),随后检查媒体类型,找到双方都支持的媒体类型。检查媒体类型调用了AgreeMediaType()函数,如果该函数指定的媒体类型非空,则针对该类型做一次尝试,如果成功则调用AttemptConnection尝试连接;如果媒体类型指针为空或对象不完整,则调用TryMedaiTypes()遍历输入和输出Pin上支持的媒体类型,对每一中支持的类型调用AttemptConnection()尝试连接。

在AttemptConnection()中,首先会调用输出Pin(上级Pin)的CheckConnect进行连接检查(如输入Pin是否支持特殊接口等),若失败则BreakConnect()。成功后调用CheckMediaType()。若check成功,则讲输入Pin和媒体类型信息保存在输出Pin中,随后调用ReceiveConnection()和CompleteConnection()完成连接。


Filter的数据传递

在DirectShow中定义了Sample类,是一个封装了一定大小数据内存的COM组件。相互链接的filter之间通过sample进行数据传输。

在传输过程中,两个链接的Pin拥有同一个sample分配器allocator,用于创建和管理sample。传输时上级filter通过输出pin的allocator得到空闲的sample及其内存地址,并将数据存放其中,随后将这个sample传递给下级filter的输入pin。

数据传输的两种主要方式:推模式和拉模式。

①推模式:常用于实时源,自身可以产生数据并通过专用数据线程将数据向下传递,具体方法是调用下级filter输入Pin的IMemInputPin::Receive函数实现;

②拉模式:常用于文件源,源filter输出pin需实现IAsyncReader接口,由下级filter的输入pin调用该接口的方法获取数据。

* DirectShow需要专门的线程来传送数据,因此至少需要两个线程(应用程序主线程和数据线程)。


Filter的状态转换

任何Filter可能分为三种状态,即“Run”、“Stop”和“Pause”。通常情况下整个Filter Graph中的filter都处于同一状态,那么这个状态也成为整个Filter Graph的状态。

在具体实现中,每个Filter实现了IBaseFilter接口,该接口继承自IMediaFilter接口,该接口的方法实现了Filter的状态转换功能。Filter Graph Manager在控制Filter Graph的运行时,通常调用其IMediaControl的Run/Pause/Stop等方法控制。在这些函数的内部,正是调用了Filter Graph内所有的filter的IMediaFilter::Run()、IMediaFilter::Pause()、IMediaFilter::Stop()实现。
0 0
原创粉丝点击