IID_IMediaControl在停止时卡住

IID_IMediaControl is stuck when stopping it

本文关键字:IMediaControl IID      更新时间:2023-10-16

我正在使用DirectShow来捕获视频。我正在把相机连接到样本采集器上,并保存我得到的图像。

在以下代码中,我将IID_ICaptureGraphBuilder2连接到捕获设备(CLSID_VideoCaptureSources(,该捕获设备连接到采样采集器(ISampleGrabber。图形连接到IID_IMediaControl。我使用IID_IMediaControl Run and Stop。大多数时候,停车位都会卡住。出现了某种僵局。我尝试添加IID_IMediaEvent和m_pEvent->WaitForCompletion(INFINITE,&evCode(;但它仍然不起作用。暂停工作没有问题,但在尝试停止软件时,被卡住

构建图形

    ICaptureGraphBuilder2   *pBuilder;
    IBaseFilter             *pCamera;
    IPin                    *pOutPin;
    IPin                    *pInPin;
    IBaseFilter     *pSampleGrabberFilter;
    IBaseFilter     *pNullRendererFilter;
    ISampleGrabber  *pSampleGrabber;
    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGraph); 
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (LPVOID*)&pBuilder);
    CHECK_HR(hr, L"Can't create Capture Graph Builder");
    hr = pBuilder->SetFiltergraph(m_pGraph);
    CHECK_HR(hr, L"Can't SetFiltergraph");
    pCamera = CreateFilterByName(pCaptureDeviceName, CLSID_VideoCaptureSources);
    WCHAR err[256];
    wsprintf(err, L"Can't add Camera '%s' to graph", pCaptureDeviceName);
    hr = m_pGraph->AddFilter(pCamera , pCaptureDeviceName);
    CHECK_HR(hr, err);

    WCHAR filterName[256];
    pOutPin = GetPinCapture(pCamera, L"Capture", i);
    if (!pOutPin)
        continue;
    IAMStreamConfig *pConfig = NULL;
    hr = pOutPin->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig);
    CHECK_HR(hr, L"Can't get configuration");
    AM_MEDIA_TYPE *pmt = NULL;
    pConfig->GetFormat(&pmt);
    VIDEOINFOHEADER *pFrmt = (VIDEOINFOHEADER *)pmt->pbFormat;
    pFrmt->bmiHeader.biWidth = 1920;
    pFrmt->bmiHeader.biHeight = 1080;
    pConfig->SetFormat(pmt);
    SAFE_RELEASE(pConfig);
    SAFE_RELEASE(pOutPin);
   // Create a sample grabber
    wsprintf(filterName, L"Sample Grabber %d", i);
    // Create a sample grabber
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pSampleGrabberFilter);
    CHECK_HR(hr, L"Unable to create sample grabber filter");
    // Initialize sample grabber
    hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void **)&pSampleGrabber);
    CHECK_HR(hr, L"Unable to get sample grabber");
    hr = pSampleGrabber->SetMediaType(pmt);
    CHECK_HR(hr, L"Unable to set media type");
    hr = pSampleGrabber->SetBufferSamples(false);
    CHECK_HR(hr, L"Unable to set buffer samples!");
    hr = pSampleGrabber->SetOneShot(false);
    CHECK_HR(hr, L"Unable to set one shot!");
    // Add the sample grabber to the graph
    hr = m_pGraph->AddFilter(pSampleGrabberFilter, filterName);
    CHECK_HR(hr, L"Unable to add sample grabber to graph");
    pOutPin = GetPinCapture(pCamera, L"Capture", i);
    pInPin = GetPin(pSampleGrabberFilter, PINDIR_INPUT);
    hr = m_pGraph->ConnectDirect(pOutPin, pInPin, 0);
    CHECK_HR(hr, L"Unable to connect Camera to pSampleGrabberFilter");
    SAFE_RELEASE(pOutPin);
    SAFE_RELEASE(pInPin);
    wsprintf(filterName, L"Null Renderer %d", i);
    // Create a null renderer
    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter,(void **)&pNullRendererFilter);
    CHECK_HR(hr, L"Unable to create null renderer filter");
    hr = m_pGraph->AddFilter(pNullRendererFilter, filterName);
    CHECK_HR(hr, L"Unable to add null renderer to graph");
    pOutPin = GetPin(pSampleGrabberFilter, PINDIR_OUTPUT);
    pInPin = GetPin(pNullRendererFilter, PINDIR_INPUT);
    hr = m_pGraph->ConnectDirect(pOutPin, pInPin, 0);
    SAFE_RELEASE(pOutPin);
    SAFE_RELEASE(pInPin);
    pFrmt = ((VIDEOINFOHEADER *)pmt->pbFormat);
    // Initialize the capture grabber
    m_pCapGrabber[i] = new CapGrabber(i);
    m_pCapGrabber[i]->SetVideoInfoHeader(pFrmt);
    m_pCapGrabber[i]->SetAttachGrabberCB(m_funcAttachGrabber);
    m_pCapGrabber[i]->SetWidth((int)pFrmt->bmiHeader.biWidth);
    m_pCapGrabber[i]->SetHeight((int)pFrmt->bmiHeader.biHeight);
    // Set the capture callback
    hr = pSampleGrabber->SetCallback(m_pCapGrabber[i], 1);
    SAFE_RELEASE(pSampleGrabberFilter);
    SAFE_RELEASE(pSampleGrabber);
    SAFE_RELEASE(pNullRendererFilter);

这个问题很典型,但它只是一个猜测,没有其他需要了解的细节。启动多线程操作很容易,但在停止操作时,需要同步线程,而不准确的同步操作是死锁的典型原因——正如您所看到的那样。

为了解决这个问题,您通常会将调试器附加到有问题的进程,并检查其调用堆栈。你会看到一个线程调用stop,并在调用的深处睡觉,等待其他事情发生。很可能还有另一个线程也在做一些可疑的事情。

线程、调用堆栈和上面的模块都在提示问题所在,并将问题隔离到特定的过滤器或库中。除此之外,您可能还想开始缩小图形,暂时删除过滤器,直到您看到冻结消失,并确定可疑过滤器。

有时最好暂停图形,等待状态更改后再停止图形。还要注意,根据msdn停止不会将图形位置重置为开头。

http://msdn.microsoft.com/en-us/library/windows/desktop/dd390178(v=vs.85(.aspx

因此,要确保图形在停止后开始。我建议使用SetPosition接口。下面是我用来停止图形的一小段代码。我假设您拥有有效的媒体控制和媒体搜索接口。

    IMediaControl *m_pControl = NULL; 
    IMediaSeeking *m_pMediaSeek = NULL;
    //Assuming that you have valid media control interface and media seeking interface    using QueryInterface
    long long m_pStart = 0;
    m_pControl->Pause();
    m_pControl->GetState(1000, NULL);

    m_pMediaSeek->SetPositions(&m_pStart, AM_SEEKING_AbsolutePositioning, NULL,  AM_SEEKING_NoPositioning);
    m_pControl->Run();
    m_pControl->GetState(1000,NULL);
    m_pControl->Stop();
    m_pControl->GetState(1000,NULL);