因此,我们正在使用由c ++媒体基础代码组成的堆栈来播放视频文件。一个重要的要求是能够以不断重复的顺序播放这些视频,因此每个视频插槽都会定期更改正在播放的视频。在当前示例中,我们将创建16个HWND来将视频渲染到16个相应的播放器对象中。主应用程序一个接一个地循环遍历它们,然后执行以下操作:
关闭最后一个玩家释放对象针对新玩家的CoCreateinstance用(旧的)HWND初始化播放器开始播放媒体播放器称为“ MediaPlayer2”,它需要构建并注册为COM(regsvr32)。主要应用程序可在TAPlayer2项目中找到。它在注册表中搜索播放器的CLSID并将其实例化。作为当前的测试文件,我们使用的test.mp4必须驻留在磁盘上,例如C:\ test.mp4
现在开始一切正常。程序在播放器中循环播放,并且视频不断重新开始播放。内存占用是正常的,并且一切顺利。经过20分钟到4天之间的时间限制后,所有突然发生的事情都会变得很奇怪。在这一点上,似乎EVR对“ InitializeRenderer”的调用速度变慢,最终根本不再进行。这样一来,线程数和内存占用量也将开始急剧增加,并且在一定时间后,取决于现有的RAM,所有内存都将耗尽,并且我们的应用程序崩溃,通常在GPU驱动程序中或EVR DLL附近。
我很高兴尝试提出解决我的问题的任何其他代码示例:同时显示多个视频窗口,并像在播放列表中一样循环浏览它们。需要在Windows 10上运行!我已经为此花了很长时间了,而且很难坚持。我上传了上述代码示例,并将链接添加到了这篇文章。这应该可以立即使用。如果愿意,我也可以在线程的此处提供代码摘录。
感谢您的任何帮助,谢谢
托马斯
链接到演示项目(VS2015):https://filebin.net/l8gl79jrz6fd02vt
编辑:winmain.cpp末尾的以下代码用于重新启动播放器:
do
{
for (int i = 0; i < PLAYER_COUNT; i++)
{
hr = g_pPlayer[i]->Shutdown();
SafeRelease(&g_pPlayer[i]);
hr = CoCreateInstance(CLSID_AvasysPlayer, // CLSID of the coclass
NULL, // no aggregation
CLSCTX_INPROC_SERVER, // the server is in-proc
__uuidof(IAvasysPlayer), // IID of the interface we want
(void**)&g_pPlayer[i]); // address of our interface pointer
hr = g_pPlayer[i]->InitPlayer(hwndPlayers[i]);
hr = g_pPlayer[i]->OpenUrl(L"C:\\test.mp4");
}
} while (true);
MediaFoundation界面类似
释放它们之前必须先关机。
此时,似乎EVR调用“ InitializeRenderer”的速度变慢,最终根本不再进行。...通常在GPU驱动程序中或EVR DLL附近。
一个在您的代码中进行精确搜索的好方法。
在文件CPlayerTopoBuilder :: AddBranchToPartialTopology中的PlayerTopoBuilder.cpp文件中:
if (bVideo)
{
if (false) {
BREAK_ON_FAIL(hr = CreateMediaSinkActivate(pSD, hVideoWnd, &pSinkActivate));
BREAK_ON_FAIL(hr = AddOutputNode(pTopology, pSinkActivate, 0, &pOutputNode));
}
else {
//// try directly create renderer
BREAK_ON_FAIL(hr = MFCreateVideoRenderer(__uuidof(IMFMediaSink), (void**)&pMediaSink));
CComQIPtr<IMFVideoRenderer> pRenderer = pMediaSink;
BREAK_ON_FAIL(hr = pRenderer->InitializeRenderer(nullptr, nullptr));
CComQIPtr<IMFGetService> getService(pRenderer);
BREAK_ON_FAIL(hr = getService->GetService(MR_VIDEO_RENDER_SERVICE, __uuidof(IMFVideoDisplayControl), (void**)&pVideoDisplayControl));
BREAK_ON_FAIL(hr = pVideoDisplayControl->SetVideoWindow(hVideoWnd));
BREAK_ON_FAIL(hr = pMediaSink->GetStreamSinkByIndex(0, &pStreamSink));
BREAK_ON_FAIL(hr = AddOutputNode(pTopology, 0, &pOutputNode, pStreamSink));
}
}
您使用MFCreateVideoRenderer和pMediaSink创建了一个IMFMediaSink。由于使用了CComPtr,因此发布了pMediaSink,但从未关机。
您必须在媒体接收器上保留一个引用,并在播放机关闭时将其关闭/释放。
或者您可以对MFCreateVideoRendererActivate使用其他方法。
如果应用程序创建了媒体接收器,则它负责调用Shutdown以避免内存或资源泄漏。但是,在大多数应用程序中,该应用程序为媒体接收器创建一个激活对象,并且媒体会话使用该对象创建媒体接收器。在这种情况下,媒体会话(而不是应用程序)将关闭媒体接收器。 (有关更多信息,请参见激活对象。)
我还建议您在CPlayer :: CloseSession的末尾使用这种代码(在释放所有其他对象之后:
if(m_pSession != NULL){
hr = m_pSession->Shutdown();
ULONG ulMFObjects = m_pSession->Release();
m_pSession = NULL;
assert(ulMFObjects == 0);
}
要使用MFCreateVideoRendererActivate,可以查看我的MFNodePlayer项目: