2016-10-05 12 views
0

私はDirectShowプログラミングの初心者です。ビデオキャプチャデバイスからフレームを頻繁に(つまり100ミリ秒ごとに)取得するために、サンプルグラバーアプリケーションを作成しようとしています。DirectShowカメラストリームドライバ

私のソースコードは、Windows SDKサンプルで提供されているSampleGrabberアプリケーションに基づいています。

一般に、ドライバは自分のPCのウェブカメラを使ってうまく動作します。しかし、私はAsus T100タブレットで使用する際にいくつか問題があります。この場合、カメラの解像度を設定した後、ConnectFilters機能を使用しようとしているときに「libtbdエラーデータが正しくタグ付けされていません」というエラーが表示されます。私がカメラに設定しようとしている解像度は1280x720で、私はそのデバイスがそれをサポートできることを知っています。

私はキャプチャ機能に関する私のコードの一部を添付しています下:

ICreateDevEnum *pSysDevEnum = 0; 
IEnumMoniker *pEnumCams = 0; 
IMoniker *pMon = 0; 
IBaseFilter *CameraF = 0; 

IGraphBuilder *pGraph = NULL; 
IMediaControl *pControl = NULL; 
IMediaEventEx *pEvent = NULL; 
IBaseFilter *pGrabberF = NULL; 
ISampleGrabber *pSGrabber = NULL; 
IBaseFilter *pSourceF = NULL; 
IEnumPins *pEnum = NULL; 
IPin *pPin = NULL; 
IBaseFilter *pNullF = NULL; 

BYTE *pBuffer = NULL; 
HRESULT hr; 
AM_MEDIA_TYPE mt; 
int count = 0; 

printf("Statting with capturing\n"); 
//Device list 
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, 
    IID_ICreateDevEnum, (void **)&pSysDevEnum); 
if (FAILED(hr)) 
    return false; 

// Obtain a class enumerator for the video compressor category. 
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, 
    &pEnumCams, 0); 
if (hr != S_OK) 
    return false; 

// Enumerate the monikers. to desired device (0,1,2,...) 
for (int i = 0; i <= cur_cam; ++i) 
{ 
    hr = pEnumCams->Next(1, &pMon, NULL); 
    if (hr != S_OK) 
     return false; 
} 
//Get BaseFilter of chosen camera 
hr = pMon->BindToObject(0, 0, IID_IBaseFilter, (void**)&CameraF); 
if (hr != S_OK) 
    return false; 

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

//Query for the IMediaControl and IMediaEventEx interfaces 
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl)); 
if (FAILED(hr)) 
    return false; 

hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent)); 
if (FAILED(hr)) 
    return false; 

// Add web camera to graph as source filter (because first?) 
hr = pGraph->AddFilter(CameraF, L"Capture Source"); 
if (hr != S_OK) 
    return false; 

// Create an instance of the Sample Grabber Filter 
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, 
    IID_PPV_ARGS(&pGrabberF)); 
if (FAILED(hr)) 
    return false; 

// Add it to the filter graph. 
hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber"); 
if (FAILED(hr)) 
    return false; 

hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pSGrabber)); 
if (FAILED(hr)) 
    return false; 

//Set the Media Type 
ZeroMemory(&mt, sizeof(mt)); 
mt.majortype = MEDIATYPE_Video; 
mt.subtype = MEDIASUBTYPE_RGB24 ; 

hr = pSGrabber->SetMediaType(&mt); 
if (FAILED(hr)) 
    return false; 

//Building graph. Connecting Source (CameraF) and Sample Grabber 
hr = CameraF->EnumPins(&pEnum); 
if (FAILED(hr)) 
    return false; 

while (S_OK == pEnum->Next(1, &pPin, NULL)) 
{ 
    hr = SetResolution(width_, height_, pPin); 

    if (FAILED(hr)) 
     std::cout << "Failed to set resolution" << std::endl; 

    hr = ConnectFilters(pGraph, pPin, pGrabberF); 

    if (SUCCEEDED(hr)) 
    { 
     std::cout << "Success to Connect Filter Graphs" << std::endl; 
     break; 
    } 
    else{ 
     std::cout << "Failed to Connect Filter Graphs" << std::endl; 
    } 
} 

if (FAILED(hr)){ 
    std::cout << "Failed A" << std::endl; 
    return false; 
} 


SafeRelease(pPin); 

