2011-09-26 10 views
4

매우 비슷한 질문을보고 거의 동일한 코드를보고 나서이 질문을 별도로하기로 결정했습니다. DirectShow가 사용하는 기본 창에 웹캠 비디오 스트림의 비디오 미리보기를 보여주고 싶습니다. 또한 주어진 순간에 비디오 스트림을 "찍을"수있는 기능이 필요합니다.DirectShow : 웹캠 미리보기 및 이미지 캡처

AMCap 샘플 코드뿐만 아니라 MSDN의 DirectShow 예제로 시작하여 미리보기 파트가 있어야한다고 생각하지만 그렇지 않습니다. SampleGrabber를 사용하는 것을 제외하고 비디오 스트림에서 이미지를 가져 오는 예제는 발견되지 않았습니다. SampleGrabber는 더 이상 사용되지 않으므로 사용하지 않으려 고합니다.

아래 코드는 내 코드입니다. EnumerateCameras의 대부분의 코드는 주석 처리되어 있습니다. 이 코드는 다른 창에 연결하기위한 것이 었습니다. 원하지 않는 창입니다. MSDN 문서에서는 VMR_7이 비디오 스트림을 표시 할 자체 창을 만드는 것으로 명시되어 있습니다. 내 응용 프로그램에서 오류가 발생하지 않지만이 창이 나타나지 않습니다.

내 질문은 다음과 같습니다. 내가 뭘 잘못하고 있니? 또는, 내가 뭘하려고하는지에 대한 간단한 예를 알고 있다면, 저를 연결하십시오. 참조 용으로 AMCap은 간단한 예가 아닙니다.

참고 : InitalizeVMR은 창없는 상태에서 실행하기위한 것으로 궁극적 인 목표입니다 (DirectX 게임에 통합). 그러나 지금은 가능한 가장 단순한 모드로 실행하기를 원합니다.

편집 : 카메라 스트림을 미리 보는이 질문의 첫 번째 부분이 해결되었습니다. 지금은 더 이상 사용되지 않는 SampleGrabber 클래스에 대한 대안을 찾고 있으므로 언제든지 사진을 찍어 파일에 저장할 수 있습니다.

편집 : Google에서 거의 한 시간 동안 찾은 후 일반적인 컨센서스는 ISampleGrabber를 사용해야한다는 것 같습니다. 다른 것을 찾으면 알려주세요.

테스트 코드 (MAIN.CPP) :

CWebcam* camera = new CWebcam();  
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);  
MessageBox(NULL, L"text", L"caption", NULL);  
if (SUCCEEDED(hr)) 
{  
camera->Create();  
camera->EnumerateCameras();  
camera->StartCamera(); 
} 
int d; 
cin >> d; 

Webcam.cpp :

#include "Webcam.h" 

CWebcam::CWebcam() { 
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 
    //m_pTexInst = nullptr; 
    //m_pTexRes = nullptr; 
} 

CWebcam::~CWebcam() { 
    CoUninitialize(); 
    m_pDeviceMonikers->Release(); 
    m_pMediaController->Release(); 
} 

BOOL CWebcam::Create() { 
    InitCaptureGraphBuilder(&m_pFilterGraph, &m_pCaptureGraph); 
    hr = m_pFilterGraph->QueryInterface(IID_IMediaControl, (void **)&m_pMediaController); 
    return TRUE; 
} 

void CWebcam::Destroy() { 
} 

void CWebcam::EnumerateCameras() { 
    HRESULT hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &m_pDeviceMonikers); 
    if (SUCCEEDED(hr)) 
    { 
     //DisplayDeviceInformation(m_pDeviceMonikers); 
     //m_pDeviceMonikers->Release(); 

     IMoniker *pMoniker = NULL; 
     if(m_pDeviceMonikers->Next(1, &pMoniker, NULL) == S_OK) 
     { 
      hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_pCameraFilter); 
      if (SUCCEEDED(hr)) 
      { 
       hr = m_pFilterGraph->AddFilter(m_pCameraFilter, L"Capture Filter"); 
      } 
     } 

     // connect the output pin to the video renderer 
     if(SUCCEEDED(hr)) 
     { 
      hr = m_pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, 
       m_pCameraFilter, NULL, NULL); 
     } 
     //InitializeVMR(hwnd, m_pFilterGraph, &m_pVMRControl, 1, FALSE); 
     //get the video window that will be displayed from the filter graph 
     IVideoWindow *pVideoWindow = NULL; 
     hr = m_pFilterGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideoWindow); 
     /*if(hr != NOERROR) 
     { 
      printf("This graph cannot preview properly"); 
     } 
     else 
     { 
      //get the video stream configurations 
      hr = m_pCaptureGraph->FindInterface(&PIN_CATEGORY_CAPTURE, 
       &MEDIATYPE_Video, m_pCameraFilter, 
       IID_IAMStreamConfig, (void **)&m_pVideoStreamConfig); 

      //Find out if this is a DV stream 
      AM_MEDIA_TYPE *pMediaTypeDV; 

      //fake window handle 
      HWND window = NULL; 
      if(m_pVideoStreamConfig && SUCCEEDED(m_pVideoStreamConfig->GetFormat(&pMediaTypeDV))) 
      { 
       if(pMediaTypeDV->formattype == FORMAT_DvInfo) 
       { 
        // in this case we want to set the size of the parent window to that of 
        // current DV resolution. 
        // We get that resolution from the IVideoWindow. 
        IBasicVideo* pBasivVideo; 

        // If we got here, gcap.pVW is not NULL 
        //ASSERT(pVideoWindow != NULL); 
        hr = pVideoWindow->QueryInterface(IID_IBasicVideo, (void**)&pBasivVideo); 

        /*if(SUCCEEDED(hr)) 
        { 
         HRESULT hr1, hr2; 
         long lWidth, lHeight; 

         hr1 = pBasivVideo->get_VideoHeight(&lHeight); 
         hr2 = pBasivVideo->get_VideoWidth(&lWidth); 
         if(SUCCEEDED(hr1) && SUCCEEDED(hr2)) 
         { 
          ResizeWindow(lWidth, abs(lHeight)); 
         } 
        } 
       } 
      } 

      RECT rc; 
      pVideoWindow->put_Owner((OAHWND)window); // We own the window now 
      pVideoWindow->put_WindowStyle(WS_CHILD); // you are now a child 

      GetClientRect(window, &rc); 
      pVideoWindow->SetWindowPosition(0, 0, rc.right, rc.bottom); // be this big 
      pVideoWindow->put_Visible(OATRUE); 
     }*/ 
    } 
} 

BOOL CWebcam::StartCamera() { 
    if(m_bIsStreaming == FALSE) 
    { 
     m_bIsStreaming = TRUE; 
     hr = m_pMediaController->Run(); 
     if(FAILED(hr)) 
     { 
      // stop parts that ran 
      m_pMediaController->Stop(); 
      return FALSE; 
     } 
     return TRUE; 
    } 
    return FALSE; 
} 

void CWebcam::EndCamera() { 
    if(m_bIsStreaming) 
    { 
     hr = m_pMediaController->Stop(); 
     m_bIsStreaming = FALSE; 
     //invalidate client rect as well so that it must redraw 
    } 
} 

BOOL CWebcam::CaptureToTexture() { 
    return TRUE; 
} 

HRESULT CWebcam::InitCaptureGraphBuilder(
    IGraphBuilder **ppGraph, // Receives the pointer. 
    ICaptureGraphBuilder2 **ppBuild // Receives the pointer. 
) 
{ 
    if (!ppGraph || !ppBuild) 
    { 
     return E_POINTER; 
    } 
    IGraphBuilder *pGraph = NULL; 
    ICaptureGraphBuilder2 *pBuild = NULL; 

    // Create the Capture Graph Builder. 
    HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, 
     CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild); 
    if (SUCCEEDED(hr)) 
    { 
     // Create the Filter Graph Manager. 
     hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, 
      IID_IGraphBuilder, (void**)&pGraph); 
     if (SUCCEEDED(hr)) 
     { 
      // Initialize the Capture Graph Builder. 
      pBuild->SetFiltergraph(pGraph); 

      // Return both interface pointers to the caller. 
      *ppBuild = pBuild; 
      *ppGraph = pGraph; // The caller must release both interfaces. 
      return S_OK; 
     } 
     else 
     { 
      pBuild->Release(); 
     } 
    } 
    return hr; // Failed 
} 

HRESULT CWebcam::EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum) 
{ 
    // Create the System Device Enumerator. 
    ICreateDevEnum *pSystemDeviceEnumerator; 
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 
     CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSystemDeviceEnumerator)); 

    if (SUCCEEDED(hr)) 
    { 
     // Create an enumerator for the category. 
     hr = pSystemDeviceEnumerator->CreateClassEnumerator(category, ppEnum, 0); 
     if (hr == S_FALSE) 
     { 
      hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error. 
     } 
     pSystemDeviceEnumerator->Release(); 
    } 
    return hr; 
} 

