实现IStream的过滤器如何知道何时不能再接收任何IStream命令

时间:2015-09-30 11:48:44

标签: directshow

我编写了一个实现IStream的过滤器(COM接口而不是C ++标准库类)。这一切都运行良好,但我的问题是我不确定何时(如果有的话)我可以确定不会发送更多的IStream命令,因此可以关闭IStream后面的流。

关闭流的最简单的地方是我的过滤器上的Stop(),但这太早了。

根据MSDN文档,过滤器图形管理器将按上游顺序在图形中的过滤器上调用Stop(),因此我的过滤器将在上游多路复用过滤器之前获得停止,该过滤器通常将使用IStream来执行流式修复的任何结束(例如, GDCL mp4 mux过滤器)。我在调试器中验证了我的过滤器上的Stop()被调用,并在上游过滤器调用Stop()之前退出(这可能会导致对我的过滤器进一步调用IStream)。

系统Microsoft文件编写器过滤器似乎能够解决这个问题。在流式传输期间,文件编写器写入的接收器文件无法按照您的预期进行重命名或移动,但一旦流式传输停止,文件就可以移动。 Microsoft文件编写器如何检测到关闭文件是否安全?一旦图表中的所有过滤器都停止或者通过插件分发器停止监听图形状态更改的结束,它是否会获得某种额外的回调?释放IStream接口并且引用计数降为零时是否关闭文件?

1 个答案:

答案 0 :(得分:2)

自从我问了这个问题已经有一段时间了,我仍然没有弄清楚MS文件编写器在关闭其输出文件时如何计算出来。

以下是一些可能的解决方案,其中一些比其他更好:

  1. 在关闭过滤器或从图形中删除过滤器之前,请不要关闭输出流。显然,MS文件编写器不会执行此操作。 GraphStudioNext中的内部分析器文件编写器过滤器使用这种方法cpp fileh file
  2. 在下游过滤器的Stop()中设置一个计时器,该计时器定期检查上游过滤器是否仍处于活动状态。一旦上游过滤器不再活动,Stop()已完成,并且不应再进行其他IStream调用,因此可以关闭输出流。这应该可以,但是不能保证在返回图上的Stop()之前关闭输出流。更新-假定由于过滤器已停止而不会再产生IStream调用,可能并不安全。根据{{​​3}},“ ...它支持IStream,以允许读写文件头 AFTER 停止图形。” [我的重点]
  3. 当释放对IStream接口的最后一个引用时,关闭流。如果IStream接口上有任何计数错误的引用,可能会出错。上游过滤器可能会挂在IStream参考上,直到引脚断开连接和/或破坏过滤器为止。
  4. 在图中插入一个额外的未连接的虚拟过滤器,其唯一目的是等待自己的Stop()函数,直到上游过滤器关闭以通知下游过滤器,以便它可以关闭其输出流。似乎是一个肮脏的hack,可能会有副作用。依靠Stop()调用在图形中的不同渲染器之间是抢占式的。
  5. 在下游过滤器中,响应在上游过滤器上调用Stop()之后但在图形上的Stop()返回之前发生的一些其他回调。会很理想,但是我还没有找到任何机制可以做到这一点。
  6. 更新2:另一个可能的想法。在包含图形的计时器回调QueryInterface上,并在图形上使用GetState()关闭文件输出流,返回State_Stopped,因为直到从Stop()返回所有过滤器和所有流应该已经结束。更新3:这似乎是使用File Writer Filter Documentation的最佳解决方案,该回调在回调的专用CRITICAL_SECTION上用标志WT_EXECUTELONGFUNCTION和TryEnterCriticalSection进行调用,以防止重新进入和线程膨胀。尽管它不能保证输出流在图形的Stop返回之前就关闭,但它应在此后不久关闭文件(如果使用细粒度的计时器,则可能很快关闭)。需要注意避免死锁和比赛条件;例如计时器回调函数不应缓存AddRef的过滤器图形接口,在过滤器图形上调用IMediaControl :: GetState()时不应持有过滤器锁,以确保代码中的其他地方,计时器回调函数在流重新启动之前一定已终止,过滤器将暂停,断开连接,从图形中移除等。甚至可能是MS File Writer也使用了此技术,并且在Stop()之后,输出文件很快关闭,以至于不易检测到。