如何让IMediaControl.Run()启动文件播放没有延迟

时间:2010-03-18 12:45:41

标签: directshow directshow.net

我正在尝试使用DirectShow连续播放两个AVI文件(一个接一个),这样当播放器从一个文件转换到另一个文件时,音频或视频就不会中断。

我的表单上有两个自定义控件。每个都预装了一个AVI文件,在播放开始之前我设置所有的DirectShow界面,设置视频窗口并调整它们大小,调用IMediaControl.Run(),然后调用IMediaControl.Pause(),然后IMediaSeeking.SetPositions到在两个控件上重置为第0帧。在表单上,​​您可以看到两个文件都在其初始帧暂停。

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

  1. 检查第一个视频在定时器内的当前位置,该定时器每隔一秒左右熄灭(使用IMediaPosition.get_CurrentPosition)。当当前位置在视频停止时间的一秒内(事先从IMediaPosition.get_StopTime中知道)时,我进入紧while循环并等待当前位置等于停止时间,然后调用Run ()在第二个视频。
  2. 与第一个相同,除了我从while调用timeSetEvent来替换winmm.dll循环,并设置了一个延迟,以便在第一个文件应该向右时触发结束。我使用回调来Run()第二个文件。
  3. 这两种方法中的任何一种都大大减少了第一个文件结束和第二个文件开头之间的延迟,表明EC_COMPLETE消息在文件完成后没有立即到达(我还尝试挂钩EC_SEGMENT_COMPLETE消息) ,它应该用于在文件中循环,但显然没有人支持这个 - 它至少在我的机器上都没有出现过。

    完成上述所有工作已将转换延迟从一秒钟缩短到几乎不可察觉的故障;大约三分之一的时间文件过渡完全没有中断,这表明没有根本原因我不能让它一直工作。

    不幸的是,轻微的延迟仍然是不可接受的。我假设(我可能很容易出错)剩下的延迟是由于IMediaControl.Run()调用和视频实际开始播放之间的微小可变延迟造成的。

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

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

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

    更多:我刚尝试“早期”开始第二个视频30-50毫秒,这似乎消除了更多的差距,所以我猜测Run()中的延迟差不多这么久了。但它似乎是变数,所以这仍然不是我需要的地方。

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

1 个答案:

答案 0 :(得分:8)

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

要将其与另一个图表同步,首先必须确保两个图表具有相同的时钟。查询IMediaFilter的图形(不是过滤器),在一个图形上调用GetSyncSource,在另一个图形上调用SetSyncSource。然后你需要暂停第二个图形,以便它被提示并准备就绪。当你想要启动它时,调用IMediaFilter :: Run而不是IMediaControl :: Run,你可以通过自己的开始时间。这仍然是未来几毫秒,所以最好的办法可能是将第二个图的开始时间设置为第一个图的开始时间加上其持续时间(对于未压缩流的索引容器,持续时间应该是准确)。

另一种方法是使用多个图形。将源与渲染分离将允许您在源之间无缝切换,因为它们会提供给公共渲染图。有关此方法的示例源代码,请访问www.gdcl.co.uk/gmfbridge。