// CaptureVideo.h: interface for the CCaptureVideo class.
//

/**///////////////////////////////////////////////////////////////////////

#if !defined(AFX_CAPTUREVIDEO_H__973C8C7A_47A3_45B6_9B28_0A4A08003540__INCLUDED_)
#define AFX_CAPTUREVIDEO_H__973C8C7A_47A3_45B6_9B28_0A4A08003540__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <atlbase.h>
#include <windows.h>
#include <dshow.h>
#ifndef SAFE_RELEASE
#define SAFE_RELEASE( x ) \
if ( NULL != x ) \


{ \
    x->Release( ); \
    x = NULL; \
}
#endif
class CSampleGrabberCB;

class CCaptureVideo  : public CWnd


{
    friend class CSampleGrabberCB;
public:
    void GrabOneFrame(BOOL bGrab);
    void ImageProcess(BOOL bImage);
    HRESULT Init(int iDeviceID,HWND hWnd);
    CCaptureVideo();
    virtual ~CCaptureVideo();

    BOOL bIsVideoOpen;
    void SwitchImageProcess(BOOL bprocess);
       void ImageProcessing(unsigned char*m_pDibBits,int m_height, int m_width);

private:
    HWND m_hWnd;
    IGraphBuilder *m_pGB;
    ICaptureGraphBuilder2* m_pCapture;
    IBaseFilter* m_pBF;
    IMediaControl* m_pMC;
    IVideoWindow* m_pVW;
    CComPtr <ISampleGrabber> m_pGrabber;

protected:
    void FreeMediaType(AM_MEDIA_TYPE& mt);
    bool BindFilter(int deviceId, IBaseFilter **pFilter);
    HRESULT InitCaptureGraphBuilder();
};

#endif // !defined(AFX_CAPTUREVIDEO_H__973C8C7A_47A3_45B6_9B28_0A4A08003540__INCLUDED_)

 
// CaptureVideo.cpp: implementation of the CCaptureVideo class.
//

/**///////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CaptureVideo.h"
#include "ImageProcess.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/**//////////////////////////声明全局变量//////////////////////////////////////
BOOL bIsSavePic = FALSE;
BOOL bIsImageProcess = FALSE;

/**///////////////////////////////////////////////////////////////////////
class CSampleGrabberCB:public ISampleGrabberCB 


{
public:
    long lWidth;
    long lHeight;
    CCaptureVideo dlg;


    STDMETHODIMP_(ULONG) AddRef() 
{ return 2; }

    STDMETHODIMP_(ULONG) Release() 
{ return 1; }
    STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)

    
{
        if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown )

        
{ 
            *ppv = (void *) static_cast<ISampleGrabberCB*> ( this );
            return NOERROR;
        } 
        
        return E_NOINTERFACE;
    }
    
    STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample )

    
{
        return 0;
    }
//回调函数
    STDMETHODIMP BufferCB( double dblSampleTime, unsigned char* pBuffer, long lBufferSize )

    
{
        if (!pBuffer)     return E_POINTER;
        
        if (bIsImageProcess) 

        
{//如果条件为真则进行数字图像处理
            dlg.ImageProcessing(pBuffer, lHeight, lWidth);
        }
        
        return 0;
    }
};
CSampleGrabberCB mCB;


/**///////////////////////////////////////////////////////////////////////
// Construction/Destruction

/**///////////////////////////////////////////////////////////////////////
CCaptureVideo::CCaptureVideo() 


{
    //COM Library Intialization
    if(FAILED(CoInitialize(NULL))) 

    
{
        AfxMessageBox("CoInitialize Failed!\r\n"); 
        return;
    }
    m_hWnd = NULL;
    m_pVW = NULL;
    m_pMC = NULL;
    m_pGB = NULL;
    m_pCapture = NULL; 
    bIsVideoOpen = FALSE;
}

CCaptureVideo::~CCaptureVideo()


{
    if (bIsVideoOpen) 

    
{    
        // Stop media playback
        if(m_pMC)

        
{
            m_pMC->Stop();
        }
        
        if(m_pVW)

        
{
            m_pVW->put_Visible(OAFALSE);
            m_pVW->put_Owner(NULL);
        }
        
        SAFE_RELEASE(m_pCapture);
        SAFE_RELEASE(m_pMC);
        SAFE_RELEASE(m_pGB);
        SAFE_RELEASE(m_pBF);
        CoUninitialize( );
    }
}


/**////////////////////////////////////////////////////////////////////////////
////
////                        DirectShow核心代码
////
///////////////////////////////////////////////////////////////////////////
HRESULT CCaptureVideo::Init(int iDeviceID, HWND hWnd)


