因为Directshow是C++的东西,后来为了方便,才有牛人们在C#把directshow重写,但是相关文档很少,所以为了了解DIrectshow ,从C++下的directshow开始是最合理不过的了,但是在C#用不到的知识就基本没有提及了··
部分问题摘录:
DirectShow与ActiveMovie的关系?
ActiveMovie是DirectShow原来的名称,现已不再使用,但是一部分API仍保留了"AM"的前缀,比如AM_MEDIA_TYPE和IAMVideoAccelerator。
DMO可以代替DirectShow filter吗?
在编写编码器、解码器、效果器应用时,鼓励用DMO代替DirectShow filter。在其它的应用中,使用DirectShow filter可能会比较合适。
基础知识
Directshow使用Filter Graph来管理Filter(管理者叫做FilterGraph Manager).Filter Graph是Graph的“容器”,而Filter是FilterGraph中的最小功能模块。
在directshow中,一个filter链表我们称为Filter Graph
Filter是一种COM组件,为了实现在FilterGraph中的统一操作,每个Filter上都至少实现了IBaseFIlter接口。
Filter必须加入到FilterGraph且接入工作链路中才能发挥作用
Filter的链接实际上也是Filter上的Pin链接
试图链接两个Filter必须处于一个FilterGraph中,可以调用接口方法IFilterGraph::ADDFilter将指定Filter加入到FilterGraph中。
Filter Graph Manager 也是一个com 对象,用来控制Filtergraph 中的所有的filter,主要有以下
的功能:
1 用来协调filter 之间的状态改变,从而使graph中的所有的filter 的状态的改变应该一致。
2 建立一个参考时钟。
3 将filter 的消息返回给应用程序
4 提供方法用来建立 filter graph。
一个简单的C++例子
在C++中创建DirectShow应用程序的三个步骤
第一步,首先调用CoCreateInstance创建Filter Graph Manager:
HRESULT hr =CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph);
【(CLSID)是CLSID_FilterGraph。Filter GraphManager由进程内DLL(in-process DLL)提供,因此参数3,dwClsContext的值为CLSCTX_INPROC_SERVER。由于DirectShow运行自由线程模式 (free-threading model),所以你同样可以使用COINIT_MULTITHREADED参数来调用CoInitializeEx】
第二步是创建filter graph,调用CoCreateInstance得到的IGraphBuilder接口包含了大部分创建filtergraph的方法。在这个例子中还需要另外两个接口:IMediaControl和IMediaEvent。 IMediaControl控制数据流,它包含开启和停止graph的方法;IMediaEvent包含从Filter Graph Manager获取事件的方法,在这个例子中,这个接口用来得到回放结束事件。所有这些接口由Filter Graph Manager提供,使用得到的IGraphBuiler接口指针来查询得到。
IMediaControl *pControl;
IMediaEvent *pEvent;
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void**)&pEvent);
现在你可以创建filter graph了,下面是对食品文件的播放
hr = pGraph->RenderFile(L"C://Example.avi",NULL);
IGraphBuilder::RenderFile方法创建了一个能够播放指定文件的filter graph,事实上,原本需要做的一些如创建filter实例及将这些filter连接起来的工作,都由这个方法自动完成了,如果是视频文件,这个 filter graph看起来应该是这个样子:
[filesource]->[如果是缩格式,这里是个解码器]->[Video Renderer]
要开始回放,调用IMediaControl::Run方法:
hr = pControl->Run();
当filter graph运行时,数据经过各个filter最后回放为视频或音频。回放发生在一个单独的线程中。你可以通过调用IMediaEvent::WaitForCompletion方法来等待回放的结束:
long evCode = 0;
pEvent->WaitForCompletion(INFINITE, &evCode);
这个方法在播放期间被阻塞,直至播放结束或超时。 当应用程序结束时,需要释放接口指针并关闭COM库:
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
完整代码见:http://blog.csdn.net/eyes4/article/details/133107
DirectShow使用一个模块化的架构,每个处理过程都由一个叫做filter的COM对象来实现。DirectShow为应用程序提供了一系列标准的filter,开发者也可以编写自己的filter来扩展DirectShow的功能。下面是播放一个AVI文件的各个步骤:
*从文件中读取数据并转成字节流(File Source filter)
*检查AVI头,分析字节流并将它们分离成视频和音频(AVI Aplitter filter)
*将视频解码(不同的解码filter,取决于不同的压缩格式)
*将视频显示出来(Video Renderer filter)
*将音频送入声卡(Default DirectSound Device filter)
每个filter与一个或多个其它的filter相连,其中的连接点也是一个COM对象,称作Pin,filter使用Pin将数据从一个filter转移到另一个,图中的箭头指示了数据流动的方向。在DirectShow中,这一系列连接在一起的filter称作filter graph。
Filter可能处于有三种不同的状态:运行、停止和暂停状态。filter在运行状态时处理数据,停止状态时停止处理数据,暂停状态则是表示就绪,可以开始进入运行状态。除了极个别的情况,一个filter Graph中的所有filter通常都处理同一个状态下,因此,filter graph也可以称其处于运行、停止、暂停状态。
*Major type:主类型,是一个GUID,定义了数据的整体类型,包括了:视频、音频、未分析的字节流、MIDI等。
*Subtype:子 类型,另一个GUID,进一步定义了数据格式。比如,如果主类型是视频,则子类型可以是RGB-24、RGB-32、UYVY等格式,如果主类型是音频,则可能是PCM或MPEG-1 payload等。子类型提供了比主类型更多的内容,但仍未提供完整的格式定义,比如,子类型没有定义图像尺寸和帧率,这些都将在Format block中被定义。
*Format block:格式块,定义了具体的格式。格式块是AM_MEDIA_TYPE结构体中一个单独被分配的内存空间,pbFormat成员指向这块内存空间。因为不同的格式会有不同的格式描述,所以 pbFormat成员的类型是void*。比如,PCM音频使用WAVEFORMATEX结构体,视频使用不同的结构体包括:VIDEOINFOHEADER和VIDEOINFOHEADER2。formattype成员是一个GUID,指定了格式块包含了哪种结构体,每一种格式的结构体都被分配了GUID。cbFormat成员定义了格式式块的长度。
当格式块被定义时,主类型和子类型包含的信息就显得有点多余了。其实,主类型和子类型为识别格式提供了一个便利的方法,比方说,你可以指定一个普通的24 位RGB格式(MEDIASUBTYPE_RGB24),而不需去关心VIDEOINFOHEADER结构体中诸如图像尺寸和帧率这些信息。
关于媒体样本(Media Sample)和分配器(Allocator)
(这部分貌似C#中没有)
DirectShow提供了一系列用于构建filtergraph的组件,包括:
*Filter Graph Manager。 这个对象用于控制filter graph,支持IGraphBuilder、IMediaControl和IMediaEventEx等许多接口。所有的directshow应用程序 都需要在某些地方用到这个对象,虽然在有些情况下,是其它的对象为应用程序创建了filter graph manager。
*Capture Graph Builder。这个对象为构建filtergraph提供附加的方法。它最初是为构建提供视频采集的graph而设计的(这正是它的名字由来),但是对于构建许多另外类型的filter graph也是很有用的。它支持ICaptureGraphBuilder2接口。
下面两个名称须分清楚:
IGraphBuilder:Filter Graph Manager
ICaptureGraphBuilder2:CaptureGraph Builder
智能连接这个术语覆盖了一系列FilterGraph Manager用于构建所有或部份filter graph的算法。任何时候,当Filter Graph Manager需要添加filter来完成graph时,它大致做以下几件事情:
1.如果有一个filter存在于graph中,而且这个filter有至少一个没有连接的input pin,Filter Graph Manager试着去试用这个filter。
Grap构建概述
创建一个filter graph,从创建一个FilterGraph Manager实例开始:
IGraphBuilder* pIGB; HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder,(void **)&pIGB);
Filter GraphManager支持下列Graph构建方法:
*IFilterGraph::ConnectDirect,在两个pin之间进行直接连接,如果连接失败,则返回失败
*IFilterGraph::Connect,连接两个Pin,如果可能的话,直接连接它们,否则,在中间加入其它的filter来完成连接。
*IGraphBuilder::Render,从某个输出Pin处开始完成余下的graph构建。该方法会自动在输出pin后面添加必须的filter,直到rendererfilter为止。
*IGraphBuilder::RenderFile,构建一个完整的文件回放graph。
*IGraphBuilder::AddFilter, 将一个filter添加到graph中。它不连接filter,并且在调用此方法前,filter必须已经被创建。创建filter可以是用CoCreateInstance方法或使用Filter Mapper或系统设备枚举器(System Device Enumerator)。
这些方法提供了三种构建graph的途径:
1.filter graph manager构建整个graph
2.filter graph manager构建部分graph
3.应用程序构建整个graph
【1】Filter Graph Manager构建整个graph
如果你仅仅是想回放一个已知格式的文件,如AVI、MPEG、WAV或MP3,使用RenderFile方法。
RenderFile方法首先寻找注册在系统中能分析源文件的filter,它使用协议名(如http://),文件扩展名或文件的头几个字节来决定选择哪一个源filter。
Filter Graph Manager使用一个迭代过程来完成余下的graph构建。在这个迭代过程中,它逐个列出filter的输出pin上支持的媒体类型,并搜索哪个已注册的filter的输入Pin接受该媒体类型。它使用一系列的规则来缩小filter的范围并排定优先顺序:
*filter类别(category)标识的filter的一般功能
*媒体类型描述filter能在接受或能输出哪种数据类型
*merit值决定filter被尝试的次序。如果两个filter具有相同的filter类别并且同时支持相同的输入类型,Filter Graph Manager选择merit值大的那一个。一些filter故意给出一个小merit值是因为它是为特殊用途设计的,仅能由应用程序来将其添加到graph。
Filter Graph Manager使用Filter Mapper对象来搜索已注册的filter。
每个filter被添加时,filter graph manager试着将其与前一个filter的输出pin连接。它们协商决定他们是否能连接,如果能,哪一种媒体类型被用来连接。如果新filter不能连接,filter graph manager丢弃它并尝试别一个,这个过程一直继续到每个流都被render为止。
【2】 Filter GraphManager构建部分graph
如果不仅仅是播放一个文件,那么你的应用程序就必须做一些graph的构建工作。比如,一个视频采集应用程序必须先选择一个source filter并将其添加到graph中去。如果你需要将数据写入到一个AVI文件中,你必须添加一个AVI Mux和File Write filter。不过,也经常有可能让filter graph manager来完成整个graph,比如,你可以通过Render方法来render一个pin进行预览。
【3】应用程序构建整个graph
在某些场合,你的应用程序需要添加和连接每个filter来构建graph。在这种情况下,你很可能明确地知道哪些filter需要加到graph中去。使用这种方式,应用程序通过调用AddFilter方法添加每个filter,然后枚举filter上的pin,调用Connect或 ConnectDirect来连接它们。
智能连接
智能连接是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。
详细内容见:http://blog.csdn.net/eyes4/article/details/133119
内容主要摘于:http://blog.csdn.net/eyes4
DirectShow SDK 学习笔记
开源C# directshow类库
http://directshownet.sourceforge.net/