退出 main() 后 Directshow 应用程序崩溃

Directshow Application crash after exiting of main()

我正在编写 directshow 应用程序。下面是工作正常但崩溃并出现错误消息 "App.exe has stopped working" 的代码。整个代码写在下面。请注意,我使用的是 Windows SDK 7.0,它没有 atlbase.h,因此我不能使用 CComPtr<IBaseFilter> myFilter; 类型的指针声明,它应该在退出时清除内存。

编辑: 只有当我显式连接所有过滤器时,应用程序才会崩溃。在这种情况下,不会调用我的过滤器的析构函数。如果我只是将源过滤器连接到渲染器(它将在内部连接我的过滤器和一个多路分解过滤器),我的过滤器的析构函数被调用并且没有崩溃。我已将宏 MANUAL_CONNECT 放在导致崩溃的代码上。我删除了 RemoveFilter 调用并将其替换为 Release 调用。

我在这里编写应用程序代码:

void main(WORD32 argc, CHAR *argv[])
{
        // Initialize the COM library.
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        printf("ERROR - Could not initialize COM library");
        return;
    }
    {
        IGraphBuilder           *pGraph = NULL;
        IFileSourceFilter       *pFileSourceFilter = NULL;
        IMediaControl           *pControl = NULL;
        IMediaEvent             *pEvent = NULL;
        IBaseFilter             *pSource = NULL;
        IBaseFilter             *pVideoDecode = NULL;
        IBaseFilter             *pVideoRenderer = NULL;
        IEnumPins               *pEnumPins = NULL;
        IPin                    *pPinIn = NULL;
        IPin                    *pPinOut = NULL;
        ULONG                   fetched;
        PIN_INFO                PinInfo;    
        IEnumFilters            *pEnum = NULL;
        BOOL                    stop = FALSE;
        int i;

        // Create the filter graph manager and query for interfaces.
        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);

        // Create the filter graph manager and query for interfaces.
        hr = CoCreateInstance(CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pSource);

        hr = pGraph->AddFilter(pSource, NULL);

        hr = pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSourceFilter);

        hr = pFileSourceFilter->Load(L"input.mp4", NULL);

        // Create Ittiam HEVC Decoder instance
        hr = CoCreateInstance(CLSID_ivdec, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pVideoDecode);

        // Create Video Renderer instance. We have used default video renderer
        hr = CoCreateInstance(CLSID_VideoRendererDefault, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pVideoRenderer);

        // Add decoder filter to the filter graph
        hr = pGraph->AddFilter(pVideoDecode, NULL);

        // Add renderer filter to the filter graph
        hr = pGraph->AddFilter(pVideoRenderer, NULL);

        /**************************************************************/
        /* -- Connecting source filter to demux filter starts here -- */
        /**************************************************************/
        // Enumerate pins of the source filter
        hr = pSource->EnumPins(&pEnumPins);
        hr = pEnumPins->Reset();
        // Get pin of source filter. Source filter has only output pin, so no check required
        hr = pEnumPins->Next(1, &pPinOut, &fetched);
        hr = pEnumPins->Release();
#if MANUAL_CONNECT
        // Enumerate pins of the decoder filter
        hr = pVideoDecode->EnumPins(&pEnumPins);
        hr = pEnumPins->Reset();
        // Get pin of decoder filter. Decoder filter has 2 pins, so ensure the selected pin is input pin.
        // If not, get another pin
        hr = pEnumPins->Next(1, &pPinIn, &fetched);
        hr = pPinIn->QueryPinInfo(&PinInfo);
        if(PINDIR_OUTPUT == PinInfo.dir)
        {
            hr = pPinIn->Release();
            hr = pEnumPins->Next(1, &pPinIn, &fetched);
        }

        // Connect output pin of demux filter to input pin of decoder filter
        hr = pGraph->Connect(pPinOut, pPinIn);

        /*************************************************************/
        /* -- Connecting demux filter to decoder filter ends here -- */
        /*************************************************************/

        /******************************************************************/
        /* -- Connecting decoder filter to renderer filter starts here -- */
        /******************************************************************/
        // Enumerate pins of the decoder filter
        hr = pVideoDecode->EnumPins(&pEnumPins);
        hr = pEnumPins->Reset();
        // Get pin of decoder filter. Decoder filter has 2 pins, so ensure the selected pin is output pin.
        // If not, get another pin
        hr = pEnumPins->Next(1, &pPinOut, &fetched);
        hr = pPinOut->QueryPinInfo(&PinInfo);
        if(PINDIR_INPUT == PinInfo.dir)
        {
            hr = pPinOut->Release();
            hr = pEnumPins->Next(1, &pPinOut, &fetched);
        }
        hr = pEnumPins->Release();
#endif

        // Enumerate pins of the renderer filter
        hr = pVideoRenderer->EnumPins(&pEnumPins);
        hr = pEnumPins->Reset();
        // Get pin of renderer filter. Renderer filter has only input pin, so no check required
        hr = pEnumPins->Next(1, &pPinIn, &fetched);
        hr = pPinIn->QueryPinInfo(&PinInfo);

        // Connect output pin of decoder filter to input pin of renderer filter
        hr = pGraph->Connect(pPinOut, pPinIn);

        /****************************************************************/
        /* -- Connecting decoder filter to renderer filter ends here -- */
        /****************************************************************/

        hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
        hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

        // Run the graph.
        hr = pControl->Run();

        if (SUCCEEDED(hr))
        {
            // Wait for completion.
            long evCode;
            pEvent->WaitForCompletion(INFINITE, &evCode);

            // Note: Do not use INFINITE in a real application, because it
            // can block indefinitely.
        }

        hr = pControl->Stop();

        hr = pSource->Release();
        hr = pVideoDecode->Release();
        hr = pControl->Release();
        hr = pEvent->Release();
        hr = pGraph->Release();
    }

    CoUninitialize();
    printf("Exiting main!!\n");
}

我已从 post 中删除错误检查,但我的代码中有所有错误检查。我可以看到 Exiting main!! 打印,但应用程序崩溃了。关于如何调试这个的任何建议?如果缺少任何信息,请告诉我。我正在使用 Microsoft Visual C++ 2010 Express 进行开发。

你必须在调用CoUninitialize之前终止线程上的所有COMactivity(具体来说:释放所有COM接口指针),你不这样做。

例如,请参阅 this code 及其在 _tmain 底部的 Release 调用。

使用较新版本的 Visual Studio(2013、2015)是有意义的,其中免费社区版已经包含 ATL,您可以使用 CComPtr 和朋友享受自动 COM 接口引用管理。这是对那些使用原始 COM 接口指针并遇到管理不当问题的人的第一个建议。

另请参阅:

  • Not releasing filter com object causing a crash
  • Unreleased DirectShow CSource filter makes program crash at process shutdown
  • Why does CoUninitialize cause an error on exit?

更新:不准确地使用原始指针,你一直有泄漏:

    hr = pGraph->Connect(pPinOut, pPinIn);
    // ...
    hr = pEnumPins->Next(1, &pPinOut, &fetched);

IEnumPin::Next 调用覆盖 pPinOut 指针并泄漏引用。