实现 IStream 的过滤器如何知道何时不再接收任何进一步的 IStream 命令
How can a filter implementing IStream know when it won't receive any further IStream commands
我编写了一个实现 IStream 的过滤器(COM 接口而不是 C++ 标准库 class)。这一切都很好,但我的问题是我不确定什么时候(如果有的话)我可以确定不会发送更多的 IStream 命令,因此可以关闭 IStream 后面的流。
关闭流的最简单位置是在我的过滤器上的 Stop() 中,但这为时过早。
根据 MSDN 文档,过滤器图形管理器将按上游顺序在图形中的过滤器上调用 Stop(),因此我的过滤器将在上游多路复用过滤器之前停止,该过滤器通常会使用 IStream 进行流式修复的任何结束(例如 GDCL mp4 mux 过滤器)。我已经在调试器中验证了我的过滤器上的 Stop() 被调用并在上游过滤器上调用 Stop() 之前退出(这可能会导致对我的过滤器的进一步 IStream 调用)。
系统 Microsoft 文件编写器过滤器似乎能够解决这个问题。在流式传输期间,文件编写器写入的接收器文件无法如您预期的那样重命名或移动,但一旦流式传输停止,文件就可以移动。 Microsoft 文件编写器如何检测到关闭文件是安全的?一旦图形中的所有过滤器都停止或侦听图形状态更改结束以通过插件分发器停止,它是否会获得某种额外的回调?当IStream接口释放,引用计数归零时,是否关闭文件?
我问这个问题已经有一段时间了,但我仍然没有弄清楚 MS 文件编写器是如何计算何时关闭其输出文件的。
这里有一些可能的解决方案,有些比其他的要好:
- 在过滤器被销毁或从图中移除之前,不要关闭输出流。显然 MS 文件编写器不会这样做。 GraphStudioNext uses this approach cpp file, h file
中的内部分析器文件编写器过滤器
- 在下游过滤器的 Stop() 中设置一个定时器,定期检查上游过滤器是否仍然处于活动状态。一旦上游过滤器不再处于活动状态,Stop() 已完成并且不应再有任何 IStream 调用,以便可以关闭输出流。这应该有效,但不能保证在图形上的 Stop() 调用返回之前关闭输出流。更新 - 由于过滤器已停止,因此假设它不会生成进一步的 IStream 调用可能是不安全的。根据 File Writer Filter Documentation,“...它支持 IStream 以允许读取和写入文件头 AFTER 图形停止。” [我的重点]
- 释放对 IStream 接口的最后一个引用时关闭流。如果 IStream 接口上存在任何引用计数错误,则可能会出错。上游过滤器可能会挂在 IStream 引用上,直到 pin 断开连接 and/or 过滤器被破坏。
- 在图中插入一个额外的未连接的虚拟过滤器,其唯一目的是在其自己的 Stop() 函数中等待,直到上游过滤器关闭以通知下游过滤器,以便它可以关闭其输出流。看起来像是一个可能有副作用的肮脏黑客。依赖于 Stop() 调用在图中的不同渲染器之间抢占。
- 在下游过滤器中,响应在上游过滤器上调用 Stop() 之后但在图上的 Stop() 之前发生的其他回调 returns。会很理想,但我还没有找到任何机制来做到这一点。
- 更新 2:另一个可能的想法。在包含图上的计时器回调 QueryInterface 上,并在 graph returns State_Stopped 上使用 GetState() 关闭文件输出流,因为这似乎没有发生直到所有过滤器都从 Stop() 返回并且所有流 should 都已完成。更新 3:这似乎是使用带有标志 WT_EXECUTELONGFUNCTION 调用的 CreateTimerQueueTimer 和回调中专用 CRITICAL_SECTION 上的 TryEnterCriticalSection 的最佳解决方案,以防止重新进入和线程膨胀。虽然它不能保证输出流在图 returns 上的 Stop 之前关闭,但它应该很快关闭文件(如果使用细粒度计时器,可能很快)。需要注意避免死锁和竞争条件;例如定时器回调不应缓存 AddRef 的过滤器图形接口,在过滤器图形上调用 IMediaControl::GetState() 时不应持有过滤器锁,确保代码中的其他地方定时器回调在流式传输重新开始之前明确终止,过滤器暂停,断开连接,从图表中删除等。甚至可能是 MS File Writer 也使用了这种技术,并且输出文件在 Stop() 之后很快关闭,以至于不容易检测到。
我编写了一个实现 IStream 的过滤器(COM 接口而不是 C++ 标准库 class)。这一切都很好,但我的问题是我不确定什么时候(如果有的话)我可以确定不会发送更多的 IStream 命令,因此可以关闭 IStream 后面的流。
关闭流的最简单位置是在我的过滤器上的 Stop() 中,但这为时过早。
根据 MSDN 文档,过滤器图形管理器将按上游顺序在图形中的过滤器上调用 Stop(),因此我的过滤器将在上游多路复用过滤器之前停止,该过滤器通常会使用 IStream 进行流式修复的任何结束(例如 GDCL mp4 mux 过滤器)。我已经在调试器中验证了我的过滤器上的 Stop() 被调用并在上游过滤器上调用 Stop() 之前退出(这可能会导致对我的过滤器的进一步 IStream 调用)。
系统 Microsoft 文件编写器过滤器似乎能够解决这个问题。在流式传输期间,文件编写器写入的接收器文件无法如您预期的那样重命名或移动,但一旦流式传输停止,文件就可以移动。 Microsoft 文件编写器如何检测到关闭文件是安全的?一旦图形中的所有过滤器都停止或侦听图形状态更改结束以通过插件分发器停止,它是否会获得某种额外的回调?当IStream接口释放,引用计数归零时,是否关闭文件?
我问这个问题已经有一段时间了,但我仍然没有弄清楚 MS 文件编写器是如何计算何时关闭其输出文件的。
这里有一些可能的解决方案,有些比其他的要好:
- 在过滤器被销毁或从图中移除之前,不要关闭输出流。显然 MS 文件编写器不会这样做。 GraphStudioNext uses this approach cpp file, h file 中的内部分析器文件编写器过滤器
- 在下游过滤器的 Stop() 中设置一个定时器,定期检查上游过滤器是否仍然处于活动状态。一旦上游过滤器不再处于活动状态,Stop() 已完成并且不应再有任何 IStream 调用,以便可以关闭输出流。这应该有效,但不能保证在图形上的 Stop() 调用返回之前关闭输出流。更新 - 由于过滤器已停止,因此假设它不会生成进一步的 IStream 调用可能是不安全的。根据 File Writer Filter Documentation,“...它支持 IStream 以允许读取和写入文件头 AFTER 图形停止。” [我的重点]
- 释放对 IStream 接口的最后一个引用时关闭流。如果 IStream 接口上存在任何引用计数错误,则可能会出错。上游过滤器可能会挂在 IStream 引用上,直到 pin 断开连接 and/or 过滤器被破坏。
- 在图中插入一个额外的未连接的虚拟过滤器,其唯一目的是在其自己的 Stop() 函数中等待,直到上游过滤器关闭以通知下游过滤器,以便它可以关闭其输出流。看起来像是一个可能有副作用的肮脏黑客。依赖于 Stop() 调用在图中的不同渲染器之间抢占。
- 在下游过滤器中,响应在上游过滤器上调用 Stop() 之后但在图上的 Stop() 之前发生的其他回调 returns。会很理想,但我还没有找到任何机制来做到这一点。
- 更新 2:另一个可能的想法。在包含图上的计时器回调 QueryInterface 上,并在 graph returns State_Stopped 上使用 GetState() 关闭文件输出流,因为这似乎没有发生直到所有过滤器都从 Stop() 返回并且所有流 should 都已完成。更新 3:这似乎是使用带有标志 WT_EXECUTELONGFUNCTION 调用的 CreateTimerQueueTimer 和回调中专用 CRITICAL_SECTION 上的 TryEnterCriticalSection 的最佳解决方案,以防止重新进入和线程膨胀。虽然它不能保证输出流在图 returns 上的 Stop 之前关闭,但它应该很快关闭文件(如果使用细粒度计时器,可能很快)。需要注意避免死锁和竞争条件;例如定时器回调不应缓存 AddRef 的过滤器图形接口,在过滤器图形上调用 IMediaControl::GetState() 时不应持有过滤器锁,确保代码中的其他地方定时器回调在流式传输重新开始之前明确终止,过滤器暂停,断开连接,从图表中删除等。甚至可能是 MS File Writer 也使用了这种技术,并且输出文件在 Stop() 之后很快关闭,以至于不容易检测到。