title: DirectShow: webcam preview and image capture
body: <p>After looking at a very similar question and seeing almost identical code, I've decided to ask this question separately. I want to show a video preview of the webcam's video stream to the default window DirectShow uses, and I also want the ability to "take a picture" of the video stream at any given moment. </p>
  
  <p>I started with the DirectShow examples on MSDN, as well as the AMCap sample code, and have something I believe should should the preview part, but does not. I've found no examples of grabbing an image from the video stream except using SampleGrabber, which is deprecated and therefore I am trying not to use it. </p>
  
  <p>Below is my code, line for line. Note that most of the code in EnumerateCameras is commented out. That code would've been for attaching to another window, which I don't want to do. In the MSDN documentation, it explicitly states that the VMR_7 creates its own window to display the video stream. I get no errors in my app, but this window never appears. </p>
  
  <p>My question then is this: What am I doing wrong? Alternatively, if you know of a simple example of what I am trying to do, link me to it. AMCap is not a simple example, for reference.</p>
  
  <p>NOTE: InitalizeVMR is for running in windowless state, which is my ultimate goal (integrating into a DirectX game). For now, however, i just want it to run in the simplest mode possible.</p>
  
  <p>EDIT: The first portion of this question, that is previewing the camera stream, is solved. I am now just looking for an alternative to the deprecated SampleGrabber class so I can snap a photo at any moment and save it to a file. </p>
  
  <p>EDIT: After looking for almost an hour on google, the general concensus seems to be that you HAVE to use ISampleGrabber. Please let me know if you find anything different. </p>
  
  <p>Testing code (main.cpp): </p>
  
  <pre><code>CWebcam* camera = new CWebcam();    
  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);    
  MessageBox(NULL, L"text", L"caption", NULL);    
  if (SUCCEEDED(hr))
  {       
  camera-&gt;Create();       
  camera-&gt;EnumerateCameras();     
  camera-&gt;StartCamera();  
  }   
  int d;  
  cin &gt;&gt; d;
  </code></pre>
  
  <p>Webcam.cpp: </p>
  
  <pre><code>#include "Webcam.h"
  
  CWebcam::CWebcam() {
      HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
      //m_pTexInst = nullptr;
      //m_pTexRes = nullptr;
  }
  
  CWebcam::~CWebcam() {
      CoUninitialize();
      m_pDeviceMonikers-&gt;Release();
      m_pMediaController-&gt;Release();
  }
  
  BOOL CWebcam::Create() {
      InitCaptureGraphBuilder(&amp;m_pFilterGraph, &amp;m_pCaptureGraph);
      hr = m_pFilterGraph-&gt;QueryInterface(IID_IMediaControl, (void **)&amp;m_pMediaController);
      return TRUE;
  }
  
  void CWebcam::Destroy() {
  }
  
  void CWebcam::EnumerateCameras() {  
      HRESULT hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &amp;m_pDeviceMonikers);
      if (SUCCEEDED(hr))
      {
          //DisplayDeviceInformation(m_pDeviceMonikers);
          //m_pDeviceMonikers-&gt;Release();
  
          IMoniker *pMoniker = NULL;
          if(m_pDeviceMonikers-&gt;Next(1, &amp;pMoniker, NULL) == S_OK)
          {
              hr = pMoniker-&gt;BindToObject(0, 0, IID_IBaseFilter, (void**)&amp;m_pCameraFilter);
              if (SUCCEEDED(hr))
              {
                  hr = m_pFilterGraph-&gt;AddFilter(m_pCameraFilter, L"Capture Filter");
              }
          }
  
          // connect the output pin to the video renderer
          if(SUCCEEDED(hr))
          {
              hr = m_pCaptureGraph-&gt;RenderStream(&amp;PIN_CATEGORY_PREVIEW, &amp;MEDIATYPE_Video, 
                  m_pCameraFilter, NULL, NULL);
          }
          //InitializeVMR(hwnd, m_pFilterGraph, &amp;m_pVMRControl, 1, FALSE);
          //get the video window that will be displayed from the filter graph
          IVideoWindow *pVideoWindow = NULL;
          hr = m_pFilterGraph-&gt;QueryInterface(IID_IVideoWindow, (void **)&amp;pVideoWindow);
          /*if(hr != NOERROR)
          {
              printf("This graph cannot preview properly");
          }
          else
          {
              //get the video stream configurations
              hr = m_pCaptureGraph-&gt;FindInterface(&amp;PIN_CATEGORY_CAPTURE,
                  &amp;MEDIATYPE_Video, m_pCameraFilter,
                  IID_IAMStreamConfig, (void **)&amp;m_pVideoStreamConfig);
  
              //Find out if this is a DV stream
              AM_MEDIA_TYPE *pMediaTypeDV;
  
              //fake window handle
              HWND window = NULL;
              if(m_pVideoStreamConfig &amp;&amp; SUCCEEDED(m_pVideoStreamConfig-&gt;GetFormat(&amp;pMediaTypeDV)))
              {
                  if(pMediaTypeDV-&gt;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-&gt;QueryInterface(IID_IBasicVideo, (void**)&amp;pBasivVideo);
  
                      /*if(SUCCEEDED(hr))
                      {
                          HRESULT hr1, hr2;
                          long lWidth, lHeight;
  
                          hr1 = pBasivVideo-&gt;get_VideoHeight(&amp;lHeight);
                          hr2 = pBasivVideo-&gt;get_VideoWidth(&amp;lWidth);
                          if(SUCCEEDED(hr1) &amp;&amp; SUCCEEDED(hr2))
                          {
                              ResizeWindow(lWidth, abs(lHeight));
                          }
                      }
                  }
              }
  
              RECT rc;
              pVideoWindow-&gt;put_Owner((OAHWND)window);    // We own the window now
              pVideoWindow-&gt;put_WindowStyle(WS_CHILD);    // you are now a child
  
              GetClientRect(window, &amp;rc);
              pVideoWindow-&gt;SetWindowPosition(0, 0, rc.right, rc.bottom); // be this big
              pVideoWindow-&gt;put_Visible(OATRUE);
          }*/
      }   
  }
  
  BOOL CWebcam::StartCamera() {
      if(m_bIsStreaming == FALSE)
      {
          m_bIsStreaming = TRUE;
          hr = m_pMediaController-&gt;Run();
          if(FAILED(hr))
          {
              // stop parts that ran
              m_pMediaController-&gt;Stop();
              return FALSE;
          }
          return TRUE;
      }
      return FALSE;
  }
  
  void CWebcam::EndCamera() {
      if(m_bIsStreaming)
      {
          hr = m_pMediaController-&gt;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**)&amp;pBuild );
      if (SUCCEEDED(hr))
      {
          // Create the Filter Graph Manager.
          hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
              IID_IGraphBuilder, (void**)&amp;pGraph);
          if (SUCCEEDED(hr))
          {
              // Initialize the Capture Graph Builder.
              pBuild-&gt;SetFiltergraph(pGraph);
  
              // Return both interface pointers to the caller.
              *ppBuild = pBuild;
              *ppGraph = pGraph; // The caller must release both interfaces.
              return S_OK;
          }
          else
          {
              pBuild-&gt;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(&amp;pSystemDeviceEnumerator));
  
      if (SUCCEEDED(hr))
      {
          // Create an enumerator for the category.
          hr = pSystemDeviceEnumerator-&gt;CreateClassEnumerator(category, ppEnum, 0);
          if (hr == S_FALSE)
          {
              hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
          }
          pSystemDeviceEnumerator-&gt;Release();
      }
      return hr;
  }
  
  void CWebcam::DisplayDeviceInformation(IEnumMoniker *pEnum)
  {
      IMoniker *pMoniker = NULL;
      int counter = 0;
  
      while (pEnum-&gt;Next(1, &amp;pMoniker, NULL) == S_OK)
      {
          IPropertyBag *pPropBag;
          HRESULT hr = pMoniker-&gt;BindToStorage(0, 0, IID_PPV_ARGS(&amp;pPropBag));
          if (FAILED(hr))
          {
              pMoniker-&gt;Release();
              continue;  
          } 
  
          VARIANT var;
          VariantInit(&amp;var);
  
          // Get description or friendly name.
          hr = pPropBag-&gt;Read(L"Description", &amp;var, 0);
          if (FAILED(hr))
          {
              hr = pPropBag-&gt;Read(L"FriendlyName", &amp;var, 0);
          }
          if (SUCCEEDED(hr))
          {
              printf("%d: %S\n", counter, var.bstrVal);
              VariantClear(&amp;var); 
          }
  
          hr = pPropBag-&gt;Write(L"FriendlyName", &amp;var);
  
          // WaveInID applies only to audio capture devices.
          hr = pPropBag-&gt;Read(L"WaveInID", &amp;var, 0);
          if (SUCCEEDED(hr))
          {
              printf("%d: WaveIn ID: %d\n", counter, var.lVal);
              VariantClear(&amp;var); 
          }
  
          hr = pPropBag-&gt;Read(L"DevicePath", &amp;var, 0);
          if (SUCCEEDED(hr))
          {
              // The device path is not intended for display.
              printf("%d: Device path: %S\n", counter, var.bstrVal);
              VariantClear(&amp;var); 
          }
  
          pPropBag-&gt;Release();
          pMoniker-&gt;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**)&amp;pVmr);
      if (FAILED(hr))
      {
          return hr;
      }
      hr = pFG-&gt;AddFilter(pVmr, L"Video Mixing Renderer");
      if (FAILED(hr))
      {
          pVmr-&gt;Release();
          return hr;
      }
  
      // Set the rendering mode and number of streams.  
      IVMRFilterConfig* pConfig;
      hr = pVmr-&gt;QueryInterface(IID_IVMRFilterConfig, (void**)&amp;pConfig);
      if (SUCCEEDED(hr)) 
      {
          pConfig-&gt;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 &gt; 1 || fBlendAppImage) 
          {
              pConfig-&gt;SetNumberOfStreams(dwNumStreams);
          }
          pConfig-&gt;Release();
  
          hr = pVmr-&gt;QueryInterface(IID_IVMRWindowlessControl, (void**)&amp;pWc);
          if (SUCCEEDED(hr)) 
          {
              pWc-&gt;SetVideoClippingWindow(hwndApp);
              *ppWc = pWc;  // The caller must release this interface.
          }
      }
      pVmr-&gt;Release();
  
      // Now the VMR can be connected to other filters.
      return hr;
  }
  </code></pre>