【问题标题】:Not releasing filter com object causing a crash未释放导致崩溃的过滤器 com 对象
【发布时间】:2013-08-09 05:38:25
【问题描述】:

我正在使用带有 vlc (http://tmhare.mvps.org/downloads/vcam.zip) 的 Viveks 捕获过滤器来模拟捕获源。当过滤器打开并关闭 vlc 时,我会崩溃。堆栈跟踪表明仍然存在 2 个 COM 对象(我猜是过滤器和引脚),它们应该在 CoUninitialize 调用之前被释放。我的问题是我不确定在哪里释放过滤器和 pin COM 对象,我有一个用于 fitler 和 pin 的析构函数,但是当 vlc 关闭时它们永远不会被调用。有类似问题的人 (Unreleased DirectShow CSource filter makes program crash at process shutdown)。

这是dll的重要注册部分。

STDAPI RegisterFilters( BOOL bRegister )
{
    HRESULT hr = NOERROR;
    WCHAR achFileName[MAX_PATH];
    char achTemp[MAX_PATH];
    ASSERT(g_hInst != 0);

    if( 0 == GetModuleFileNameA(g_hInst, achTemp, sizeof(achTemp))) 
        return AmHresultFromWin32(GetLastError());

    MultiByteToWideChar(CP_ACP, 0L, achTemp, lstrlenA(achTemp) + 1, 
                   achFileName, NUMELMS(achFileName));

    hr = CoInitialize(0);
    if(bRegister)
    {
        hr = AMovieSetupRegisterServer(CLSID_VirtualCam, L"Virtual Cam", achFileName, L"Both", L"InprocServer32");
    }

    if( SUCCEEDED(hr) )
    {
        IFilterMapper2 *fm = 0;

        hr = CreateComObject( CLSID_FilterMapper2, IID_IFilterMapper2, fm );
        if( SUCCEEDED(hr) )
        {
            if(bRegister)
            {
                IMoniker *pMoniker = 0;
                REGFILTER2 rf2;
                rf2.dwVersion = 1;
                rf2.dwMerit = MERIT_DO_NOT_USE;
                rf2.cPins = 1;
                rf2.rgPins = &AMSPinVCam;
                hr = fm->RegisterFilter(CLSID_VirtualCam, L"Virtual Cam", &pMoniker, &CLSID_VideoInputDeviceCategory, NULL, &rf2);
            }
            else
            {
                hr = fm->UnregisterFilter(&CLSID_VideoInputDeviceCategory, 0, CLSID_VirtualCam);
            }
        }  

      // release interface
      //
      if(fm)
          fm->Release();
    }

    if( SUCCEEDED(hr) && !bRegister )
         hr = AMovieSetupUnregisterServer( CLSID_VirtualCam );

    CoFreeUnusedLibraries();
    CoUninitialize();
    return hr;
}

STDAPI DllRegisterServer()
{
    return RegisterFilters(TRUE);
}

STDAPI DllUnregisterServer()
{
    return RegisterFilters(FALSE);
}

extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)
{
    return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

重要的过滤部分

CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) :
CSourceStream(NAME("Virtual Cam"),phr, pParent, pPinName), m_pParent(pParent)
{
    // Set the default media type as 320x240x24@15
    GetMediaType(4, &m_mt);
}

CVCamStream::~CVCamStream()
{
    m_pParent->Release();
} 

【问题讨论】:

  • 请提供一个小代码示例。

标签: c++ video com directshow


【解决方案1】:

泄露的 COM 引用很难确定。假设 COM 客户端 - 在您的情况下为 VLC - 一切正常(可能不是这种情况,但可以从这个假设开始),问题出在您的代码上。它通常是以下两者之一:

  1. 您正在处理原始指针,并且在某处没有与之前完成的 Release 匹配的 AddRef
  2. 有循环引用和对象互相保持活力

正如您已经看到有两个浮动的对象,一个好的策略是确定它们究竟是什么类,并跟踪引用计数器的变化以查看丢失的IUnknown::Release 的位置。

【讨论】:

  • 我正在使用原始指针,我听说过使用 CComPtr,但无法在我的 Visual Studio 版本中获取它们。你知道我如何监控对象的引用计数吗?
  • 另外我认为 vlc 做的事情是正确的,因为我可以打开一个 decklink 捕获源并在没有任何错误的情况下关闭它。
  • 将调试输出跟踪放入:构造函数、析构函数、AddRef、Release 方法。检查日志以获得线索。使用原始指针很容易出错 - 这就是 CComPtr 提供帮助的地方(QzCComPtr 是 DirectShow BaseClasses 中的备用副本,供那些没有 ATL 或不想使用它的人使用)。
  • QzCComPtr 指针在崩溃或超出范围时会调用释放吗?
  • 这些类只是几屏代码,你看一下就明白了。离开范围崩溃,析构函数(以及因此,Release)可能被调用或可能不取决于编译器设置,特别是异常处理。
猜你喜欢
  • 1970-01-01
  • 2011-08-07
  • 2012-02-27
  • 1970-01-01
  • 2011-07-02
  • 1970-01-01
  • 1970-01-01
  • 2014-08-25
  • 2022-01-05
相关资源
最近更新 更多