筛选状态

筛选器有三种可能的状态:已停止、暂停和运行。 暂停状态的目的是提示图形中的数据,以便运行命令立即响应。 筛选器Graph管理器控制所有状态转换。 当应用程序调用 IMediaControl::RunIMediaControl::P ause 或 IMediaControl::Stop 时,筛选器Graph管理器在所有筛选器上调用相应的 IMediaFilter 方法。 在已停止和正在运行之间切换始终处于暂停状态,因此,如果应用程序调用在已停止的图形上运行,筛选器Graph管理器在运行图形之前暂停图形。

对于大多数筛选器,运行状态和暂停状态相同。 请考虑以下筛选器图:

源 > 转换 > 呈现器

假设源筛选器现在不是实时捕获源。 当源筛选器暂停时,它会创建一个线程来生成新数据,并尽快将其写入媒体示例。 线程通过调用转换筛选器的输入引脚上的 IMemInputPin::Receive 来“推送”下游示例。 转换筛选器接收源筛选器线程上的示例。 它可以使用工作线程将样本传送到呈现器,但通常在同一线程上传递它们。 当呈现器暂停时,它会等待接收示例。 收到一个样本后,它会无限期地阻止并保存该样本。 如果是视频呈现器,它将示例显示为海报图像,根据需要重新绘制图像。

此时,流已完全提示并已准备好呈现。 如果图形保持暂停状态,示例将在第一个样本后面的图形中“堆积”,直到 接收IMemAllocator::GetBuffer 中阻止每个筛选器为止。 不过,不会丢失任何数据。 取消阻止源线程后,它只需从阻止的点恢复。

源筛选器和转换筛选器会忽略从暂停到正在运行的转换, 它们只需尽可能快地继续处理数据。 但是,当呈现器运行时,它将开始呈现示例。 首先,它会在暂停时呈现它保持的样本。 然后,每次收到新样本时,都会计算样本的呈现时间。 (有关详细信息,请参阅 DirectShow.) 呈现器将每个样本保留到呈现时间,此时呈现示例。 当它等待演示时间时,它会在 Receive 方法中阻止,或者接收具有队列的工作线程上的新示例。 来自呈现器的上游筛选器不参与计划。

实时源(如捕获设备)是此常规体系结构的例外。 使用实时源时,无需提前提示任何数据。 应用程序可能会暂停图形,然后在运行图形之前等待很长时间。 图形不应呈现“过时”示例。 因此,实时源在暂停时不生成样本,仅在运行时生成。 若要向筛选器Graph管理器发出此信号,源筛选器的 IMediaFilter::GetState 方法将返回VFW_S_CANT_CUE。 此返回代码指示筛选器已切换到暂停状态,即使呈现器未收到任何数据。

筛选器停止时,它会拒绝传递给它的更多样本。 源筛选器关闭其流式处理线程,其他筛选器会关闭他们可能已创建的任何工作线程。 引脚取消提交其分配器。

状态转换

筛选器Graph管理器按上游顺序执行所有状态转换,从呈现器开始,并向后工作到源筛选器。 此排序是必要的,以防止样本被删除,并防止图形死锁。 最重要的状态转换是在暂停和停止之间:

  • 已停止暂停:随着每个筛选器的暂停,可以接收下一个筛选器中的样本。 源筛选器是最后一个暂停筛选器。 它创建流式处理线程并开始传送示例。 由于所有下游筛选器都暂停,因此任何筛选器都拒绝任何样本。 筛选器Graph管理器不会完成转换,直到图形中的每个呈现器都收到一个示例 (,但实时源除外,如前面) 所述。
  • 暂停为已停止:筛选器停止时,它会释放它保存的任何示例,从而取消阻止 在 GetBuffer 中等待的任何上游筛选器。 如果筛选器正在等待 Receive 方法中的资源,它将停止等待并从 Receive 返回,从而取消阻止调用筛选器。 因此,当筛选器Graph管理器停止下一个上游筛选器时,该筛选器不会在 GetBufferReceive 中被阻止,并且可以响应 stop 命令。 上游筛选器可能会在获取停止命令之前提供一些额外的示例,但下游筛选器只是拒绝它们,因为它已经停止。

筛选器Graph中的数据流