首页 > 代码库 > CCapture directshow 视频捕获类

CCapture directshow 视频捕获类

 

[cpp] view plaincopy
 
  1. // Capture.h for class CCapture  
  2.   
  3. #include <dshow.h>  
  4. #include <qedit.h>  
  5. #include <atlbase.h>  
  6. #if !defined(CAPTURE_H_________)  
  7. #define CAPTURE_H_________  
  8.   
  9. // image size: 160*120  176*144   320*240  640*480  1024*1806  
  10. #define IMG_WIDTH 320  
  11. #define IMG_HEIGHT 240  
  12.   
  13. typedef void (*capCallBackFunc)(LPVOID lParam);  
  14. enum DeviceType{DTypeVideo, DTypeAudio};  
  15. class CSampleGrabberCB; // 用于不会帧数据保存图片的接口  
  16. class CCapture  
  17. {  
  18.     friend class CSampleGrabberCB;  
  19. public:  
  20.     // 设置回调函数 用于处理获取的图片帧数据  
  21.     CDialog *m_dlgParent;  
  22.     capCallBackFunc calFunc;  
  23.     void SetCallBKFun(capCallBackFunc f);  
  24.     /////////////////////////////////  
  25.     CCapture();  
  26.     virtual ~CCapture();  
  27.     int EnumDevice(HWND hCmbList, DeviceType deviceType); // 设备枚举  
  28. //  void SaveGraph(TCHAR *wFileName);   // 保存滤波器链表  
  29.     void SetCameraFormat(HWND hwndParent);  // 设置摄像头的视频格式  
  30.     void SetCameraFilter(HWND hwndParent);  // 设置摄像头的图像参数  
  31.     HRESULT CaptureVideo(CString inFileName);   // 捕获保存视频  
  32.     HRESULT CaptureImage(CString inFileName);   // 抓取保存图片  
  33.     HRESULT CaptureImage(); // 抓取图片并显示  
  34.     HRESULT Preview(int iDevVideoID, HWND hVideo, int iDevAudioID = 0, HWND hAudio = NULL); // 采集预览视频  
  35.     HRESULT InitCaptureGraphBuilder();  // 创建滤波器管理器,查询其各种控制接口  
  36.     void StopCapture();  // 停止捕获  
  37.     void FreeMediaType(AM_MEDIA_TYPE &mt);  // 释放对象内存  
  38.   
  39.     void SetOnShot(BOOL bFlag);   // 设置是否捕获帧数据  
  40.     void SetParent(CDialog *pdlg);  
  41. protected:  
  42.     bool BindFilter(int iDeviceID, IBaseFilter **pOutFilter, DeviceType deviceType); // 把指定的设备滤波器捆绑到链表中  
  43.     void ResizeVideoWindow();           // 更改视频显示窗口  
  44.     HRESULT SetupVideoWindow();         // 设置视频显示窗口的特性  
  45.     static UINT ThreadFunDrawText(LPVOID lParam);  
  46. private:  
  47.     HWND m_hWnd;            // 视频显示窗口的句柄  
  48.     IBaseFilter *m_pVideoCap;       // 视频捕获滤波器  
  49.     IBaseFilter *m_pAudioCap;       // 音频捕获滤波器  
  50.     CComPtr<ISampleGrabber> m_pGrabber;       // 抓取图片滤波器  
  51.     IBaseFilter *m_pMux;    // 写文件滤波器  
  52.     ICaptureGraphBuilder2 *m_pCapGB;    // 增强型捕获滤波器链表管理  
  53.     IGraphBuilder *m_pGB;   // 滤波链表管理器  
  54.     IVideoWindow *m_pVW;    // 视频显示窗口接口  
  55.     IMediaControl *m_pMC;   // 媒体控制接口  
  56.     static bool m_bRecording;       // 录制视频标志  
  57.   
  58.     IBaseFilter *m_pXviDCodec;   //mpeg4 滤波器  
  59. };  
  60.   
  61.   
  62. #endif  


 