{
    HRESULT hr;
    hr = InitCaptureGraphBuilder();
    if (FAILED(hr))

    
{
        AfxMessageBox("Failed to get video interfaces!");
        return hr;
    }

    // Bind Device Filter. We know the device because the id was passed in
    if(!BindFilter(iDeviceID, &m_pBF))

    
{
        AfxMessageBox("未找到USB摄像头!\n请检查设备后重试!");
        PostQuitMessage(0);
        return S_FALSE;
    }
    
    hr = m_pGB->AddFilter(m_pBF, L"Capture Filter");
    // hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, // m_pBF, NULL, NULL);
    // create a sample grabber
    hr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );
    if( !m_pGrabber )

    
{
        AfxMessageBox("Fail to create SampleGrabber, maybe qedit.dll is not registered?");
        return hr;
    }

    CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabBase(m_pGrabber);
    
    //**********设置视频格式**********//
    AM_MEDIA_TYPE mt; 
    ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
    mt.majortype = MEDIATYPE_Video;
    mt.subtype = MEDIASUBTYPE_RGB24;  //抓取24位位图
    hr = m_pGrabber->SetMediaType(&mt);

    if( FAILED( hr ) )

    
{
        AfxMessageBox("Fail to set media type!");
        return hr;
    }
    
    hr = m_pGB->AddFilter( pGrabBase, L"Grabber" );
    if( FAILED( hr ) )

    
{
        AfxMessageBox("Fail to put sample grabber in graph");
        return hr;
    }

    // try to render preview/capture pin
    hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
    if( FAILED( hr ) )
        hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);

    if( FAILED( hr ) )

    
{
        AfxMessageBox("Can't build the graph");
        return hr;
    }
    
    hr = m_pGrabber->GetConnectedMediaType( &mt );
    
    if ( FAILED( hr) )

    
{
        AfxMessageBox("Failt to read the connected media type");
        return hr;
    }

    VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
    mCB.lWidth = vih->bmiHeader.biWidth;
    mCB.lHeight = vih->bmiHeader.biHeight;
    FreeMediaType(mt);
    hr = m_pGrabber->SetBufferSamples( FALSE );
    hr = m_pGrabber->SetOneShot( FALSE );
    hr = m_pGrabber->SetCallback( &mCB, 1 );
    
    //*********设置视频捕捉窗口********//
    m_hWnd = hWnd ; //picture控件的句柄
    hr = m_pVW->put_Owner((OAHWND)m_hWnd);
    if (FAILED(hr)) return hr;
    hr = m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
    if (FAILED(hr)) return hr;

    if (m_pVW)

    
{    
        CRect rc;
        ::GetClientRect(m_hWnd,&rc);
        m_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);//让图像充满整个窗口
    } 

    hr = m_pVW->put_Visible(OATRUE);

    //*********开始视频捕捉********//
    hr = m_pMC->Run();
    if(FAILED(hr))

    
{
        AfxMessageBox("Couldn't run the graph!");
        return hr;
    }

    bIsVideoOpen = TRUE;
    return S_OK;
}

HRESULT CCaptureVideo::InitCaptureGraphBuilder()


{
    HRESULT hr;
    // 创建IGraphBuilder接口
    hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB);
    // 创建ICaptureGraphBuilder2接口
    hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **) &m_pCapture);
    if (FAILED(hr)) return hr;
    m_pCapture->SetFiltergraph(m_pGB);
    hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
    if (FAILED(hr)) return hr;
    hr = m_pGB->QueryInterface(IID_IVideoWindow, (LPVOID *)&m_pVW);
    if (FAILED(hr)) return hr;
    return hr;
}

bool CCaptureVideo::BindFilter(int deviceId, IBaseFilter **pFilter)


{
    if (deviceId < 0) return false;

    // enumerate all video capture devices
    CComPtr<ICreateDevEnum> pCreateDevEnum;
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);
    if (hr != NOERROR)

    
{
        return false;
    }

    CComPtr<IEnumMoniker> pEm;
    hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);
    if (hr != NOERROR) 

    
{
        return false;
    }

    pEm->Reset();
    ULONG cFetched;
    IMoniker *pM;
    int index = 0;
    while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK, index <= deviceId)

    
{
        IPropertyBag *pBag;
        hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
        if(SUCCEEDED(hr)) 

        
{
            VARIANT var;
            var.vt = VT_BSTR;
            hr = pBag->Read(L"FriendlyName", &var, NULL);
            if (hr == NOERROR) 

            
{
                if (index == deviceId)

                
{
                    pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
                }

                SysFreeString(var.bstrVal);
            }
            
            pBag->Release();
        }
        
        pM->Release();
        index++;
    }
    
    return true;
}

void CCaptureVideo::FreeMediaType(AM_MEDIA_TYPE& mt)


{
    if (mt.cbFormat != 0) 

    
{
        CoTaskMemFree((PVOID)mt.pbFormat);
        // Strictly unnecessary but tidier
        mt.cbFormat = 0;
        mt.pbFormat = NULL;
    }
    
    if (mt.pUnk != NULL) 

    
{
        mt.pUnk->Release();
        mt.pUnk = NULL;
    }
} 


/**///////////////////////////////////////////////////////////////////////////////////////////

void CCaptureVideo::SwitchImageProcess(BOOL bprocess)


{
    bIsImageProcess = bprocess;
}


/**///////////////////////////////////////////////////////////////////////////////
/////////
/////////                         数字图像处理       
////////
///////////////////////////////////////////////////////////////////////////////
void CCaptureVideo::ImageProcessing(unsigned char*m_pDibBits, int m_height, int m_width)


{    
    CImageProcess::ColorToGray(m_pDibBits,m_height, m_width); //彩色转灰度
    CImageProcess::ConvertGrayToWhiteBlack(m_pDibBits, m_height, m_width, 120); //二值化
}

 
主程序


#ifdef _DEBUG
#pragma comment(lib,"strmbasd.lib")
#else
#pragma comment(lib,"STRMBASE.lib")
#endif
#pragma comment(lib,"strmiids.lib")
#pragma comment(lib,"quartz.lib")

void CUSBShowDlg::OnBUTTONOpenVideo() //打开摄像头


{
    HWND hWnd = m_StaticShow.GetSafeHwnd(); 
    HRESULT hr = m_cap.Init(0,hWnd); //DirectShow初始化
}

void CUSBShowDlg::OnBUTTONImageProcess() //启动数字图像处理开关


{
    m_cap.SwitchImageProcess(TRUE);
}
