DirectShow 动态重联
在大多数DirectShow筛选器中,当图形正在活动地流式传输数据时,无法重新连接管脚。应用程序必须在重新连接管脚之前停止图形。但是,某些过滤器在图形运行时确实支持pin重新连接,这一过程称为动态重新连接。这可以由应用程序或图形中的过滤器来完成。
作为示例,请查看下图中的图形。
动态重新连接的一种方案可能是在图运行时从图中删除过滤器2,然后用另一个筛选器替换它。要使此场景正常工作,必须满足以下条件:
- 过滤器3上的输入引脚(引脚D)必须支持IPinConnection接口。此接口允许在不停止过滤器的情况下重新连接管脚。
- 过滤器1上的输出引脚(引脚A)必须能够在重新连接时阻止媒体数据流。在重新连接期间,没有数据可以在插脚A和插脚D之间传输。通常,这意味着输出引脚必须支持IPinFlowControl接口。但是,如果过滤器1是启动重新连接的筛选器,则它可能有某种内部机制来阻止自己的数据流。
动态重连包括以下步骤:
- 阻止来自插脚A的数据流。
- 可能通过新的中间滤清器将针脚A重新连接到Pin D。
- 解除锁定Pin A,以便数据再次开始流动。
第一步 阻止数据流
若要阻止数据流,请在pin A上调用IPinFlowControl::block。可以异步或同步调用此方法。要异步调用该方法,请创建Win32事件对象并将事件句柄传递给块方法。方法将立即返回。使用诸如WaitForSingleObject之类的函数等待向事件发出信号。该引脚在阻止数据流时向事件发出信号。例如:
// 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);
}
}
要同步调用该方法,只需传递值NULL而不是事件句柄。现在该方法将阻塞,直到操作完成。在准备好交付新Sample之前,这可能不会发生。如果过滤器暂停,这可能需要任意的时间长度。因此,不要从主应用程序线程进行同步调用。使用工作线程,或者异步调用该方法。
第二步 重新连接管脚
要重新连接管脚,请查询IGraphConfig接口的筛选器图形管理器,并调用IGraphConfig::reconnect或IGraphConfig::Reconfigure。重新连接方法更易于使用;它执行以下操作:
- 停止中间过滤器(示例中的过滤器2)并将其从图形中删除。
- 如果需要,添加新的中间过滤器。
- 连接所有针脚。
- 暂停或运行任何新筛选器,以匹配图形的状态。
- 重新连接方法有几个可选参数,可用于指定针连接的介质类型和要使用的中间筛选器。例如:
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方法,该方法调用应用程序定义的回调方法来重新连接管脚。要使用此方法,请在应用程序中实现IGraphConfigCallback接口。
在调用Reconfigure之前,阻止来自输出引脚的数据流,如前所述。然后按如下所示,推送正在重新连接的图形部分中仍挂起的任何数据:
- 在重新连接链中最下游的输入管脚(示例中的管脚D)上调用IPinConnection::NotifyEndOfStream。传入Win32事件的句柄。
- 在输入管脚上调用IPin::EndOfStream,该管脚位于阻止数据流的输出管脚的下游。(在本例中,数据流在插脚A处被阻塞,因此您可以在插脚B上调用EndOfStream。)
- 等待事件发出信号。输入管脚(管脚D)在接收到流结束通知时向事件发送信号。这表示没有数据在管脚之间传输,并且调用者可以安全地重新连接管脚。
请注意,IGraphConfig::Reconnect方法自动处理前面的步骤。如果您使用的是Reconfigure方法,那么只需要执行这些步骤。
在将数据推送到图形中之后,调用Reconfigure并将指针传递给IGraphConfigCallback接口。过滤器图形管理器将调用您提供的IGraphConfigCallback::configure方法。
第三步 取消阻止数据流
重新连接管脚后,通过调用第一个参数的值为零的IPinFlowControl::Block来解除数据流的阻塞。