我有这个小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.无论如何,问题在于我想知道是否有解决方案。< / p>
答案 0 :(得分:3)
没有标准的循环播放解决方案,但任务并非不可能,并且可以通过合理的努力来实现。
错误的方法是使用标准图形/管道实现期望的行为,期望在图形的上游部分执行无缝搜索操作。该图以非常有效的方式流式传输数据并预加载管道以准确地播放数据。但是,一旦到达文件的末尾,就会出现不可避免的搜索和状态转换,这会导致延迟
您需要两者中的任何一种(两种方法都需要开发工作):
更新。由于媒体文件很短(可能是某种动画),因此上面的第1项看起来很合适。目标是缓冲过滤器接受所有内容直到完成,将其保留在内部缓冲区,并从内部缓冲区进一步流。
这两个选项都可以实现目标,您可以根据内存/速度要求和偏好在两者之间进行选择。
缓冲区过滤器的最佳基础是CBaseFilter
。