2015-05-01 42 views
1

我一直試圖使用SampleGrabber從網絡攝像頭抓取一幀並將其保存爲位圖,但一直沒有任何運氣。我在MSDN上使用了ICaptureGraphBuilder2以及Sample grabber示例的Directshow視頻捕捉示例。在CaptureGraphBuilder2中使用SampleGrabber的問題

我打算我filter圖表看起來像下面這樣:

網絡攝像頭(源) - >樣品採集卡 - > Null渲染

因爲我不希望看到的預覽,我決定, null渲染器對我來說足夠好。

該計劃是通過搜索特定的VID和PID(webcamCapture :: findWebCam())來找到我的攝像頭,創建我的samplegrabber,創建null渲染器,然後使用pGraphBuilder-> RenderStream()將它們連接在一起。由於我只需要一幀,我使用OneShot方法,然後使用GetCurrentBuffer來檢索幀。

的問題發生在這一行:

pEvent->WaitForCompletion(2000, &evCode); 

的HRESULT返回代碼爲E_ABORT。將超時設置爲INFINITE導致程序凍結,可能意味着過濾器永遠不會停止。來自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; 
} 

回答

0

的代碼是正確的。是的,您可以像這樣構建一個圖形,並且一次採樣模式下的採樣卡接受視頻幀並指示完成。

的潛在問題的清單包括:

  1. 視頻設備不提供框架,樣本採集卡將永遠等待
  2. 您請求轉換爲24位RGB和你的相機是更可能支持其他視頻格式,所以你可能會爲你插入另一個轉換器濾波器 - 視頻幀可能會留下相機濾波器,並在轉換器中丟失;你有興趣在審查你建立
  3. 你建立圖表不正確,你的樣品採集實際上並沒有連接正確

在任何情況下做你的第一件事情是簡單地打破與調試器和檢查線程有效圖形,你可能會在現場看到錯誤。那麼你的第二件事是要找出如何review your filter graphs。這對於任何DirectShow開發都是必須的。

S_FALSE return對於具有拓撲中的活動源的圖是典型的。這可以。