//The following code connects the Sample Grabber to the Null Renderer filter: 
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pNullF)); 
if (FAILED(hr)) 
    return false; 

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

//ConnectFilters SamplerGrabber and Null Filter 
hr = ConnectFilters(pGraph, pGrabberF, pNullF); 
if (FAILED(hr)) 
    return false; 

hr = pSGrabber->SetBufferSamples(TRUE); 
if (FAILED(hr)) 
    return false; 

hr = pSGrabber->SetOneShot(TRUE);//Halt after sample received 
if (FAILED(hr)) 
    return false; 

hr = pControl->Run();//Run filter graph 
if (FAILED(hr)) 
    return false; 

printf("Wait for a seconds to let cam sensor adopt to light\n"); 
Sleep(3000);//Wait 3 seconds 
printf("OK\n"); 

//char filename[50]; 
printf("Go for the loop"); 

for (;;){ 

    long evCode; 
    while (1) 
    { 
     hr = pEvent->WaitForCompletion(INFINITE, &evCode);//Wait for frame 
     if (evCode == EC_COMPLETE || evCode == EC_SYSTEMBASE) 
      break; 
     printf("Not complete. event: %d\n", evCode); 
     pControl->Pause();//pause the Graph 
     pSGrabber->SetOneShot(TRUE);//Set to halt after first frame 
     hr = pControl->Run();//resume filter graph 
     if (FAILED(hr)) 
      return false; 
     Sleep(1000);//wait for a second 
    } 
    printf("out of while loop"); 
    //if (hr != S_OK) 
    // return false; 
    Sleep(100); 
    //there frame got. Graph still running, but Sample Grabber halted 

    // Find the required buffer size. 
    long cbBufSize; 
    hr = pSGrabber->GetCurrentBuffer(&cbBufSize, NULL); 
    if (FAILED(hr)) 
     return false; 

    pBuffer = (BYTE*)CoTaskMemAlloc(cbBufSize); 
    if (!pBuffer) 
    { 
     hr = E_OUTOFMEMORY; 
     return false; 
    } 

    hr = pSGrabber->GetCurrentBuffer(&cbBufSize, (long*)pBuffer); 
    if (FAILED(hr)) 
     return false; 


    hr = pSGrabber->GetConnectedMediaType(&mt); 
    if (FAILED(hr)) 
     return false; 


    // Examine the format block. 
    if ((mt.formattype == FORMAT_VideoInfo) && 
     (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) && (mt.pbFormat != NULL)) 
    { 
     VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat; 
     //sprintf_s(filename, sizeof(filename), "photo%d.bmp",++count); 
     time_t t1 = time(NULL); 
     SYSTEMTIME st; 
     GetSystemTime(&st); 

     printf("Save frame to file: %s - %02ld,%02ld.%03ld seconds\n", FileName, st.wMinute,st.wSecond, st.wMilliseconds); 
     hr = WriteBitmap(FileName, &pVih->bmiHeader, mt.cbFormat - SIZE_PREHEADER,pBuffer, cbBufSize); 
    } 
    else 
    { 
     // Invalid format. 
     hr = VFW_E_INVALIDMEDIATYPE; 
     printf("Invalid frame format\n"); 
    } 

    CoTaskMemFree(pBuffer); 

    if ((GetAsyncKeyState(VK_ESCAPE) & 0x01)) 
     break; 
    else if ((GetAsyncKeyState(VK_SPACE) & 0x01)) 
     CameraProperties(CameraF); 

} 

SafeRelease(pEnum); 
SafeRelease(pNullF); 
SafeRelease(pSourceF); 
SafeRelease(pSGrabber); 
SafeRelease(pGrabberF); 
SafeRelease(pControl); 
SafeRelease(pEvent); 
SafeRelease(pGraph); 

以下は、カメラの解像度を設定する関数です:

// Set the grabbing size 
// First we iterate through the available media types and 
// store the first one that fits the requested size. 
// If we have found one, we set it. 
// In any case we query the size of the current media type 
// to have this information for clients of this class. 

HRESULT hr; 

IAMStreamConfig *pConfig; 
IEnumMediaTypes *pMedia; 
AM_MEDIA_TYPE *pmt = NULL, *pfnt = NULL; 