void CWebcam::DisplayDeviceInformation(IEnumMoniker *pEnum) 
{ 
    IMoniker *pMoniker = NULL; 
    int counter = 0; 

    while (pEnum->Next(1, &pMoniker, NULL) == S_OK) 
    { 
     IPropertyBag *pPropBag; 
     HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag)); 
     if (FAILED(hr)) 
     { 
      pMoniker->Release(); 
      continue; 
     } 

     VARIANT var; 
     VariantInit(&var); 

     // Get description or friendly name. 
     hr = pPropBag->Read(L"Description", &var, 0); 
     if (FAILED(hr)) 
     { 
      hr = pPropBag->Read(L"FriendlyName", &var, 0); 
     } 
     if (SUCCEEDED(hr)) 
     { 
      printf("%d: %S\n", counter, var.bstrVal); 
      VariantClear(&var); 
     } 

     hr = pPropBag->Write(L"FriendlyName", &var); 

     // WaveInID applies only to audio capture devices. 
     hr = pPropBag->Read(L"WaveInID", &var, 0); 
     if (SUCCEEDED(hr)) 
     { 
      printf("%d: WaveIn ID: %d\n", counter, var.lVal); 
      VariantClear(&var); 
     } 

     hr = pPropBag->Read(L"DevicePath", &var, 0); 
     if (SUCCEEDED(hr)) 
     { 
      // The device path is not intended for display. 
      printf("%d: Device path: %S\n", counter, var.bstrVal); 
      VariantClear(&var); 
     } 

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

HRESULT CWebcam::InitializeVMR(
    HWND hwndApp,   // Application window. 
    IGraphBuilder* pFG, // Pointer to the Filter Graph Manager. 
    IVMRWindowlessControl** ppWc, // Receives the interface. 
    DWORD dwNumStreams, // Number of streams to use. 
    BOOL fBlendAppImage // Are we alpha-blending a bitmap? 
    ) 
{ 
    IBaseFilter* pVmr = NULL; 
    IVMRWindowlessControl* pWc = NULL; 
    *ppWc = NULL; 

    // Create the VMR and add it to the filter graph. 
    HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL, 
     CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr); 
    if (FAILED(hr)) 
    { 
     return hr; 
    } 
    hr = pFG->AddFilter(pVmr, L"Video Mixing Renderer"); 
    if (FAILED(hr)) 
    { 
     pVmr->Release(); 
     return hr; 
    } 

    // Set the rendering mode and number of streams. 
    IVMRFilterConfig* pConfig; 
    hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig); 
    if (SUCCEEDED(hr)) 
    { 
     pConfig->SetRenderingMode(VMRMode_Windowless); 

     // Set the VMR-7 to mixing mode if you want more than one video 
     // stream, or you want to mix a static bitmap over the video. 
     // (The VMR-9 defaults to mixing mode with four inputs.) 
     if (dwNumStreams > 1 || fBlendAppImage) 
     { 
      pConfig->SetNumberOfStreams(dwNumStreams); 
     } 
     pConfig->Release(); 

     hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc); 
     if (SUCCEEDED(hr)) 
     { 
      pWc->SetVideoClippingWindow(hwndApp); 
      *ppWc = pWc; // The caller must release this interface. 
     } 
    } 
    pVmr->Release(); 

    // Now the VMR can be connected to other filters. 
    return hr; 
} 

답변

3

창문이 모드는 VMR는 별도의 창을 만들 수 없습니다. 무한 모드의 초기화를 시작 했으므로 IVWRowindowlessControl :: SetVideoPosition 호출로 SetVideoClippingWindow를 따라 윈도우 내에 위치를 제공해야합니다 (VMR Windowless Mode on MSDN 참조). 당신을 위해

또 다른 샘플 코드 : 나는 창문 모드 초기화를 시작하지 않은 http://www.assembla.com/code/roatl-utilities/subversion/nodes/trunk/FullScreenWindowlessVmrSample01/MainDialog.h#ln188

+0

. InitializeVMR()이 주석 처리되었습니다. 필자는 제공된 코드 샘플을 살펴 보았습니다. atlcoll.h로 작업 한 적이 없기 때문에 모든 ATL ... 호출에 약간 혼란스러워했습니다. 이러한 호출을 제거한 후에 코드를 만들 수 있지만 샘플은 DirectShow가 아닌 ​​윈도우를 만드는 응용 프로그램과 비슷합니다. 나는 오히려 DirectShow가 가능하다면 나를 위해 윈도우를 생성하게 할 것이다. – Darkhydro

+0

코드를 다시 한 번 확인했는데 StartCamera이 반환 한 후에 무엇을하고 있습니까? 거기에 메세지 루프가있어, 필터 그래프가 메세지를 송신 할 수 있도록 (듯이)합니다. 이런 식으로하고 있니? StartCamera 다음에 또 다른 MessageBox가 필요할 수도 있습니다. –

+0

창 모드 (호환성) 모드에서 Windows 메시지를 처리해야한다는 것을 알지 못했습니다. 나는 지금 어떤 Windows 메시지도 처리하지 않을 것이다. 필요한 처리가 있습니까? 아니면 간단한 메시지 루프를 설정하고 메시지를 사용하지 않아도됩니까? – Darkhydro