CCapture directshow 视频捕获类

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