4

我有这个小 C++ 代码用DirectShow播放视频剪辑。我想要的是视频永远不会停止,所以一旦它到达终点,我再次将位置设置为 0。问题是在新循环的结束和开始之间有一个我想删除的小延迟。我的代码如下所示:

#define WM_GRAPHNOTIFY  WM_USER

// Global vars
IGraphBuilder*      g_pGraphBuilder;
IMediaControl*      g_pMediaCtrl;
IMediaPosition*     g_pMediaPos;
IMediaEventEx*      g_pMediaEvent;

HWND                h_MainWindow;

// PlayVideo() - I removed the errors checking lines (irrelevant right now)
RECT grc;
IVideoWindow *pVidWin = NULL;
HRESULT hr = CoInitialize(NULL);

hr = CoCreateInstance(
    CLSID_FilterGraph, 
    NULL, 
    CLSCTX_INPROC_SERVER,
    IID_IGraphBuilder,
    (void**)&g_pGraphBuilder
);

hr = g_pGraphBuilder->RenderFile(L"Clip.mpeg", NULL);
hr = g_pGraphBuilder->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
hr = pVidWin->put_Owner((OAHWND)h_MainWindow);
hr = pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

GetClientRect(h_MainWindow, &grc);
pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);

hr = g_pGraphBuilder->QueryInterface(IID_IMediaEventEx, (void **)&g_pMediaEvent);
hr = g_pGraphBuilder->QueryInterface(IID_IMediaPosition, (void**)&g_pMediaPos);
hr = g_pMediaEvent->SetNotifyWindow((OAHWND)h_MainWindow, WM_GRAPHNOTIFY, 0);
g_pMediaEvent->SetNotifyFlags(0);

hr = g_pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&g_pMediaCtrl);
g_pMediaCtrl->Run();

// WndPrc of the main window, the WM_GRAPHNOTIFY message
long EventCode, Param1, Param2;
// ...
case WM_GRAPHNOTIFY:
    while (g_pMediaEvent->GetEvent(&EventCode, &Param1, &Param2, 0)!=E_ABORT) {
        switch (EventCode) {
            case EC_COMPLETE:
                // Going back to the start of the clip
                g_pMediaPos->put_CurrentPosition(0);
            break;
            default:
            break;
        }   
        g_pMediaEvent->FreeEventParams(EventCode, Param1, Param2);
    }
break;
// ...

正如我所说,这里的问题是视频停止和重新开始时存在明显的延迟。看起来 EC_COMPLETE 并没有在视频停止时准确发送,或者它可能是但put_CurrentPosition()需要一些时间才能将位置设置回 0。无论如何,问题是这样,我想知道是否有解决方案。

4

1 回答 1

3

循环播放没有标准的解决方案,但这项任务并非不可能,只需付出合理的努力即可完成。

错误的方法是使用标准图形/管道实现所需的行为,期望一些魔法在图形的上游部分执行无缝搜索操作。该图以非常有效的方式流式传输数据,并预加载管道以准确播放数据。但是,一旦您到达文件末尾,就会不可避免地进行搜索和状态转换,这涉及延迟

您需要两种方法中的任何一种(两种方法都需要开发工作):

  1. 一个智能自定义过滤器,它拦截完成(流结束)消息并寻找上游部分,或者在小流的情况下,完全缓冲数据并从内部缓冲区无缝继续(适用于小流)
  2. 一个两图设计,其中一部分从文件中读取并将数据发送到另一个图进行回放,而另一部分处理来自注入数据的无休止回放;您可以正常寻找第一个图,而不会延迟传播到另一个图

更新。由于媒体文件很短(可能是某种动画),所以上面的项目#1 看起来很适用。目标是缓冲过滤器接受所有内容直到完成,将其保存在内部缓冲区中,并从内部缓冲区进一步流出。

  • 源 -> ...(解复用器等)->缓冲区-> 解压缩器 -> 视频渲染器
  • 源 -> ...(解复用器等)-> 解压缩器 ->缓冲区-> 视频渲染器

这两个选项都实现了目标,您可以根据内存/速度要求和偏好在两者之间进行选择。

Buffer 过滤器的最佳基础是CBaseFilter.

于 2013-09-28T13:30:00.480 回答