#include "stdafx.h"
#include <windows.h>
#include <dshow.h>
#include <qedit.h>
#include <Ocidl.h>
#include <atlbase.h>
#include <ole2.h>
#define TS_CONST_VALUE    10000000
#define CHK( x ) do{ \
      lRet = x; \
      if( FAILED( lRet)) \
      { \
       DebugMsg(L"Error in line = %d\n", __LINE__); \
       goto exit; \
      } \
     } while( FALSE );
#define RELEASE( x ) { if (x){ x.Release();x=NULL; }}

static struct tagCAM_DATA
{
 BOOL      state;
 CComPtr<ICaptureGraphBuilder2> m_pCaptureGraphBuilder;
 CComPtr<IGraphBuilder>      m_pFilterGraph;
 CComPtr<IMediaControl>  m_pMediaControl;
 CComPtr<IBaseFilter>  m_pVideoCaptureFilter;
 CComPtr<IBaseFilter>  m_pPreviewRender;
 IVideoWindow*    m_piPreviewWin;
 CComPtr<IBaseFilter>  m_pCaptureRender;
 IVideoWindow*    m_piCaptureWin;
}camData;
#pragma comment(lib, "strmiids")
static HRESULT FindCAMVideoDevices(IBaseFilter **pVideoCaptureFilter)
{
    // Create the System Device Enumerator.
 IEnumMoniker *pEnum;
    ICreateDevEnum *pDevEnum;
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
    if (SUCCEEDED(hr))
    {
        // Create an enumerator for the category.
        hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
        if (hr == S_FALSE)
        {
            hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
        }
        pDevEnum->Release();
    }
 if (SUCCEEDED(hr))
 {
  IMoniker *pMoniker = NULL;
  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))
   {
    if(wcscmp(var.bstrVal, L"IRiiiCH RC-V200 USB2.0 Scanner")==0)
    {
     hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)pVideoCaptureFilter);
    }
    //printf("%S\n", var.bstrVal);//Sunny HD WebCam(UVC 1.1)
    VariantClear(&var); 
   }
   hr = pPropBag->Write(L"FriendlyName", &var);
   pPropBag->Release();
   pMoniker->Release();
  }
 }
 if(pEnum)
  pEnum->Release();
 if(*pVideoCaptureFilter == NULL)
  hr = E_FAIL;
    return hr;
}
BOOL CAMInit(HWND hPreviewWnd, HWND hCaptureWnd)
{
 HRESULT lRet = S_OK;
 RECT grc;
 memset(&camData, 0, sizeof(camData));
 CoInitialize( NULL );
 CHK(CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&camData.m_pCaptureGraphBuilder));
    CHK( CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&camData.m_pFilterGraph));
 CHK( camData.m_pCaptureGraphBuilder->SetFiltergraph( camData.m_pFilterGraph ));
 CHK(FindCAMVideoDevices(&camData.m_pVideoCaptureFilter));
 camData.m_pFilterGraph->AddFilter(camData.m_pVideoCaptureFilter, L"Capture Filter");
 
 CHK(camData.m_pPreviewRender.CoCreateInstance (CLSID_VideoRendererDefault));
 camData.m_pFilterGraph->AddFilter(camData.m_pPreviewRender, L"Preview Render Filter");
 CHK(camData.m_pCaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,camData.m_pVideoCaptureFilter, NULL,camData.m_pPreviewRender));
 
 CHK(camData.m_pFilterGraph->QueryInterface( IID_IVideoWindow, (void**)&camData.m_piPreviewWin));
 camData.m_piPreviewWin->put_Owner((OAHWND)hPreviewWnd);
 camData.m_piPreviewWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
 GetClientRect(hPreviewWnd, &grc);
 camData.m_piPreviewWin->SetWindowPosition(0, 0, grc.right, grc.bottom);
 CHK(camData.m_pCaptureRender.CoCreateInstance(CLSID_SampleGrabber));
 camData.m_pFilterGraph->AddFilter(camData.m_pCaptureRender, L"Capture render Filter");
 CHK(camData.m_pCaptureGraphBuilder->RenderStream(&PIN_CATEGORY_STILL, &MEDIATYPE_Video,camData.m_pVideoCaptureFilter, NULL, camData.m_pCaptureRender));
 /*CHK(camData.m_pFilterGraph->QueryInterface( IID_IVideoWindow, (void**)&camData.m_piCaptureWin));
 camData.m_piCaptureWin->put_Owner((OAHWND)hCaptureWnd);
 camData.m_piCaptureWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
 GetClientRect(hCaptureWnd, &grc);
 camData.m_piCaptureWin->SetWindowPosition(0, 0, grc.right, grc.bottom);
*/
 CHK(camData.m_pFilterGraph->QueryInterface( IID_IMediaControl, (void**)&camData.m_pMediaControl ));
 camData.state = FALSE;
 if(camData.m_pMediaControl)
 {
  camData.m_pMediaControl->Run();
  camData.state = TRUE;
 }
 return TRUE;
