Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用带有CaptureGraphBuilder2的SampleGrabber时出现的问题_C++_Webcam_Directshow_Video Capture_Samplegrabber - Fatal编程技术网

C++ 使用带有CaptureGraphBuilder2的SampleGrabber时出现的问题

C++ 使用带有CaptureGraphBuilder2的SampleGrabber时出现的问题,c++,webcam,directshow,video-capture,samplegrabber,C++,Webcam,Directshow,Video Capture,Samplegrabber,我一直在尝试使用SampleGrabber从网络摄像头抓取一个帧并将其保存为位图,但没有任何运气。我在MSDN上使用了Directshow视频捕获示例,使用了ICaptureGraphBuilder2以及示例抓取器示例 我希望我的过滤器图如下所示: 网络摄像头(源)->示例抓取器->空渲染器 因为我对预览不感兴趣,所以我决定空渲染器对我来说就足够了 计划是通过搜索特定的VID和PID(webcamCapture::findWebCam())来查找我的网络摄像头,创建我的samplegrabber

我一直在尝试使用SampleGrabber从网络摄像头抓取一个帧并将其保存为位图,但没有任何运气。我在MSDN上使用了Directshow视频捕获示例,使用了ICaptureGraphBuilder2以及示例抓取器示例

我希望我的过滤器图如下所示:

网络摄像头(源)->示例抓取器->空渲染器

因为我对预览不感兴趣,所以我决定空渲染器对我来说就足够了

计划是通过搜索特定的VID和PID(webcamCapture::findWebCam())来查找我的网络摄像头,创建我的samplegrabber,创建空渲染器,然后使用pGraphBuilder->RenderStream()将它们连接在一起。因为我只需要一个帧,所以我使用了OneShot方法,然后使用GetCurrentBuffer来检索该帧

问题发生在这一行:

pEvent->WaitForCompletion(2000, &evCode);
返回的HRESULT代码为E_ABORT。将超时设置为无限导致程序冻结,这可能意味着过滤器从未停止。pControl->Run()的HRESULT为S_FALSE,这意味着并非所有筛选器都在运行。我不知道为什么会发生这种情况,我感觉在构建这些过滤器时出现了一些问题

下面是我的资料来源。我创建了一个类来处理网络摄像头捕获。在使用过程中,基本上有两件事被称为:

webcamCapture::buildFilterGraph()
webcamCapture::runFilter()
runFilter将运行过滤器并将帧保存为位图文件。 我是directshow的新手,我很确定我错过了一些简单的东西。如有任何见解,将不胜感激

