directshow - 如何获取IMediaControl.Run()以开始播放文件而没有延迟

标签 directshow directshow.net

我试图使用DirectShow连续播放两个AVI文件(一个接一个),以便当播放器从一个文件过渡到下一个文件时,音频或视频不会中断。

我在窗体上有两个自定义控件。每个接口都预加载了一个AVI文件,在播放开始之前,我设置了所有DirectShow接口,设置视频窗口并调整它们的大小,依次调用IMediaControl.Run(),IMediaControl.Pause(),IMediaSeeking.SetPositions在两个控件上均重置为帧0。在窗体上,您可以看到两个文件都在其初始帧处暂停。

然后,我在第一个控件上调用IMediaControl.Run(),并等待它完成,然后再在第二个控件上调用Run()。最初,我迷上了第一个视频的EC_COMPLETE通知消息,并使用它来启动第二个视频。考虑到该事件可能会很慢到达(事实是这样,但是出于一个奇怪的原因),我尝试了另外两种方法:


检查每秒钟关闭的计时器中的第一部视频的当前位置(使用IMediaPosition.get_CurrentPosition)。当当前位置在视频停止时间的一秒之内时(预先从IMediaPosition.get_StopTime获知),我进入一个紧密的while循环,等待当前位置等于停止时间,然后调用Run()在第二个视频上。
与第一个相同,除了我用从while调用timeSetEvent替换winmm.dll循环,并设置了延迟,以便在第一个文件应该结束时正确触发。我使用回调来运行第二个文件。


这两种方法都可以大大减少第一个文件的末尾与第二个文件的开始之间的延迟,这表明EC_COMPLETE消息在文件完成后不会立即到达(我还尝试挂钩EC_SEGMENT_COMPLETE消息,这是应该用于在文件内循环,但显然没有人支持它-至少在我的机器上从来没有发生。

通过以上所有操作,可以将转换延迟从一秒缩短到几乎无法察觉的故障;大约有三分之一的时间文件完全没有中断地过渡,这表明没有根本原因使我不能一直运行。

不幸的是,轻微的延迟仍然是无法接受的。我认为(而且我很容易错了),剩余的延迟是由于在调用IMediaControl.Run()与实际开始播放视频之间存在微小的延迟。

有人知道我能做些什么来消除这种小滞后吗?被告知这无论出于何种原因从根本上都是不可能的,这也不会让我感到惊讶。我从未在Windows中遇到没有此问题的视频播放器,因此它可能不可行。

更多信息:我正在播放的AVI文件是完全未压缩的(视频和音频是未压缩的),因此我认为延迟不是由于DirectShow不得不在播放开始之前解压缩视频,尽管它可能仍会缓冲当然(这可能是问题的根源)。尽管我会开始播放,暂停然后倒回开头将解决此问题。

另外,我处理过渡的方法是将第二个控件实际放在第一个控件的下面;当第一个完成播放时,我开始第二个播放,然后在其上调用BringToFront,从而在两个原始文件之间创建了单个视频的外观。我不认为这是由于故障造成的,因为在某些时候它可以完美工作,即使这有问题,也无法解释匹配的音频故障。

甚至更多:我只是尝试“提前”在30到50毫秒之间开始播放第二个视频,这似乎消除了更多的差距,所以我猜想Run()中的延迟大约有那么长。但是,它似乎是可变的,因此这仍然不是我需要的位置。

更重要的是:也许我可以通过从内存而不是从文件加载AVI来消除这种延迟。不幸的是,我不知道该怎么做。 IMediaControl仅具有RenderFile()方法,而不具有RenderStreamRenderMemory方法。

最佳答案

如果在停止的图上调用IMediaControl :: Run,则图管理器会将调用发布到工作线程上(因此会有一些可变性)。在辅助线程上,图形将被暂停。渲染过滤器仅在接收到数据后才完成暂停过渡,因此一旦GetState()返回S_OK,图形管理器就会知道该图形已完全提示。此时,它将选择大约10ms的时间,并以该时间为起点在每个过滤器上调用Run。由于告诉每个过滤器要花时间,因此dshow Run方法具有一个参数,该参数是应播放采样时间戳为零的时钟时间-即实际过渡到运行模式的时间。

要将其与另一个图同步,首先必须确保两个图具有相同的时钟。在图形(不是过滤器)上查询IMediaFilter,然后在一个图形上调用GetSyncSource,在另一个图形上调用SetSyncSource。然后,您需要暂停第二张图,以便对其进行提示和准备。当您要启动它时,调用IMediaFilter :: Run而不是IMediaControl :: Run,您可以传递自己的开始时间。距离未来还有几毫秒,因此最好的办法可能是将第二张图的开始时间设置为第一张图的开始时间及其持续时间(对于未压缩流的索引容器,持续时间应为准确)。

另一种方法是使用多个图。将源与渲染分开将使您能够在源之间进行无缝切换,因为它们会馈入一个通用的渲染图中。 www.gdcl.co.uk/gmfbridge上有此方法的示例源代码。

G

关于directshow - 如何获取IMediaControl.Run()以开始播放文件而没有延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2469855/

相关文章:

c++ IPC - d3d 钩子(Hook)和 directshow 捕获源

c# - 任何示例项目都使用 DirectShow.NET 库在同一项目中捕获图像和视频?

directshow - 如何检测网络摄像头插入/拔出?

c# - 我是否使用 GMFBridge.DLL 来正确预览/捕获流?

c# - DirectShow:如何更改过滤器属性?

c# - 如何在 DirectShow.NET 中只播放特定的音频 channel 并将其余 channel 静音?

c++ - 如何获取directshow网络摄像头视频流的宽度和高度

audio - 我听到点击带有使用Graph Edit创建的DirectShow图的音频,但PC上的播放器软件可以流畅地播放音频

c# - 在线程中创建 DirectShow 图形

filter - DirectShow - 将参数传递给自定义源推送过滤器