exit:
 CAMUninit();
 return FALSE; 
}
BOOL CAMRun()
{
 if(camData.state)
 {
  return TRUE;
 }
 if(camData.m_pMediaControl)
 {
  camData.m_pMediaControl->Run();
  camData.state = TRUE;
 }
 else
 {
  return FALSE;
 }
 return TRUE;
}
BOOL CAMStop()
{
 if(!camData.state)
 {
  return TRUE;
 }
 if(camData.m_pMediaControl)
 {
  camData.m_pMediaControl->Stop();
  camData.state = FALSE;
 }
 else
 {
  return FALSE;
 }
 return TRUE;
}
void WriteData(char* pBuffer, int nLen)
{
#if 1 
FILE *file = fopen("2048X1536.yuv", "wb");
if (file)
{
fwrite(pBuffer, 1, nLen, file);
fclose(file);
}
#endif
}
BOOL  CAMCapturePhoto()
{
 HRESULT lRet = S_OK;
 IAMVideoControl*   pAMVidControl = NULL;
 IPin*      pPhotoPin = NULL;
 ISampleGrabber  *pGrab = NULL;
 IMediaEvent     *pEvent = NULL;
 //long evCode;
 if(!camData.state)
 {
  return TRUE;
 }
 CHK(camData.m_pCaptureRender->QueryInterface(IID_ISampleGrabber, (void **)&pGrab))
 pGrab->SetBufferSamples(TRUE);
 pGrab->SetOneShot(TRUE);
 CHK( camData.m_pCaptureGraphBuilder->FindPin( camData.m_pVideoCaptureFilter, PINDIR_OUTPUT, &PIN_CATEGORY_STILL, 0, FALSE, 0, &pPhotoPin));
 CHK( camData.m_pVideoCaptureFilter->QueryInterface(IID_IAMVideoControl, (void**)&pAMVidControl));
 CHK(pAMVidControl->SetMode(pPhotoPin, VideoControlFlag_Trigger));
 //lRet = pEvent->WaitForCompletion(INFINITE, &evCode);
 Sleep(2000);
 AM_MEDIA_TYPE MediaType;
 pGrab->GetConnectedMediaType(&MediaType); 
 VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)MediaType.pbFormat;
 long nBufferSize = pVideoHeader->bmiHeader.biWidth*pVideoHeader->bmiHeader.biHeight*pVideoHeader->bmiHeader.biBitCount/8;
 void *pBuffer = malloc(nBufferSize);
 if(pBuffer)
 {
  pGrab->GetCurrentBuffer(&nBufferSize, (long *)pBuffer);
  WriteData((char*)pBuffer, nBufferSize);
  free(pBuffer);
 } 
exit:
 if(pAMVidControl)
  pAMVidControl->Release();
 if(pPhotoPin)
  pPhotoPin->Release();
 if(pGrab)
  pGrab->Release();
 if(lRet == S_OK)
  return TRUE;
 return FALSE;
}
void CAMUninit()
{
 CAMStop();
 if(camData.m_pMediaControl)
 {
  camData.m_pMediaControl.Release();
 }
 if(camData.m_piPreviewWin)
 {
  camData.m_piPreviewWin->put_Owner((OAHWND)NULL);
  camData.m_piPreviewWin->Release();
  camData.m_piPreviewWin = NULL;
 }
 if(camData.m_piCaptureWin)
 {
  camData.m_piCaptureWin->put_Owner((OAHWND)NULL);
  camData.m_piCaptureWin->Release();
  camData.m_piCaptureWin = NULL;
 }
 RELEASE(camData.m_pPreviewRender);
 RELEASE(camData.m_pCaptureRender);
 if(camData.m_pVideoCaptureFilter)
 {
  camData.m_pVideoCaptureFilter.Release();
 }
 if(camData.m_pFilterGraph)
 {
  camData.m_pFilterGraph.Release();
 }
 if(camData.m_pCaptureGraphBuilder)
 {
  camData.m_pCaptureGraphBuilder.Release();
 }
 memset(&camData, 0, sizeof(camData));
 CoUninitialize();
}