媒体基础上的多个视频播放会导致在不确定的时间范围后出现内存泄漏和崩溃

问题描述 投票:0回答:1

因此,我们正在使用由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);
c++ video-streaming ms-media-foundation
1个回答
0
投票

MediaFoundation界面类似

  • IMFMediaSource
  • IMFMediaSession
  • IMFMediaSink

释放它们之前必须先关机。

此时,似乎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使用其他方法。

IMFMediaSink::Shutdown

如果应用程序创建了媒体接收器,则它负责调用Shutdown以避免内存或资源泄漏。但是,在大多数应用程序中,该应用程序为媒体接收器创建一个激活对象,并且媒体会话使用该对象创建媒体接收器。在这种情况下,媒体会话(而不是应用程序)将关闭媒体接收器。 (有关更多信息,请参见激活对象。)

我还建议您在CPlayer :: CloseSession的末尾使用这种代码(在释放所有其他对象之后:

if(m_pSession != NULL){

    hr = m_pSession->Shutdown();

    ULONG ulMFObjects = m_pSession->Release();
    m_pSession = NULL;

    assert(ulMFObjects == 0);
}

要使用MFCreateVideoRendererActivate,可以查看我的MFNodePlayer项目:

MFNodePlayer

© www.soinside.com 2019 - 2024. All rights reserved.