[cpp] view plaincopy
 
    1. /// Capture.cpp for class CCapture implement  
    2. //  
    3. ///  
    4. ////////////////////////////////////////  
    5.   
    6. #include "StdAfx.h"  
    7. #include "Capture.h"  
    8. #include <atlconv.h>  
    9. #include "VideoChatDlg.h"  
    10. #include "yuv2bmp.h"  
    11.   
    12. #ifndef srelease  
    13. #define srelease(x) if (NULL != x)\  
    14. {\  
    15.     x->Release();\  
    16.     x = NULL;\  
    17. }  
    18. #endif  
    19.   
    20. #ifndef MAX_PATH  
    21. #define  MAX_PATH 1024  
    22. #endif  
    23. BOOL bOneShot = FALSE; // 全局变量  
    24. capCallBackFunc fun;  
    25.   
    26. class CSampleGrabberCB : public ISampleGrabberCB  
    27. {  
    28. public:  
    29.     long lWidth;  
    30.     long lHeight;  
    31.     CCapture *pCap;  
    32.     TCHAR m_szFileName[MAX_PATH]; // 位图文件名称  
    33.     CSampleGrabberCB(){  
    34.         strcpy(m_szFileName, ".\\sample.bmp");  
    35.     }  
    36.     STDMETHODIMP_(ULONG) AddRef() { return 2; }   
    37.     STDMETHODIMP_(ULONG) Release() { return 1; }   
    38.     STDMETHODIMP QueryInterface(REFIID riid, void ** ppv){   
    39.         if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ){    
    40.         *ppv = (void *) static_cast<ISampleGrabberCB*> ( this );   
    41.             return NOERROR;   
    42.         }    
    43.         return E_NOINTERFACE;   
    44.     }   
    45.     STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample ){   
    46.         return 0;   
    47.     }   
    48.     STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ){   
    49.         if( !bOneShot )  
    50.             return 0;  
    51.         if (!pBuffer)  
    52.         {  
    53.             AfxMessageBox(_T("Save Bmp File Failure!"));  
    54.             return E_POINTER;   
    55.         }  
    56.         if (pBuffer != NULL && pCap)  
    57.         {  
    58. //          BYTE *rgb = new BYTE[lWidth*lHeight*3];   
    59. //          YUV422_C_RGB(pBuffer,rgb, (int)lHeight, (int)lWidth);  
    60. //          outBmpBuf(pBuffer, pCap);  // 将一帧图像数据传给显示函数  
    61. //          ((CVideoNetDlg *)pCap->m_dlgParent)->SendVideo(pBuffer, (int)lBufferSize);  
    62.         }  
    63.     //  SaveBitmap(pBuffer, lBufferSize);  // 保存成位图文件  
    64. //      bOneShot = FALSE; // 停止捕获图像  
    65. //      AfxMessageBox(_T("Get bmp data success."));  
    66.         return 0;   
    67.     }  
    68.     void outBmpBuf(BYTE *buf, CCapture* cap)  
    69.     {  
    70.         cap->calFunc(buf);  
    71.     }  
    72.     // 创建位图文件  
    73.     BOOL SaveBitmap(BYTE *pBuffer, long lBufferLen)  
    74.     {  
    75.         HANDLE hf = CreateFile(m_szFileName, GENERIC_WRITE,   
    76.             FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);  
    77.         if (hf == INVALID_HANDLE_VALUE) return 0;  
    78.         // 写文件头  
    79.         BITMAPFILEHEADER fileheader;  
    80.         ZeroMemory(&fileheader, sizeof(BITMAPFILEHEADER));  
    81.         fileheader.bfType = ‘MB‘;  
    82.         fileheader.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+lBufferLen;  
    83.         fileheader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);  
    84.         DWORD dwWritter = 0;  
    85.         WriteFile(hf, &fileheader, sizeof(BITMAPFILEHEADER), &dwWritter, NULL);  
    86.         // 写文图格式  
    87.         BITMAPINFOHEADER infoHeader;  
    88.         ZeroMemory(&infoHeader, sizeof(BITMAPINFOHEADER));  
    89.         infoHeader.biSize = sizeof(BITMAPINFOHEADER);  
    90.         infoHeader.biSizeImage = lBufferLen;  
    91.         infoHeader.biWidth = lWidth;  
    92.         infoHeader.biHeight = lHeight;  
    93.         infoHeader.biBitCount = 24;  
    94.         WriteFile(hf, &infoHeader, sizeof(BITMAPINFOHEADER), &dwWritter, NULL);  
    95.         // 写位图数据  
    96.         WriteFile(hf, pBuffer, lBufferLen, &dwWritter, NULL);  
    97.         CloseHandle(hf);  
    98.         MessageBox(NULL, _T("Save bmp file succeed!"), _T("warn"), MB_OK|MB_ICONINFORMATION);  
    99.         return 0;  
    100.     }  
    101. };  
    102.   
    103. /////////////////////////////////////////////  
    104. /// for class CCapture‘s Function  
    105. ///  
    106. ////////////////////////////////////////////////  
    107. CSampleGrabberCB samCB;  
    108. CCapture::CCapture()  
    109. {  
    110.     CoInitialize(NULL);  // 初始化COM库  
    111.     m_hWnd = NULL;  
    112.     m_pVideoCap = NULL;  
    113.     m_pAudioCap = NULL;  
    114.     m_pCapGB = NULL;  
    115.     m_pGB = NULL;  
    116.     m_pMC = NULL;  
    117.     m_pMux = NULL;  
    118.     m_pVW = NULL;  
    119.     m_pGrabber = NULL;  
    120.     m_dlgParent = NULL;  
    121. }  
    122. bool CCapture::m_bRecording = false;  
    123.   
    124. CCapture::~CCapture()  
    125. {  
    126.     if (m_pMC) m_pMC->Stop();  
    127.     if (m_pVW)  
    128.     {  
    129.         m_pVW->put_Owner(NULL);  
    130.         m_pVW->put_Visible(OAFALSE);  
    131.     }  
    132.     m_hWnd = NULL;  
    133.     srelease(m_pVideoCap);  
    134.     srelease(m_pGB);  
    135.     srelease(m_pCapGB);  
    136.     srelease(m_pMC);  
    137.     srelease(m_pVW);  
    138.     m_bRecording = false;  
    139.     CoUninitialize(); // 释放COM库  
    140. }  
    141.   
    142. int CCapture::EnumDevice( HWND hCmbList, DeviceType deviceType )  
    143. {  
    144.     if (hCmbList == NULL) return -1;  
    145.     int id = 0;  
    146.     /////枚举捕获设备  
    147.     ICreateDevEnum *pCreateDevEnum;  
    148.     HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,  
    149.         NULL,  
    150.         CLSCTX_INPROC_SERVER,  
    151.         IID_ICreateDevEnum,  
    152.         (LPVOID *)&pCreateDevEnum);  
    153.     if ( hr != NOERROR) return -1;  
    154.     //////// 获取视频类的枚举器  
    155.     IEnumMoniker *pEm;           //枚举监控器接口  
    156.     if (deviceType == DTypeVideo)  
    157.         hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);  
    158.     // 如果获取音频类的枚举器 用下面的代码  
    159.     else   
    160.          hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEm, 0);  
    161. //  if (hr != NOERROR) return -1;  
    162.     if (!pEm || FAILED(hr)) return -1;  
    163.     ////////////////////////  
    164.     pEm->Reset();   // 类型枚举器复位  
    165.     ULONG cFetched;  
    166.     IMoniker *pM;    // 监控器接口指针  
    167.     while(hr = pEm->Next(1, &pM, &cFetched), hr == S_OK)  
    168.     {  
    169.         IPropertyBag *pBag;   // 属性页接口指针  
    170.         hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);  
    171.         // 获取设备属性页  
    172.         if (SUCCEEDED(hr))  
    173.         {  
    174.             VARIANT var;  
    175.             var.vt = VT_BSTR;       // 保存的是二进制数据  
    176.             // 获取firendlyName 形式的信息  
    177.             hr = pBag->Read(L"FriendlyName", &var, NULL);  
    178.             if (hr == NOERROR) // 获取成功  
    179.             {  
    180.                 id++;  
    181.                 char szDeviceName[256] = {0};  
    182.                 WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, szDeviceName,80, NULL, NULL);  // 字符串编码转换UNICODE TO ANSI  
    183.                 ::SendMessage(hCmbList, CB_ADDSTRING, 0, (LPARAM)szDeviceName);//添加到组合列表框  
    184.                 SysFreeString(var.bstrVal);  //释放资源,特别要注意  
    185.             }  
    186.             pBag->Release();  
    187.         }  
    188.         pM->Release();  
    189.     }  
    190.     return 0;  
    191. }  
    192.   
    193. void CCapture::ResizeVideoWindow()  
    194. {  
    195.     if (m_pVW)  
    196.     {  
    197.         // 让图像充满整个指定窗口  
    198.         CRect rc;  
    199.         ::GetClientRect(m_hWnd, &rc);  
    200.         m_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);  
    201.     }  
    202. }  
    203.   
    204. HRESULT CCapture::SetupVideoWindow()  
    205. {  
    206.     HRESULT hr;  
    207.     //m_hWnd为类CCapture的成员变量,在使用该函数前须初始化  
    208.     hr = m_pVW->put_Visible(OAFALSE);  // 视频窗口不可见  
    209.     hr = m_pVW->put_Owner((OAHWND)m_hWnd);  // 设置视频窗口  
    210.     if (FAILED(hr)) return hr;  
    211.     hr = m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN); //设置窗口类型  
    212.     if (FAILED(hr)) return hr;  
    213.     ResizeVideoWindow();   // 更改窗口大小  
    214.     hr = m_pVW->put_Visible(OATRUE);  // 显示视频窗口  
    215.     return hr;  
    216. }  
    217.   
    218. HRESULT CCapture::InitCaptureGraphBuilder()  
    219. {  
    220.     HRESULT hr;  
    221.     //创建IGraphBuilder接口(滤波器链表管理器) m_pGB  
    222.     hr = CoCreateInstance(CLSID_FilterGraph, NULL,  
    223.         CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB);  
    224.     if (FAILED(hr)) return hr;  
    225.     //创建ICaptureGraphBuilder2接口(增强型捕获滤波器链表管理器)m_pCapGB  
    226.     hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,  
    227.         CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **)&m_pCapGB);  
    228.     if (FAILED(hr)) return hr;  
    229.     // 创建抓取图片滤波器  
    230.     if (m_pGrabber){  
    231.         m_pGrabber.Release();  
    232.         m_pGrabber = NULL;  
    233.     }  
    234.   
    235.     hr = CoCreateInstance(CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, IID_ISampleGrabber, (void **)&m_pGrabber);  
    236. //  hr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );   
    237.     if (FAILED(hr)) return hr;  
    238.     // 初始化滤波器链表管理器IGraphBuilder  
    239.     m_pCapGB->SetFiltergraph(m_pGB);  
    240.     // 查询媒体控制接口  
    241.     hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);  
    242.     if (FAILED(hr))  return hr;  
    243.     // 查询视频窗口接口  
    244.     hr = m_pGB->QueryInterface(IID_IVideoWindow, (LPVOID *)&m_pVW);  
    245.     if (FAILED(hr)) return hr;  
    246.     /////  
    247.     return hr;  
    248. }  
    249.   
    250. HRESULT CCapture::Preview( int iDevVideoID, HWND hVideo, int iDevAudioID /*= 0*/HWND hAudio /*= NULL*/ )  
    251. {  
    252.     HRESULT hr;  
    253.     if (m_pMC)  
    254.         m_pMC->Stop();  
    255.     m_bRecording = false;  
    256.     // 初始化视频捕获滤波器链表管理器  
    257.     hr = InitCaptureGraphBuilder();  
    258.     if (FAILED(hr)) return hr;  
    259.   
    260.     // 把指定的视频采集设备与滤波器捆绑  
    261.     if (BindFilter(iDevVideoID, &m_pVideoCap, DTypeVideo))   
    262.     {  
    263.         // 把滤波器添加到滤波器链表中  
    264.         hr = m_pGB->AddFilter(m_pVideoCap, L"Video Capture Filter");  
    265.         if (FAILED(hr)) return hr;  
    266.     }  
    267.     else return FALSE;  
    268.   
    269.     if (BindFilter(iDevAudioID, &m_pAudioCap, DTypeAudio))  
    270.     {  
    271.         hr = m_pGB->AddFilter(m_pAudioCap, L"Audio Capture Filter");  
    272.         if (FAILED(hr))  
    273.         {  
    274.             MessageBox(NULL, _T("绑定音频设备失败!"), _T("系统提示"), MB_OK|MB_ICONINFORMATION);  
    275.         //  return hr;  
    276.         }  
    277.     }  
    278.     else  
    279.     {  
    280.         MessageBox(NULL, _T("绑定音频设备失败!"), _T("系统提示"), MB_OK|MB_ICONINFORMATION);  
    281.     //  return FALSE;  
    282.     }  
    283.     // 如果我们想抓取24位的RGB图片,如下设置媒体图片类型  
    284.     CComQIPtr<IBaseFilter, &IID_IBaseFilter> pGrabBase(m_pGrabber);  
    285.   
    286.     AM_MEDIA_TYPE mediaType;  
    287.     VIDEOINFOHEADER vih;  
    288.   
    289.     IAMStreamConfig* pConfig = NULL;  
    290.     m_pCapGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoCap, IID_IAMStreamConfig, (void**)&pConfig);  
    291.     // 设置视频格式  
    292.     ZeroMemory(&mediaType, sizeof(AM_MEDIA_TYPE));  
    293.     vih.bmiHeader.biWidth = IMG_WIDTH;  
    294.     vih.bmiHeader.biHeight = IMG_HEIGHT;  
    295.     vih.bmiHeader.biSizeImage = IMG_HEIGHT*IMG_WIDTH*3;  
    296.     mediaType.pbFormat = (BYTE *)(&vih);  
    297.     mediaType.cbFormat = sizeof(VIDEOINFOHEADER);  
    298.     mediaType.subtype = MEDIASUBTYPE_YUY2;  
    299.     mediaType.majortype = MEDIATYPE_Video;  
    300.     mediaType.formattype = FORMAT_VideoInfo;  
    301.     hr = pConfig->SetFormat(&mediaType);  
    302.     hr = m_pGrabber->SetMediaType(&mediaType);   
    303.     if( FAILED( hr ) ){   
    304.         AfxMessageBox("Fail to set media type!");   
    305.         return hr;   
    306.     }  
    307.       
    308.     hr = m_pGB->AddFilter(pGrabBase, L"SampleGrabber");  
    309.     if (FAILED(hr)) return hr;  
    310.     // 渲染媒体, 把链表中滤波器链接起来  
    311.     hr = m_pCapGB->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pAudioCap, NULL, NULL);  
    312.     hr = m_pCapGB->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVideoCap, pGrabBase, NULL);  
    313.     if (FAILED(hr))  
    314.         hr = m_pCapGB->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoCap, pGrabBase, NULL);  
    315.     if( FAILED( hr ) ){  
    316.         AfxMessageBox(_T("Can’t build the graph"));  
    317.         return hr;  
    318.     }  
    319.   
    320.     ////////// 设置图片捕获数据  
    321.     hr = m_pGrabber->GetConnectedMediaType( &mediaType );  
    322.     if ( FAILED( hr) ){  
    323.         AfxMessageBox(_T("Failt to read the connected media type"));  
    324.         return hr;  
    325.     }  
    326.     VIDEOINFOHEADER * pVih = (VIDEOINFOHEADER*)mediaType.pbFormat;  
    327.     samCB.lWidth = pVih->bmiHeader.biWidth;  
    328.     samCB.lHeight = pVih->bmiHeader.biHeight;  
    329.     samCB.pCap = (CCapture *)this;  
    330.     FreeMediaType(mediaType);  
    331.     hr = m_pGrabber->SetBufferSamples( TRUE );  // 如果此处为false 第一次抓取图片时失败(不用回调方式)  
    332.     hr = m_pGrabber->SetOneShot( FALSE );       
    333.     hr = m_pGrabber->SetCallback( &samCB, 1 );  
    334.     SetOnShot(TRUE);// ture 时开始捕获视频帧数据  
    335.     // 设置视频显示窗口  
    336.     m_hWnd = hVideo;  
    337.     SetupVideoWindow(); // 设置显示窗口  
    338.     hr = m_pMC->Run();  // 开始采集、预览视频,并在指定窗口显示  
    339.     if (FAILED(hr))   
    340.     {  
    341.         MessageBox(NULL, _T("请检查该设备是否被占用!"), _T("系统提示"), MB_OK|MB_ICONINFORMATION);  
    342.         return hr;  
    343.     }  
    344.     return S_OK;  
    345. }  
    346.   
    347. #if 1  // avi video format  
    348. HRESULT CCapture::CaptureVideo( CString inFileName )  // 录制视频  
    349. {  
    350.     HRESULT hr = 0;  
    351.     DWORD dwId;  
    352.     HANDLE hThread;  
    353.     m_bRecording = false;  
    354.     m_pMC->Stop();   // 先停止视频采集  
    355.   
    356.     // 设置文件名,注意第二个参数类型  
    357.     hr = m_pCapGB->SetOutputFileName(&MEDIASUBTYPE_Avi, inFileName.AllocSysString(), &m_pMux, NULL);  
    358.   
    359.     //渲染媒体 连接捕获器和AVI Muxer过滤器   
    360.     hr = m_pCapGB->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoCap, NULL, m_pMux);  
    361.     hr = m_pCapGB->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudioCap, NULL, m_pMux);  
    362.     //设置音频流为主流   
    363.     IConfigAviMux *pConfigMux;  
    364.     m_pMux->QueryInterface(IID_IConfigAviMux, (void **)&pConfigMux);  
    365.     hr = pConfigMux->SetMasterStream(1);   // 0 为视频  1为音频  
    366.   
    367.     pConfigMux->Release();  
    368.     m_pMux->Release();  
    369.     m_bRecording = true;  
    370.     hThread = CreateThread(NULL, 0,  
    371.         (LPTHREAD_START_ROUTINE)ThreadFunDrawText,  
    372.         (LPVOID)m_hWnd,  
    373.         0, &dwId);  
    374.     m_pMC->Run();  // 恢复视频采集,同时写入文件  
    375.       
    376.     return hr;  
    377. }  
    378. #else  // mpeg4 format video  
    379. HRESULT CCapture::CaptureVideo(CString inFileName)  
    380. {  
    381.     HRESULT hr=0;  
    382.       
    383.     m_pMC->Stop();  
    384.       
    385.     m_pGB->AddFilter(m_pXviDCodec,L"99 Xvid MPEG-4 Codec");  
    386.     m_pXviDCodec->Release();  
    387.       
    388.     hr = m_pCapGB->SetOutputFileName(&MEDIASUBTYPE_Avi, inFileName.AllocSysString(), &m_pMux, NULL );  
    389.     hr = ConnectFilters(m_pGB,m_pSmartTee_1,m_pXviDCodec, 0);    //0,连接capture引脚  
    390.     hr = ConnectFilters(m_pGB,m_pXviDCodec,m_pMux, 2);    //2,默认自然连接  
    391.     m_pMux->Release();  
    392.       
    393.     m_pMC->Run();  
    394.       
    395.     return hr;  
    396. }  
    397. #endif  
    398.   
    399. ///////////////////////////////  
    400.   
    401. HRESULT CCapture::CaptureImage() // 抓取并显示图像  
    402. // 采用CB接口回调函数存储图片  
    403.     bOneShot = TRUE;  
    404.     return 0;  
    405. }  
    406.   
    407. HRESULT CCapture::CaptureImage( CString inFileName ) // 抓取图像  
    408. {  
    409.     HRESULT hr;  
    410.     AM_MEDIA_TYPE mediaType;  
    411.     hr = m_pGrabber->GetConnectedMediaType(&mediaType);  
    412.     if (FAILED(hr))  return hr;  
    413.     VIDEOINFOHEADER *pVih;  
    414.     if (mediaType.formattype == FORMAT_VideoInfo &&   
    415.         (mediaType.cbFormat >= sizeof(VIDEOINFOHEADER)) &&  
    416.         mediaType.pbFormat != NULL)  
    417.     {  
    418.         pVih = (VIDEOINFOHEADER *)mediaType.pbFormat;  
    419.     }  
    420.     else       
    421.         return VFW_E_INVALIDMEDIATYPE;  
    422.   
    423. //  hr = m_pGrabber->SetOneShot(TRUE);  
    424.     if (SUCCEEDED(m_pGrabber->SetBufferSamples(TRUE)) )  // 设置为缓冲形式)  
    425.     {  
    426.         long cbBuffer = 0;  
    427.         hr = m_pGrabber->GetCurrentBuffer(&cbBuffer, NULL);  
    428.         BYTE *pBuffer = new BYTE[cbBuffer];  
    429.         if (!pBuffer) return -1;  
    430.         // 获取一帧媒体的数据  
    431.         hr = m_pGrabber->GetCurrentBuffer(&cbBuffer, (long *)pBuffer);  
    432.         if (FAILED(hr))  return hr;  
    433. //          if (pBuffer != NULL)  
    434. //          {  
    435. //              calFunc(pBuffer);   // 将一帧图像数据传给显示函数  
    436. //      }  
    437.   
    438.         ///-------------------------测试所得数据是rgb格式还是yuv格式--------  
    439.         long n1,n2;  
    440.         int datalen = IMG_WIDTH*IMG_HEIGHT*3;  
    441.         BYTE *rgb = new BYTE[datalen];  
    442.           
    443.         YUV422_C_RGB(pBuffer,rgb, IMG_HEIGHT, IMG_WIDTH);  
    444.         n1 = strlen((char *)pBuffer);  
    445.         n2 = strlen((char *)rgb);  
    446. //      ((CVideoNetDlg *)(m_dlgParent))->SendVideo((BYTE *)pBuffer, (int)cbBuffer);  
    447.         ///------------------------------------------------------------------  
    448. ///////////////////////////////////////////////////////////////  
    449.         // Create a file to hold the bitmap  
    450.         HANDLE hf = CreateFile(inFileName, GENERIC_WRITE, FILE_SHARE_READ,    
    451.             NULL, CREATE_ALWAYS, NULL, NULL );  
    452.           
    453.         if( hf == INVALID_HANDLE_VALUE ){  
    454.             MessageBox(NULL, _T("Create bmp file failure!"), _T(""), MB_OK|MB_ICONINFORMATION);  
    455.             return 0;  
    456.         }  
    457.           
    458.         // Write out the file header  
    459.         //  
    460.         // 信息头  
    461.         BITMAPFILEHEADER bfh;  
    462.         memset( &bfh, 0, sizeof( bfh ) );  
    463.         bfh.bfType = ‘MB‘;  
    464.         bfh.bfSize = sizeof( bfh ) + cbBuffer + sizeof( BITMAPINFOHEADER );  
    465.         bfh.bfOffBits = sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER );  
    466.           
    467.         DWORD Written = 0;  
    468.         WriteFile( hf, &bfh, sizeof( bfh ), &Written, NULL );  
    469.           
    470.         // Write the bitmap format  
    471.         //文件头  
    472.         BITMAPINFOHEADER bih;  
    473.         memset( &bih, 0, sizeof( bih ) );  
    474.         bih.biSize = sizeof( bih );  
    475.         bih.biWidth = pVih->bmiHeader.biWidth;  
    476.         bih.biHeight = pVih->bmiHeader.biHeight;  
    477.         bih.biPlanes = 1;  
    478.         bih.biBitCount = 24;  
    479.           
    480.         Written = 0;  
    481.         WriteFile( hf, &bih, sizeof( bih ), &Written, NULL );  
    482.           
    483.         // Write the bitmap bits  
    484.         //  
    485.         Written = 0;  
    486.         WriteFile( hf, rgb, datalen, &Written, NULL );       
    487.         CloseHandle( hf );  
    488.         delete pBuffer;  
    489.         MessageBox(NULL, _T("Save photo succeeded!"), _T("抓取图片提示"), MB_OK|MB_ICONINFORMATION);  
    490.     }  
    491.     m_pGrabber->SetOneShot(FALSE);  
    492.     m_pGrabber->SetBufferSamples(FALSE);  
    493.     FreeMediaType(mediaType);  
    494.     return 0;  
    495. }  
    496.   
    497. bool CCapture::BindFilter( int iDeviceID, IBaseFilter **pOutFilter, DeviceType deviceType )  
    498. {  
    499.     if (iDeviceID < 0) return false;  
    500.     // 枚举所有的视频设备  
    501.     ICreateDevEnum *pCreateDevEnum;  
    502.     //生成设备枚举器pCreateDevEnum  
    503.     HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,  
    504.         NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pCreateDevEnum);  
    505.     if (hr != NOERROR) return false;  
    506.     IEnumMoniker *pEM;  
    507.     // 创建视频输入设备类枚举器  
    508.     if (deviceType == DTypeVideo)  
    509.         hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEM, 0);  
    510.     // 音频设备枚举器  
    511.     else  
    512.         hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEM, 0);  
    513.     if (hr != NOERROR) return false;  
    514.     pEM->Reset();  // 复位该设备  
    515.     ULONG cFetched;  
    516.     IMoniker *pM;  
    517.     int indexDev = 0;  
    518.     // 获取设备  
    519.     while(hr = pEM->Next(1, &pM, &cFetched), hr == S_OK, indexDev <= iDeviceID)  
    520.     {  
    521.         IPropertyBag *pBag;  
    522.         // 获取该设备属性集  
    523.         hr = pM->BindToStorage(0,0,IID_IPropertyBag,(void **)&pBag);  
    524.         if (SUCCEEDED(hr))  
    525.         {  
    526.             VARIANT var;  
    527.             var.vt = VT_BSTR;  
    528.             hr = pBag->Read(L"FriendlyName", &var, NULL);  
    529.             if (hr == NOERROR)  
    530.             {  
    531.                 // 采集设备与捕获滤波器捆绑  
    532.                 if (indexDev == iDeviceID) pM->BindToObject(0, 0, IID_IBaseFilter, (void **)pOutFilter);  
    533.                 SysFreeString(var.bstrVal);  
    534.             }  
    535.             pBag->Release();  
    536.         }  
    537.         pM->Release();  
    538.         indexDev++;  
    539.     }  
    540.     return true;  
    541. }  
    542.   
    543. void CCapture::SetCameraFormat( HWND hwndParent ) // 设置视频格式  
    544. {  
    545.     HRESULT hr;  
    546.     IAMStreamConfig *pSC; // 流配置接口  
    547.     ISpecifyPropertyPages *pSpec; //属性页接口  
    548.     m_pMC->Stop();  // 只有停止后才能进行引脚属性的设置  
    549.     m_bRecording = false;  
    550.     // 首先查询捕获CAPTURE、视频Video接口  
    551.     hr = m_pCapGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,  
    552.         m_pVideoCap, IID_IAMStreamConfig, (void **)&pSC);  
    553.   
    554.     CAUUID cauuid; // 所有属性页结构体  
    555.     hr = pSC->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpec);  
    556.     if (hr == S_OK)  
    557.     {  
    558.         // 显示属性页窗口  
    559.         hr = pSpec->GetPages(&cauuid);  // 获取所有属性页  
    560.         hr = OleCreatePropertyFrame(hwndParent, 30, 30, NULL, 1,  
    561.             (IUnknown **)&pSC, cauuid.cElems, (GUID *)cauuid.pElems, 0, 0, NULL);  
    562.         // 释放内存资源  
    563.         CoTaskMemFree(cauuid.pElems);  
    564.         pSpec->Release();  
    565.         pSC->Release();  
    566.     }  
    567.     // 恢复运行  
    568.     m_pMC->Run();          
    569. }  
    570.   
    571. void CCapture::SetCameraFilter( HWND hwndParent ) // 设置图像各参数设置  
    572. {  
    573.     HRESULT hr = 0;  
    574.     ISpecifyPropertyPages *pSpec;  
    575.     hr = m_pVideoCap->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpec);  
    576.     if (SUCCEEDED(hr))  
    577.     {  
    578.         // 获取滤波器名称和IUnknown 接口指针  
    579.         FILTER_INFO FilterInfo;  
    580.         hr = m_pVideoCap->QueryFilterInfo(&FilterInfo);  
    581.         IUnknown *pFilterUnk;  
    582.         m_pVideoCap->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);  
    583.         // 显示该页  
    584.         CAUUID caGUID;  
    585.         pSpec->GetPages(&caGUID);  
    586.         OleCreatePropertyFrame(hwndParent,  
    587.             0, 0,  
    588.             FilterInfo.achName,  
    589.             1,  
    590.             &pFilterUnk,  
    591.             caGUID.cElems,  
    592.             caGUID.pElems,  
    593.             0,  
    594.             0, NULL);  
    595.         // 释放内存资源  
    596.         CoTaskMemFree(caGUID.pElems);  
    597.         pFilterUnk->Release();  
    598.         FilterInfo.pGraph->Release();  
    599.         pSpec->Release();  
    600.     }  
    601. }  
    602.   
    603. void CCapture::StopCapture()  
    604. {  
    605.     m_pMC->Stop();  
    606. }  
    607.   
    608. UINT CCapture::ThreadFunDrawText( LPVOID lParam )  
    609. {  
    610.     HWND hwnd = (HWND)lParam;  
    611.     if (hwnd == NULL) return -1;  
    612.     HDC hdc = GetDC(hwnd);  
    613.     CRect rcDraw, rcTime;  
    614.     CTime time, time0;  
    615.     CTimeSpan timespan;  
    616.     CString strTime;  
    617.     CBrush br;  
    618.     time0 = CTime::GetCurrentTime();  
    619.     br.CreateSolidBrush(RGB(255,0,0));  
    620.     GetClientRect(hwnd, &rcDraw);  
    621.     rcTime = rcDraw;  
    622.     rcTime.bottom = rcTime.top + 30;  
    623.     rcDraw.top = rcDraw.bottom - 30;  
    624.     SelectObject(hdc, &br);  
    625.     SetTextColor(hdc, 0x0000ff);  
    626.     SetBkMode(hdc, TRANSPARENT);  
    627.     while(m_bRecording)  
    628.     {  
    629.         time = CTime::GetCurrentTime();  
    630.         timespan = time - time0;  
    631.         strTime = time.Format(_T(" %Y-%m-%d 星期%w %H:%M:%S"));  
    632.         DrawText(hdc, strTime, strTime.GetLength(), &rcTime, DT_VCENTER|DT_LEFT|DT_SINGLELINE);  
    633.         strTime = timespan.Format(_T("%H:%M:%S "));  
    634.         strTime = _T("●录制 ") + strTime;  
    635.         DrawText(hdc, strTime, strTime.GetLength(), &rcDraw, DT_VCENTER|DT_RIGHT|DT_SINGLELINE);  
    636.     }  
    637.     return 0;  
    638. }  
    639.   
    640. void CCapture::FreeMediaType(AM_MEDIA_TYPE &mt)  
    641. {  
    642.     if (mt.cbFormat != 0)  
    643.     {  
    644.         CoTaskMemFree((PVOID)mt.pbFormat);  
    645.         mt.cbFormat = 0;  
    646.         mt.pbFormat = NULL;  
    647.     }  
    648.     if (mt.pUnk != NULL)  
    649.     {  
    650.         mt.pUnk->Release();  
    651.         mt.pUnk = NULL;  
    652.     }  
    653. }  
    654.   
    655. void CCapture::SetOnShot( BOOL bFlag )  
    656. {  
    657.     bOneShot = bFlag;  
    658. }  
    659.   
    660. void CCapture::SetCallBKFun( capCallBackFunc f )  
    661. {  
    662.     this->calFunc = f;  
    663.     samCB.pCap = static_cast<CCapture *>(this);  
    664. }  
    665.   
    666. void CCapture::SetParent( CDialog *pdlg )  
    667. {  
    668.     m_dlgParent = pdlg;  
    669. }