动态重新连接

[与此页面关联的功能(DirectShow)是一项旧功能。 它已被 MediaPlayerIMFMediaEngine取代,并在媒体基金会 音频/视频捕获。 这些功能已针对 Windows 10 和 Windows 11 进行了优化。 Microsoft强烈建议新代码尽可能使用 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获,而不是 DirectShow。 Microsoft建议重写使用旧 API 的现有代码,以尽可能使用新 API。]

在大多数 DirectShow 筛选器中,在图形主动流式传输数据时,无法重新连接引脚。 应用程序必须在重新连接引脚之前停止图形。 但是,某些筛选器在图形运行时支持固定重新连接,这是一个称为动态重新连接的进程。 这可以通过应用程序或图形中的筛选器来完成。

例如,请考虑下图中的图形。

动态图形生成关系图

动态重新连接的一种方案可能是从图形中删除筛选器 2,而图形正在运行,并将其替换为另一个筛选器。 若要使此方案正常工作,必须遵循以下条件:

  • 筛选器 3(引脚 D)上的输入引脚必须支持 IPinConnection 接口。 此接口允许在不停止筛选器的情况下重新连接引脚。
  • 筛选器 1(引脚 A)上的输出引脚必须能够在重新连接发生时阻止媒体数据流。 在重新连接期间,任何数据都不能在固定 A 和引脚 D 之间移动。 通常,这意味着输出引脚必须支持 IPinFlowControl 接口。 但是,如果筛选器 1 是启动重新连接的筛选器,则它可能有一些内部机制来阻止其自己的数据流。

动态重新连接将涉及以下步骤:

  1. 阻止数据流固定 A。
  2. 将引脚 A 重新连接到引脚 D,可能通过新的中间筛选器。
  3. 取消阻止固定 A,使数据再次开始流动。

步骤 1. 阻止数据流

若要阻止数据流,请调用 pin A 上的 IPinFlowControl::Block。此方法可以异步或同步调用。 若要异步调用方法 ,请创建一个 Win32 事件对象并将事件句柄传递给 Block 方法。 该方法将立即返回。 使用 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 而不是事件句柄传递。 现在,该方法将阻止作完成。 在引脚准备好交付新示例之前,可能不会发生这种情况。 如果筛选器已暂停,则可能需要任意时间。 因此,不要从主应用程序线程进行同步调用。 使用工作线程,或者异步调用该方法。

步骤 2. 重新连接引脚

若要重新连接引脚,请查询 Filter Graph Manager 以获取 IGraphConfig 接口,并调用 IGraphConfig::重新连接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);     

有关详细信息,请参阅参考页。 如果 重新连接 方法不够灵活,则可以使用 Reconfigure 方法,该方法调用应用程序定义的回调方法重新连接引脚。 若要使用此方法,请在应用程序中实现 IGraphConfigCallback 接口。

在调用 重新配置之前,请阻止来自输出引脚的数据流,如前所述。 然后,推送仍在重新连接的图形部分挂起的任何数据,如下所示:

  1. 调用 IPinConnection::NotifyEndOfStream 重新连接链中下游最远的输入引脚(示例中的 pin D)。 传入 Win32 事件的句柄。
  2. 在输入引脚上调用 IPin::EndOfStream,该输入引脚紧接在阻止数据流的输出引脚的下游。 (在此示例中,数据流在固定 A 处被阻止,因此会在 pin B 上调用 EndOfStream
  3. 等待事件发出信号。 输入引脚(引脚 D)在收到流结束通知时向事件发出信号。 这表示没有数据在引脚之间移动,并且调用方可以安全地重新连接引脚。

请注意,IGraphConfig::重新连接 方法会自动处理前面的步骤。 仅当使用 Reconfigure 方法时,才需要执行这些步骤。

将数据推送到图形后,调用 重新配置,并将指针传递给 IGraphConfigCallback 回调接口。 Filter Graph 管理器将调用你提供的 IGraphConfigCallback::Reconfigure 方法。

步骤 3. 取消阻止数据流

重新连接引脚后,通过调用 IPinFlowControl::Block 来取消阻止数据流,第一个参数的值为零。

注意

如果动态重新连接由筛选器执行,则必须注意一些线程问题。 如果 Filter Graph 管理器尝试停止筛选器,则它可以死锁,因为图形会等待筛选器停止,同时筛选器可能正在等待数据通过图形推送。 为了防止可能的死锁,本部分中介绍的一些方法处理 Win32 事件。 如果 Filter Graph 管理器尝试停止筛选器,筛选器应向事件发出信号。 有关详细信息,请参阅 IGraphConfigIPinConnection

 

动态图形生成