DirectShow技术介绍(长篇)-8

原创 2011年01月10日 10:20:00

 

3.7. Graph动态重建(Dynamic Graph Building

     如果你需要修改一个已经存在的filter graph,你可以停止,修改后再重新启动它。这通常是一种最佳的解决方法。但是,在某此情况下,你可能需要在一个graph处于运行状态时来修改它,比如:

     *应用程序在进行视频回放时需要插入一个(视频滤镜filter)Video effect filter

     source filter在播放的过程中改变了媒体格式,此时可能需要接入新的解码filter;

     *应用程序在graph中加入一个新的视频流。

     上面的这些都是graph动态重建的例子。所有在graph继续处于运行状态而做的graph修改都被叫做graph动态重建。动态重建可以由应用程序发起,也可以由一个在graph中的filter发起。动态重建有三种可能:

     *媒体格式动态变化:一个filter可以在运行的中途改变媒体格式,而不需要重新被替换为另一个;

     *动态重连:在graph中添加或删除filter

     Filter Chain操作:添加,删除,控制filter chain,(Filter Chain是相互连接着的一条Filter链路,并且链路中的每个Filter至多有一个Input pin,至多有一个Output pin

   

3.7.1. 动态重连

     在绝大多数的directshow filter中,当graph处于运行状态时pin是不能被重新连接的,应用程序必须在重连前停止graph。但是,某些filter却支持动态重连,这既可以由应用程序来执行,也可以由graph中的一个filter来执行。

     假设我们要将filter 2graph中移除掉,替换成另一个filter,而此时graph还处于运行状态,那么必须具备以下几个条件:

     filter 3的输入pin(pin D)必须支持IPinConnection接口,这个接口可以重新连接pin而不需要停止它。

     filter 1的输出pin(pin A)必须能够在重连时阻塞媒体数据,数据不再在pin Apin D之间传递。也就是说,输出Pin必须支持IPinFlowControl接口。但是,如果filter 1是发起重连的那个filter,那么它有可能已经在其内部实现了阻塞;

     动态重连包括下列步骤:

     1. Pin A那里阻塞数据流

     2. 重新连接Pin APin D,或者在中间加入新的filter

     3. 取消Pin A上的阻塞

 

    步骤1. 阻塞数据流

     通过调用Pin A上的IPinFlowControl::Block方法来阻塞数据流。这个方法既可以被同步调用,也可以被异步调用。要异步调用这个方法,需要创建一个win32事件对象,并将事件句柄传给Block,方法会立即返回,然后使用WaitForSingleObject或其它函数来等待事件的触发。当阻塞工作完成时,pin会触发这个事件。如:

 

 

// Create an event

HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if (hEvent != NULL)

{

     // Block the data flow.

     hr = pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, hEvent);

     if (SUCCEEDED(hr))

     {

         // Wait for the pin to finish.

         DWORD dwRes = WaitForSingleObject(hEvent, dwMilliseconds);

     }

}

   如果是同步调用Block,那么只需将传入的hEvent参数设为NULL,此时这个方法会一直阻塞到阻塞工作完成为止。如果pin还没有准备好deliver一个新的sample,那么就会一直阻塞。而如果filter处于就绪状态,这可能会花费任意长的时间,因此,不要在应用程序的主线程中使用同步调用,以免发生死锁,开一个工作线程来使用同步调用,或者干脆就使用异步调用。

 

    步骤2. 重连pin

     要重新连接pin,查询graphIGraphConfig接口并调用IGraphConfig::ReconnectIGraphConfig::ReconfigureReconnect方法使用比较简单:

     *停止中间filter(比如filter 2),并移除它

     *如果需要的话,加入新的中间filter

     *连接所有的pin

     pauserun所有新的filter,使它的状态与graph相同

     Reconnect方法有参数可以用来指定pin连接的媒体类型和中间filter。如:

pGraph->AddFilter(pNewFilter, L"New Filter for the Graph");

pConfig->Reconnect(

     pPinA,       // Reconnect this output pin...

     pPinD,       // ... to this input pin.

     pMediaType, // Use this media type.

     pNewFilter, // Connect them through this filter.

     NULL,

     0); 

     如果Reconnect还不够用来应付我们的要求,那么你可以使用Reconfigure方法,它调用一个由应用程序定义的回调函数来重连这些pin。要调用这个方法,需要在你的应用程序中实现IGraphConfigCallback接口。

     在调用Reconfigure之前,如前面所述地那样阻塞输出pin的数据流。然后如下所示,将处于待处理状态的数据push下去:

     1. 在重连链路中处于下游的最远的那个输入pin(例子中为Pin D)上调用IPinConnection::NotifyEndOfStream方法,方法的参数是一个Win32事件句柄;

     2. 在与要阻塞数据的那个输出pin直接相连的那个输入pin上调用IPin::EndOfStream方法。(在例子中,要阻塞的那个输出pinpin A,那么直接与之相连的那个输入pinPin B)

     3. 等待事件触发。输入pinpin D)在它接收到end-of-stream事件通告时触发事件。这表示再没有数据需要传输,此时就可以安全地进行重连了。

     注意:IGraphConfig::Reconnect方法会自动处理上述步骤,你仅在调用Reconfigure方法时才需要自己来处理。

     当数据完成push后,调用Reconfigure,传入IGraphConfigCallback回调函数的指针。Filter Graph Manager会调用IGraphConfigCallback::Reconfigure方法。

 

    步骤3. 取消数据流的阻塞

    当你完成重连后,通过调用IPinFlowControl::Block,第一个参数为0来取消阻塞。

     注意:如果动态重连是由一个filter来执行的,那么你需要知道一点线程方面的问题。如果filter graph manager尝试去停止filter,它可能会死锁,因为graph等待filter停止,而与此同时,filter有可能在等待数据在graph中完成push。要防止这个可能存在的死锁问题,如前所述可以用事件机制来处理。

 

3.7.2. filter链(filter chains

     一个filter chain是一系列具备下述条件的相互连接的filter

     *每一个在链中的filter最多只有一个已连接的输入pin和一个已连接的输出pin;

     Filter链路中的数据流不依赖于链路外的其他Filter

     举个例子,在下图中,filter A-BC-DF-G-H是一个filter chains。每个F-G-H中的子链(F-GG-H)也是一个filter chain。一个filter chain同样可以是由单个filter组成的,因此ABCDFGH同样也是filter chainfilter E由于有两个输入连接,所以任何含有E的一系列filter都不是filter chain

    IFilterChain接口提供下述方法来控制filter chain:

 

    IFilterChain::StartChain   开启一个链

    IFilterChain::StopChain    停止一个链

    IFilterChain::PauseChain   暂停一个链

    IFilterChain::RemoveChain   graph中移除一个链

 

     没有特殊的方法来添加一个链,要添加链,通过调用IFilterGraph::AddFilter方法来插入新的filter,然后调用IGraphBuilder::ConnectIGraphBuilder::Render或类似的方法来连接它们。

     graph运行时,一个filter chain可以在运行和停止状态间切换。当graph处理就绪状态时,它可以在就绪和停止状态间切换。这是两种仅有的filter chain状态切换可能。

    Filter链指南

     当你使用IFilterChain方法时,确认在graph中的filter是否能支持filter链操作是十分必要的,否则,可能会发生死锁或graph错误。filter连接到链上必须发生在链状态改变后。

     使用IFilterChain的最佳情况是与一系统为链而设计的filter一起使用。使用下面的指南来确保你的filter是链操作安全的。

    *在filter链状态变化前,所在在filter链分界线上调用的数据处理都必须已完成。这个规则应用于IMemInputPin::ReceiveIPin::NewSeqmentIPin::EndOfStream方法。链中的filter必须从由链外filter实现的这些方法调用中返回;而链外的filter也必须从这些由链内filter实现的这些方法调用中返回。

     举个例子,在上图中,filter B必须完成在filter A上的所有数据处理调用,而filter E也必须完成从filter D上的调用。如果pin暴露了IPinFlowControlIPinConnection接口,那么如在动态重连那一节中所讲的,你可以通过调用IPinFlowControl::BlockIGraphConfig::PushThroughData方法来推数据。filter也可能通过自己的方法来推数据。

    *上游filter必须与链的状态一起发生变化。比如,在上图中,假如链已停止,但filter A调用IMemInputPin::Receive方法,那么调用将失败,作为回应,filter A停止流。当应用程序重新开启链时,不会产生什么影响,因为filter A不再向使数据流动了。

    *下游filter必须同样与链的状态一起发生变化,否则,下游filter在等待取得sample时会发生死锁,因为sample不会再到来了。比如,多路复用(MUXfilter总是在它所有的input pin上需要数据,如果挂起其中的一个input pin,在其它input pin上的流处理也会被阻塞。这会导致graph死锁

    *每个与链内部filter相连的外部filterpin必须拥有自己的分配器(allocator),它不能被其它pin连接共享。当链的状态发生变化或从graph移除掉时,分配器便不可用了,此时如果还有其它的连接使用这个分配器的话,它们将不能再处理sample了。

    *除非与链相连的filter支持动态断开,否则不要移除链。典型的,已连接的filter会支持IPinConnectionIPinFlowControl接口,或者用它自己定义的接口代替。

 

DirectShow技术介绍(长篇)-3

3.2.5. 硬件如何参与Filter Graph     这一节描述了DirectShow如何与音频和视频硬件交互。         外壳filter(Wrapper Filter)     所...
  • bisword
  • bisword
  • 2011年01月10日 10:09
  • 1172

DirectShow技术介绍(长篇)-1

DirectShow 用于控制多媒体数据流;它可以在运行时允许用户播放数字电影和对不同格式的声音进行解码,包括MPEG-1。这种播放性能可以让音视频卡支持Microsoft DirectX?的API,...
  • bisword
  • bisword
  • 2011年01月10日 10:05
  • 2434

DirectShow技术介绍(长篇)-5

3.4. Filter Graph中的数据流     这一节主要描述媒体数据是如何在filter graph中流动的。如果你只是为了编写DirectShow应用程序,你不需要知道这些细节,当然,知道...
  • bisword
  • bisword
  • 2011年01月10日 10:12
  • 766

DirectShow技术介绍(长篇)-2

2. 开始DirectShow旅程     这个章节的内容主要是编写DirectShow应用所需的一些基本概念,可以把它当作一个高级介绍,理解这些内容只需具备一般的编程和有关多媒体的知识。2.1. 设...
  • bisword
  • bisword
  • 2011年01月10日 10:06
  • 1138

DirectShow技术介绍(长篇)-9

3.8. 插件发布者(Plug-in Distributors)    Plug-in Distributors(PIDs)是扩展filter graph manager的一种方法。一个PID是f...
  • bisword
  • bisword
  • 2011年01月10日 10:21
  • 624

介绍长篇文档排版技巧2 标准版

  • 2008年12月03日 14:28
  • 448KB
  • 下载

介绍长篇文档排版技巧1 标准版

  • 2008年12月03日 14:26
  • 711KB
  • 下载

配置DirectShow开发环境(VS2010,64位Win8系统)

配置DirectShow开发环境(VS2010,64位Win8系统) 目前,新版的DirectShow并没有包括在DirecxtX中一起发布,而是和Windows SDK一起打包发布,因此首先要下载...
  • iw1210
  • iw1210
  • 2016年03月20日 14:27
  • 1872

一个清华学子写的关于directshow的学习心得。8错。

http://bbs.tsinghua.edu.cn/pc/pccon.php?id=4962&nid=132351   学习DirectShow有一段时间了,把这段学习过程中翻译出来的SD...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:DirectShow技术介绍(长篇)-8
举报原因:
原因补充:

(最多只允许输入30个字)