hr = pPin->EnumMediaTypes(&pMedia); 
if (SUCCEEDED(hr)) 
{ 

    while (pMedia->Next(1, &pmt, 0) == S_OK) 
    { 
     if (pmt->formattype == FORMAT_VideoInfo) 
     { 
      VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)pmt->pbFormat; 
      // printf("Size %i %i\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight); 
      if (vih->bmiHeader.biWidth == width_ && vih->bmiHeader.biHeight == height_) 
      { 
       pfnt = pmt; 
       printf("found mediatype with %i %i\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight); 
       break; 
      } 
      DeleteMediaType(pmt); 
     } 
    } 
    pMedia->Release(); 
} 
hr = pPin->QueryInterface(IID_IAMStreamConfig, (void **)&pConfig); 
if (SUCCEEDED(hr)) 
{ 
    if (pfnt != NULL) 
    { 
     hr = pConfig->SetFormat(pfnt); 
     DeleteMediaType(pfnt); 
    } 
    hr = pConfig->GetFormat(&pfnt); 
    if (SUCCEEDED(hr)) 
    { 

     m_nWidth = ((VIDEOINFOHEADER *)pfnt->pbFormat)->bmiHeader.biWidth; 
     m_nHeight = ((VIDEOINFOHEADER *)pfnt->pbFormat)->bmiHeader.biHeight; 

     DeleteMediaType(pfnt); 
    } 
} 

誰もが前に、この種の問題に直面しました?キャプチャフィルタ設定に間違いはありますか?

いずれのアイデアも非常に役に立ちます。

更新1

私はアプリケーション実行出力のスクリーンショットを追加しています。 Output

UPDATE 2

私はOpenCVの3.1を使用して解像度を設定しようとしましたが、私は正確に同じ問題を抱えていました。タブレットでは、カメラのインテル(R)イメージングシグナルプロセッサ2400ドライバを使用しています。これが問題の場所です。奇妙なのは、AmCapを使用すると、カメラの解像度を設定して問題なくカメラのデバイスを操作できることです。誰か助けてもらえますか? AmCapがカメラとの通信にどのようなインターフェースを使用しているかは誰にも分かりますか?

+0

エラーメッセージはDirectShowに属しません。どのメソッドがそれを与えるのか、それともメッセージボックスですか? Asusソフトウェアの問題とよく似ています。 –

+0

こんにちは、あなたの答えをありがとう。カメラの解像度を設定し、派生したフィルタをグラフに接続しようとしているところでこのエラーが発生します。 'SetResolution(width_、height_、pPin); hr = ConnectFilters(pGraph、pPin、pGrabberF); ' – mike1821

+0

@ mike1821このエラーはどのようにして得られますか?スクリーンショットを表示できますか? – wimh

答えて

0

この問題を解決できました。報告されたlibdbdエラーは解像度の変更に関連していないようです。

問題は、サポートされていないビデオフォーマットをSetFormat()関数に渡して解像度を設定しようとしていたことでした。具体的には、新しい作業SetResolution()関数は次のようになりました。

// Set the grabbing size 
// First we iterate through the available media types and 
// store the first one that fits the requested size. 
// If we have found one, we set it. 
// In any case we query the size of the current media type 
// to have this information for clients of this class. 

HRESULT hr; 

IAMStreamConfig *pConfig=NULL; 
//IEnumMediaTypes *pMedia; 
BYTE *pSCC = NULL; 
AM_MEDIA_TYPE *pmt = NULL, *pfnt = NULL, *mfnt=NULL; 

//hr = pPin->EnumMediaTypes(&pMedia); 
int iCount, iSize; 

hr = pPin->QueryInterface(IID_IAMStreamConfig, (void **)&pConfig); 

hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); 
pSCC = new BYTE[iSize]; 
int i = 0; 
if (SUCCEEDED(hr)) 
{ 
    while (i<=iCount) 
    { 
     pConfig->GetStreamCaps(i++, &pfnt, pSCC); 

     VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)pfnt->pbFormat; 
     printf("Size %i %i\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight); 
     if (vih->bmiHeader.biWidth == width_ && vih->bmiHeader.biHeight == height_) 
     { 
      //pfnt = mfnt; 
      printf("Found mediatype with %i %i - %x\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight, pfnt->formattype); 
      hr = pConfig->SetFormat(pfnt); 
      //break; 
     } 

    } 
} 

//DeleteMediaType(pfnt); 
delete[] pSCC; 
pConfig->Release(); 
return hr; 
関連する問題