来源

    HRESULT webcamCapture::buildFilterGraph(void){
    HRESULT hr;

    if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
        return hr;
    }

    createCOMInstances();

    //  Use findWebCam() to find the webcam and add it to our capture graph
    hr = findWebCam();
    if(FAILED(hr)){
        return hr;
    }

    //  Add the sample grabber to the graph
    hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
    if(FAILED(hr)){
        return hr;
    }

    hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pGrabber));
    if(FAILED(hr)){
        return hr;
    }

    //  Set media type for the sample grabber (24-bit RGB Uncompressed video)
    ZeroMemory(&mt, sizeof(mt));
    mt.majortype = MEDIATYPE_Video;
    mt.subtype = MEDIASUBTYPE_RGB24;

    hr = pGrabber->SetMediaType(&mt);
    if(FAILED(hr)){
        return hr;
    }

    hr = pGraph->AddFilter(pNullF, L"Null Filter");
    if(FAILED(hr)){
        return hr;
    }

    //  Connect source (pCapF), sample grabber (pGrabberF) and null renderer (pNullF)
    pGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pCapF,pGrabberF, pNullF);

    hr = pGrabber->SetOneShot(TRUE);
    hr = pGrabber->SetBufferSamples(TRUE);


    return S_OK;
    }

    HRESULT webcamCapture::runFilter(){
    HRESULT hr;
    FILTER_STATE filterState;

    pBuffer = NULL;



    hr = pControl->Run();
    if(FAILED(hr)){
        goto done;
    }

    pControl->GetState(1000, (OAFilterState*)&filterState);

    long evCode;
    hr = pEvent->WaitForCompletion(2000, &evCode);
    if(FAILED(hr)){
        goto done;
    }

    long cbBuffer;
    hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
    if(FAILED(hr)){
        goto done;
    }

    pBuffer = (BYTE*)CoTaskMemAlloc(cbBuffer);
    if(!pBuffer){
        hr = E_OUTOFMEMORY;
        goto done;
    }

    hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
    if(FAILED(hr)){
        goto done;
    }

    hr = pGrabber->GetConnectedMediaType(&mt);
    if(FAILED(hr)){
        goto done;
    }

    if((mt.formattype == FORMAT_VideoInfo) && (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) && (mt.pbFormat != NULL)){

        VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;
        writeBitmap(L"test_image.bmp", &pVih->bmiHeader, mt.cbFormat - SIZE_PREHEADER, pBuffer, cbBuffer);
    }

    //FreeMediaType(mt);

    done:
        CoTaskMemFree(pBuffer);
        pNullF->Release();
        pNullF = NULL;
        pCapF->Release();
        pCapF = NULL;
        pGrabber->Release();
        pGrabber = NULL;
        pGrabberF->Release();
        pGrabberF = NULL;
        pControl->Release();
        pControl = NULL;
        pEvent->Release();
        pEvent = NULL;
        pGraph->Release();
        pGraph = NULL;
        CoUninitialize();


    return hr;
    }

    HRESULT webcamCapture::createCOMInstances(void){
    HRESULT hr;

    //  Instructions to create a Capture Graph using CaptureGraphBuilder2 can be found at https://msdn.microsoft.com/en-us/library/windows/desktop/dd373396(v=vs.85).aspx

    //  Create Capture Graph Builder
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraphBuilder));
    if(FAILED(hr)){
        return hr;
    }

    //  Create Graph Manager
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
    if(FAILED(hr)){
        return hr;
    }

    //  Initialize Capture Graph Builder by referencing pGraph (Graph Manager)
    hr = pGraphBuilder->SetFiltergraph(pGraph);
    if(FAILED(hr)){
        pGraphBuilder->Release();
        return hr;
    }

    //  Set pointer to Media Control Interface
    hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
    if(FAILED(hr)){
        return hr;
    }

    //  Set pointer to Media Event Interface
    hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
    if(FAILED(hr)){
        return hr;
    }

    //  Create Sample Grabber
    //  NOTE: ISampleGrabber is depreciated and may not be supported in later versions of Windows!
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGrabberF));
    if(FAILED(hr)){
        return hr;
    }

    //  Create the null renderer filter.  We don't be previewing the camera feed so we can just drop the frames when we've converted them to bitmaps
    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pNullF));
    if(FAILED(hr)){
        return hr;
    }

    TRACE(_T("Interface Creation Successful\n"));
    return S_OK;
    }

    //  Function to find the MS HD3000 webcam (VID=0x045E PID=0x0779)
    //  For more info on finding devices for Video/Audio capture, see https://msdn.microsoft.com/en-us/library/windows/desktop/dd377566(v=vs.85).aspx
    HRESULT webcamCapture::findWebCam(void){

    HRESULT hr;
    ICreateDevEnum *pDevEnum;
    IEnumMoniker *pEnum;
    IMoniker *pMoniker;
    BOOL isDeviceFound = FALSE;

    WORD wNumCameras = 0;

    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
    if(FAILED(hr)){
        return hr;
    }

    hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
    if(hr == S_FALSE){
        return VFW_E_NOT_FOUND;
    }

    pDevEnum->Release();

    //  Go through each device moniker and read their Device Path properties.  This is how we will find our webcam of interest
    while(pEnum->Next(1, &pMoniker, NULL) == S_OK){

        IPropertyBag *pPropBag;
        VARIANT var;

        hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));

        if(FAILED(hr)){
            pMoniker->Release();
            continue;
        }

        VariantInit(&var);

        hr = pPropBag->Read(L"DevicePath", &var, 0);
        if(SUCCEEDED(hr)){
            //  String search variables
            CString csVidToCompare = _T("");
            CString csPidToCompare = _T("");
            WORD wVidSearchIndex = 0;
            WORD wPidSearchIndex = 0;

            CString csDevPath = var.bstrVal;
            csDevPath.MakeLower();

            wVidSearchIndex = csDevPath.Find(_T("vid_"), 0);
            wPidSearchIndex = csDevPath.Find(_T("pid_"), 0);

            csVidToCompare = csDevPath.Mid(wVidSearchIndex + 4, 4);
            csPidToCompare = csDevPath.Mid(wPidSearchIndex + 4, 4);

            //  If MS Device is found
            if(!csVidToCompare.Compare(_T("045e"))){
                //  If the 3000HD camera is found
                if((!csPidToCompare.Compare(_T("0779"))) && (wNumCameras == 0)){
                    wNumCameras++;
                    hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCapF);
                    if(FAILED(hr)){
                        return hr;
                    }

                    isDeviceFound = TRUE;
                    //  Add the webcam to the filter graph
                    hr = pGraph->AddFilter(pCapF, L"Capture Filter");

                    if(FAILED(hr)){
                        TRACE(_T("Failed to add webcam to filter graph\n"));
                        return hr;
                    }

                    TRACE(_T("Webcam found and added to filter!\n"));

                }

                else if((!csPidToCompare.Compare(_T("0779"))) && (wNumCameras > 0)){
                    TRACE(_T("More than one HD3000 camera found!\n"));
                    continue;
                }

                else{
                    TRACE(_T("MS Device found, but not the camera\n"));
                    continue;
                }
            }
        }

        pPropBag->Release();
        pMoniker->Release();
    }

    if(isDeviceFound == FALSE){
        TRACE(_T("Webcam was not found\n"));
        pEnum->Release();
        return E_FAIL;
    }

    pEnum->Release();

    return S_OK;
}

代码是正确的。是的,您可以构建一个这样的图形,并且一次拍摄模式下的样本抓取器接受一个视频帧并指示完成

潜在问题清单包括:

  • 您的视频设备无法传送帧,样本抓取器将永远等待
  • 您请求转换为24位RGB,并且您的相机更可能支持其他视频格式,因此您可能插入了另一个转换器过滤器-视频帧可能会离开相机过滤器,并在转换器中丢失;您对查看所构建的有效图表感兴趣
  • 您构建的图形不正确,示例抓取器实际上连接不正确
  • 在任何情况下,您要做的第一件事就是简单地闯入调试器并检查线程,您可能会当场看到一些错误。然后你要做的第二件事就是找出如何去做。这对于任何DirectShow开发都是必须的

    S_FALSE
    返回是拓扑中具有活动源的图的典型返回。这很好