多媒体编程——摄像头录像预览

59 篇文章 0 订阅

http://blog.csdn.net/yangyk125/article/details/29216149



多媒体编程——摄像头录像预览


1、 新建MFC工程,选择对话框工程。


2、新建一个static控件。


3、修改ID,并且在OnInitDialog里面获取指针。





4、加一个成员函数,并且在OnInitDialog里面调用,作为我们的例子代码的放置位置。





5、添加完整头文件


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <qedit.h>  
  2. #include <dshow.h>  
  3. #include <dxtrans.h>  
  4. #pragma comment(lib,"strmiids.lib")  
  5.    
  6. //DirectDraw  
  7. #include <ddraw.h>  
  8. #pragma comment(lib,"ddraw.lib")  
  9. #pragma comment(lib,"dxguid.lib")  

并且让Dialog同时继承类型 ISampleGrabberCB


6、添加读取摄像头的代码

摄像头读取,使用的是DirectXSDK中的DirectShow组件

 

需要编写的代码如下

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CCameraTestDlg::initCameraPreview()  
  2. {  
  3.     HRESULT hr = CoInitialize(NULL);  
  4.     if(FAILED(hr))  
  5.         return ;  
  6.   
  7.     IBaseFilter* pCameraFilter = NULL ;  
  8.   
  9.     //检查并加载系统摄像头。  
  10.     CComPtr <IMoniker> pMoniker =NULL;  
  11.     ULONG cFetched;  
  12.     CComPtr <ICreateDevEnum> pDevEnum =NULL;  
  13.     hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,IID_ICreateDevEnum, (void **) &pDevEnum);  
  14.     if (FAILED(hr))  
  15.         return ;  
  16.     CComPtr <IEnumMoniker> pClassEnum = NULL;  
  17.     hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);  
  18.     if (FAILED(hr))  
  19.         return ;  
  20.     if (pClassEnum == NULL)  
  21.         return ;  
  22.     if (SUCCEEDED(pClassEnum->Next (1, &pMoniker, &cFetched)))  
  23.     {  
  24.         hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pCameraFilter);  
  25.         if (FAILED(hr))  
  26.             return ;  
  27.     }  
  28.   
  29.     if(pCameraFilter == NULL)  
  30.         return ;  
  31.   
  32.     //加载DirectShow对象  
  33.     IGraphBuilder* pGraphBuilder = NULL ;  
  34.     hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,IID_IGraphBuilder, (void **) &pGraphBuilder);  
  35.     if (FAILED(hr))  
  36.         return ;  
  37.   
  38.     // Create the capture graph builder  
  39.     ICaptureGraphBuilder2* pCaptureGraphBuilder = NULL ;  
  40.     hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **) &pCaptureGraphBuilder);  
  41.     if (FAILED(hr))  
  42.         return ;  
  43.   
  44.     //Create sampleGrabber   
  45.     IBaseFilter* pSampleGrabberFilter = NULL ;  
  46.     hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC,IID_IBaseFilter, (void**)&pSampleGrabberFilter);  
  47.     if (FAILED(hr))  
  48.         return ;  
  49.   
  50.     ISampleGrabber* pSampleGrabber = NULL ;  
  51.     hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);  
  52.     if (FAILED(hr))  
  53.         return ;  
  54.   
  55.   
  56.     //设置视频格式  
  57.     AM_MEDIA_TYPE mt;  
  58.     ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));  
  59.     mt.majortype = MEDIATYPE_Video   ;  
  60.     mt.subtype   = MEDIASUBTYPE_RGB32;  
  61.   
  62.     hr = pSampleGrabber->SetMediaType(&mt);  
  63.     if (FAILED(hr))  
  64.         return ;  
  65.   
  66.     hr = pSampleGrabber->SetOneShot(FALSE);  
  67.     if (FAILED(hr))  
  68.         return ;  
  69.   
  70.     hr = pSampleGrabber->SetBufferSamples(FALSE);  
  71.     if (FAILED(hr))  
  72.         return ;  
  73.   
  74.     hr = pSampleGrabber->SetCallback(this, 1);  
  75.     if (FAILED(hr))  
  76.         return ;  
  77.   
  78.     // Obtain interfaces for media control and Video Window  
  79.     IMediaControl* pMediaControl = NULL ;  
  80.     hr = pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID *) &pMediaControl);  
  81.     if (FAILED(hr))  
  82.         return ;  
  83.   
  84.     // Attach the filter graph to the capture graph  
  85.     hr = pCaptureGraphBuilder->SetFiltergraph(pGraphBuilder);  
  86.     if (FAILED(hr))  
  87.         return ;  
  88.   
  89.     // Add Capture filter to our graph.  
  90.     hr = pGraphBuilder->AddFilter(pCameraFilter, L"Video Capture");  
  91.     if (FAILED(hr))  
  92.         return ;  
  93.   
  94.     hr = pGraphBuilder->AddFilter(pSampleGrabberFilter, L"Sample Grabber");  
  95.     if (FAILED(hr))  
  96.         return ;  
  97.   
  98.     //将摄像头和采集连接  
  99.     hr = pCaptureGraphBuilder->RenderStream(NULL,&MEDIATYPE_Video,pCameraFilter,NULL,pSampleGrabberFilter);  
  100.     if (FAILED(hr))  
  101.         return ;  
  102.   
  103.     //连接之后取得来源视频格式  
  104.     AM_MEDIA_TYPE amt;  
  105.     hr = pSampleGrabber->GetConnectedMediaType(&amt);  
  106.     if (FAILED(hr))  
  107.         return ;  
  108.   
  109.     //获取摄像头采集画面的分辨率  
  110.     int width = 0 ;  
  111.     int height = 0 ;  
  112.     VIDEOINFOHEADER* pVideoHeader = reinterpret_cast<VIDEOINFOHEADER*>(amt.pbFormat);  
  113.     if(pVideoHeader)  
  114.     {  
  115.         width = pVideoHeader->bmiHeader.biWidth ;  
  116.         height= pVideoHeader->bmiHeader.biHeight ;  
  117.   
  118.         if (amt.cbFormat != 0)  
  119.         {  
  120.             CoTaskMemFree((PVOID)mt.pbFormat);  
  121.             mt.cbFormat = 0;  
  122.             mt.pbFormat = NULL;  
  123.         }  
  124.         if (amt.pUnk != NULL)  
  125.         {  
  126.             mt.pUnk->Release();  
  127.             mt.pUnk = NULL;  
  128.         }  
  129.     }  
  130.     else  
  131.         return ;  
  132.     //调用run之后才真正开始得到图像。  
  133.     pMediaControl->Run();  
  134. }  
  135.   
  136. HRESULT CCameraTestDlg::SampleCB(double SampleTime,IMediaSample *pSample)  
  137. {  
  138.     return E_FAIL;  
  139. }  
  140. HRESULT CCameraTestDlg::BufferCB(double SampleTime,BYTE *pBuffer, long BufferLen)  
  141. {  
  142.     OutputDebugString(_T("BufferCB image data!\n"));  
  143.     return E_FAIL;  
  144. }  
  145. HRESULT CCameraTestDlg::QueryInterface(REFIID riid,void** ppvObject)  
  146. {  
  147.     return S_OK ;  
  148. }  
  149. ULONG CCameraTestDlg::AddRef(void)  
  150. {  
  151.     return 0 ;  
  152. }  
  153. ULONG CCameraTestDlg::Release(void)  
  154. {  
  155.     return 0 ;  
  156. }  

此刻运行,已经能看到OutputDebugString不停的输出了,说明已经获取到了数据。只不过还没添加渲染,看不到图像。


7、添加视频渲染初始化函数,initDrawVideo(int width, int height)


并且在初始化摄像头成功,获取了分辨率那个地方,调用它。


新增加一个渲染函数。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void DisplayLine(LPBYTE pBuf,int nPixelBytes)  

第一个参数是数据buf,第二个参数是字节数。

后面完整代码:



[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // CameraTestDlg.h : 头文件  
  2. //  
  3.   
  4. #pragma once  
  5.   
  6. //DirectShow  
  7. #include <qedit.h>  
  8. #include <dshow.h>  
  9. #include <dxtrans.h>  
  10. #pragma comment(lib,"strmiids.lib")  
  11.   
  12. //DirectDraw  
  13. #include <ddraw.h>  
  14. #pragma comment(lib,"ddraw.lib")  
  15. #pragma comment(lib,"dxguid.lib")  
  16.   
  17. // CCameraTestDlg 对话框  
  18. class CCameraTestDlg : public CDialog  
  19.                      , public ISampleGrabberCB  
  20. {  
  21. // 构造  
  22. public:  
  23.     CCameraTestDlg(CWnd* pParent = NULL);   // 标准构造函数  
  24.   
  25. // 对话框数据  
  26.     enum { IDD = IDD_CAMERATEST_DIALOG };  
  27.   
  28.     protected:  
  29.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  30.   
  31.   
  32. // 实现  
  33. protected:  
  34.     HICON m_hIcon;  
  35.   
  36.     // 生成的消息映射函数  
  37.     virtual BOOL OnInitDialog();  
  38.     afx_msg void OnPaint();  
  39.     afx_msg HCURSOR OnQueryDragIcon();  
  40.     DECLARE_MESSAGE_MAP()  
  41.   
  42. protected:  
  43.     CStatic*                 m_pPlayControl ;  
  44.   
  45.     LPDIRECTDRAW7            m_lpDDraw;   // DirectDraw 对象指针  
  46.     LPDIRECTDRAWSURFACE7     m_lpDDSOverlay ; // DirectDraw 离屏表面指针  
  47.     DDSURFACEDESC2           m_stOverlayDdsd;   // DirectDraw 表面描述  
  48.     LPDIRECTDRAWSURFACE7     m_lpDDSPrimary; // DirectDraw 主表面指针  
  49.     DDSURFACEDESC2           m_stPrimaryDdsd;   // DirectDraw 表面描述  
  50.     LPDIRECTDRAWCLIPPER      m_pDirectDrawCliper ;//  
  51.   
  52.     void  initCameraPreview() ;  
  53.     void  initDrawVideo(int width, int height);  
  54.     void  DisplayLine(LPBYTE pBuf,int nPixelBytes);  
  55. public:  
  56.     HRESULT STDMETHODCALLTYPE SampleCB(double SampleTime,IMediaSample *pSample);  
  57.     HRESULT STDMETHODCALLTYPE BufferCB(double SampleTime,BYTE *pBuffer, long BufferLen);  
  58.     HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,void**ppvObject);  
  59.     ULONG STDMETHODCALLTYPE AddRef(void);  
  60.     ULONG STDMETHODCALLTYPE Release(void);  
  61. };  

实现文件代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // CameraTestDlg.cpp : 实现文件  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include "CameraTest.h"  
  6. #include "CameraTestDlg.h"  
  7.   
  8. #ifdef _DEBUG  
  9. #define new DEBUG_NEW  
  10. #endif  
  11.   
  12.   
  13. // CCameraTestDlg 对话框  
  14.   
  15.   
  16.   
  17. CCameraTestDlg::CCameraTestDlg(CWnd* pParent /*=NULL*/)  
  18.     : CDialog(CCameraTestDlg::IDD, pParent)  
  19. {  
  20.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
  21. }  
  22.   
  23. void CCameraTestDlg::DoDataExchange(CDataExchange* pDX)  
  24. {  
  25.     CDialog::DoDataExchange(pDX);  
  26. }  
  27.   
  28. BEGIN_MESSAGE_MAP(CCameraTestDlg, CDialog)  
  29.     ON_WM_PAINT()  
  30.     ON_WM_QUERYDRAGICON()  
  31.     //}}AFX_MSG_MAP  
  32. END_MESSAGE_MAP()  
  33.   
  34.   
  35. // CCameraTestDlg 消息处理程序  
  36.   
  37. BOOL CCameraTestDlg::OnInitDialog()  
  38. {  
  39.     CDialog::OnInitDialog();  
  40.   
  41.     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动  
  42.     //  执行此操作  
  43.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  44.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  45.   
  46.     this->m_pPlayControl = (CStatic*)GetDlgItem(IDC_STATIC_PLAYCONTROL);  
  47.   
  48.     this->initCameraPreview();  
  49.   
  50.     return TRUE;  // 除非将焦点设置到控件,否则返回TRUE  
  51. }  
  52.   
  53. // 如果向对话框添加最小化按钮,则需要下面的代码  
  54. //  来绘制该图标。对于使用文档/视图模型的MFC 应用程序,  
  55. //  这将由框架自动完成。  
  56.   
  57. void CCameraTestDlg::OnPaint()  
  58. {  
  59.     if (IsIconic())  
  60.     {  
  61.         CPaintDC dc(this); // 用于绘制的设备上下文  
  62.   
  63.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  
  64.   
  65.         // 使图标在工作区矩形中居中  
  66.         int cxIcon = GetSystemMetrics(SM_CXICON);  
  67.         int cyIcon = GetSystemMetrics(SM_CYICON);  
  68.         CRect rect;  
  69.         GetClientRect(&rect);  
  70.         int x = (rect.Width() - cxIcon + 1) / 2;  
  71.         int y = (rect.Height() - cyIcon + 1) / 2;  
  72.   
  73.         // 绘制图标  
  74.         dc.DrawIcon(x, y, m_hIcon);  
  75.     }  
  76.     else  
  77.     {  
  78.         CDialog::OnPaint();  
  79.     }  
  80. }  
  81.   
  82. //当用户拖动最小化窗口时系统调用此函数取得光标  
  83. //显示。  
  84. HCURSOR CCameraTestDlg::OnQueryDragIcon()  
  85. {  
  86.     return static_cast<HCURSOR>(m_hIcon);  
  87. }  
  88.   
  89.   
  90. void CCameraTestDlg::initCameraPreview()  
  91. {  
  92.     HRESULT hr = CoInitialize(NULL);  
  93.     if(FAILED(hr))  
  94.         return ;  
  95.   
  96.     IBaseFilter* pCameraFilter = NULL ;  
  97.   
  98.     //检查并加载系统摄像头。  
  99.     CComPtr <IMoniker> pMoniker =NULL;  
  100.     ULONG cFetched;  
  101.     CComPtr <ICreateDevEnum> pDevEnum =NULL;  
  102.     hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,IID_ICreateDevEnum, (void **) &pDevEnum);  
  103.     if (FAILED(hr))  
  104.         return ;  
  105.     CComPtr <IEnumMoniker> pClassEnum = NULL;  
  106.     hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);  
  107.     if (FAILED(hr))  
  108.         return ;  
  109.     if (pClassEnum == NULL)  
  110.         return ;  
  111.     if (SUCCEEDED(pClassEnum->Next (1, &pMoniker, &cFetched)))  
  112.     {  
  113.         hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pCameraFilter);  
  114.         if (FAILED(hr))  
  115.             return ;  
  116.     }  
  117.   
  118.     if(pCameraFilter == NULL)  
  119.         return ;  
  120.   
  121.     //加载DirectShow对象  
  122.     IGraphBuilder* pGraphBuilder = NULL ;  
  123.     hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,IID_IGraphBuilder, (void **) &pGraphBuilder);  
  124.     if (FAILED(hr))  
  125.         return ;  
  126.   
  127.     // Create the capture graph builder  
  128.     ICaptureGraphBuilder2* pCaptureGraphBuilder = NULL ;  
  129.     hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **) &pCaptureGraphBuilder);  
  130.     if (FAILED(hr))  
  131.         return ;  
  132.   
  133.     //Create sampleGrabber   
  134.     IBaseFilter* pSampleGrabberFilter = NULL ;  
  135.     hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC,IID_IBaseFilter, (void**)&pSampleGrabberFilter);  
  136.     if (FAILED(hr))  
  137.         return ;  
  138.   
  139.     ISampleGrabber* pSampleGrabber = NULL ;  
  140.     hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);  
  141.     if (FAILED(hr))  
  142.         return ;  
  143.   
  144.   
  145.     //设置视频格式  
  146.     AM_MEDIA_TYPE mt;  
  147.     ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));  
  148.     mt.majortype = MEDIATYPE_Video   ;  
  149.     mt.subtype   = MEDIASUBTYPE_RGB32;  
  150.   
  151.     hr = pSampleGrabber->SetMediaType(&mt);  
  152.     if (FAILED(hr))  
  153.         return ;  
  154.   
  155.     hr = pSampleGrabber->SetOneShot(FALSE);  
  156.     if (FAILED(hr))  
  157.         return ;  
  158.   
  159.     hr = pSampleGrabber->SetBufferSamples(FALSE);  
  160.     if (FAILED(hr))  
  161.         return ;  
  162.   
  163.     hr = pSampleGrabber->SetCallback(this, 1);  
  164.     if (FAILED(hr))  
  165.         return ;  
  166.   
  167.     // Obtain interfaces for media control and Video Window  
  168.     IMediaControl* pMediaControl = NULL ;  
  169.     hr = pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID *) &pMediaControl);  
  170.     if (FAILED(hr))  
  171.         return ;  
  172.   
  173.     // Attach the filter graph to the capture graph  
  174.     hr = pCaptureGraphBuilder->SetFiltergraph(pGraphBuilder);  
  175.     if (FAILED(hr))  
  176.         return ;  
  177.   
  178.     // Add Capture filter to our graph.  
  179.     hr = pGraphBuilder->AddFilter(pCameraFilter, L"Video Capture");  
  180.     if (FAILED(hr))  
  181.         return ;  
  182.   
  183.     hr = pGraphBuilder->AddFilter(pSampleGrabberFilter, L"Sample Grabber");  
  184.     if (FAILED(hr))  
  185.         return ;  
  186.   
  187.     //将摄像头和采集连接  
  188.     hr = pCaptureGraphBuilder->RenderStream(NULL,&MEDIATYPE_Video,pCameraFilter,NULL,pSampleGrabberFilter);  
  189.     if (FAILED(hr))  
  190.         return ;  
  191.   
  192.     //连接之后取得来源视频格式  
  193.     AM_MEDIA_TYPE amt;  
  194.     hr = pSampleGrabber->GetConnectedMediaType(&amt);  
  195.     if (FAILED(hr))  
  196.         return ;  
  197.   
  198.     //获取摄像头采集画面的分辨率  
  199.     int width = 0 ;  
  200.     int height = 0 ;  
  201.     VIDEOINFOHEADER* pVideoHeader = reinterpret_cast<VIDEOINFOHEADER*>(amt.pbFormat);  
  202.     if(pVideoHeader)  
  203.     {  
  204.         width = pVideoHeader->bmiHeader.biWidth ;  
  205.         height= pVideoHeader->bmiHeader.biHeight ;  
  206.   
  207.         if (amt.cbFormat != 0)  
  208.         {  
  209.             CoTaskMemFree((PVOID)mt.pbFormat);  
  210.             mt.cbFormat = 0;  
  211.             mt.pbFormat = NULL;  
  212.         }  
  213.         if (amt.pUnk != NULL)  
  214.         {  
  215.             mt.pUnk->Release();  
  216.             mt.pUnk = NULL;  
  217.         }  
  218.     }  
  219.     else  
  220.         return ;  
  221.   
  222.     this->initDrawVideo(width, height);  
  223.   
  224.     pMediaControl->Run();  
  225. }  
  226.   
  227. HRESULT CCameraTestDlg::SampleCB(double SampleTime,IMediaSample *pSample)  
  228. {  
  229.     return E_FAIL;  
  230. }  
  231. HRESULT CCameraTestDlg::BufferCB(double SampleTime,BYTE *pBuffer, long BufferLen)  
  232. {  
  233.     this->DisplayLine(pBuffer, 32/8);  
  234.     return E_FAIL;  
  235. }  
  236. HRESULT CCameraTestDlg::QueryInterface(REFIID riid,void** ppvObject)  
  237. {  
  238.     return S_OK ;  
  239. }  
  240. ULONG CCameraTestDlg::AddRef(void)  
  241. {  
  242.     return 0 ;  
  243. }  
  244. ULONG CCameraTestDlg::Release(void)  
  245. {  
  246.     return 0 ;  
  247. }  
  248.   
  249.   
  250.   
  251.   
  252.   
  253. void CCameraTestDlg::initDrawVideo(int width, int height)  
  254. {  
  255.     HRESULT hr = DirectDrawCreateEx(NULL, (LPVOID*)&m_lpDDraw,IID_IDirectDraw7, NULL);  
  256.     if (FAILED(hr))  
  257.         return ;  
  258.   
  259.     // 设置协作层  
  260.     hr = m_lpDDraw->SetCooperativeLevel(this->m_hWnd, DDSCL_NORMAL);  
  261.     if (FAILED(hr))  
  262.         return ;  
  263.   
  264.     // 创建主表面  
  265.     ZeroMemory(&m_stPrimaryDdsd, sizeof(DDSURFACEDESC2));  
  266.     m_stPrimaryDdsd.dwSize = sizeof(DDSURFACEDESC2);  
  267.     m_stPrimaryDdsd.dwFlags = DDSD_CAPS ;  
  268.     m_stPrimaryDdsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;  
  269.     hr = m_lpDDraw->CreateSurface(&m_stPrimaryDdsd, &m_lpDDSPrimary, NULL);  
  270.     if (FAILED(hr))  
  271.         return ;  
  272.   
  273.     // 创建缓存表面  
  274.     ZeroMemory(&m_stOverlayDdsd, sizeof(DDSURFACEDESC2));  
  275.     m_stOverlayDdsd.dwSize = sizeof(DDSURFACEDESC2);  
  276.     m_stOverlayDdsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN ;  
  277.     m_stOverlayDdsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT ;  
  278.     m_stOverlayDdsd.dwWidth = width;  
  279.     m_stOverlayDdsd.dwHeight = height;  
  280.   
  281.     struct DDPIXELFORMATDEF : public DDPIXELFORMAT  
  282.     {  
  283.         DDPIXELFORMATDEF(UINT dwFlags,  
  284.             UINT dwFourCC = 0x0,  
  285.             UINT dwUnionBitCount = 0x0,  
  286.             UINT dwUnionBitMask1 = 0x0,UINT dwUnionBitMask2 = 0x0,  
  287.             UINT dwUnionBitMask3 = 0x0,UINT dwUnionBitMask4 = 0x0)  
  288.         {  
  289.             __super::dwFlags = dwFlags ;  
  290.             __super::dwFourCC = dwFourCC ;  
  291.             __super::dwRGBBitCount = dwUnionBitCount ;  
  292.             __super::dwRBitMask = dwUnionBitMask1 ;  
  293.             __super::dwGBitMask = dwUnionBitMask2 ;  
  294.             __super::dwBBitMask = dwUnionBitMask3 ;  
  295.             __super::dwRGBAlphaBitMask = dwUnionBitMask4 ;  
  296.         }  
  297.     };  
  298.   
  299.     //上面摄像头那里强制的设置的RGB32,则这里就使用RGB32。  
  300.     m_stOverlayDdsd.ddpfPixelFormat = DDPIXELFORMATDEF(DDPF_RGB,0x0,32,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000) ;  
  301.     m_stOverlayDdsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);  
  302.   
  303.     hr = m_lpDDraw->CreateSurface(&m_stOverlayDdsd, &m_lpDDSOverlay, NULL);  
  304.     if (FAILED(hr))  
  305.     {  
  306.         m_stOverlayDdsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN ;//使用内存再次尝试创建。  
  307.         hr = m_lpDDraw->CreateSurface(&m_stOverlayDdsd, &m_lpDDSOverlay, NULL);  
  308.         if (FAILED(hr))  
  309.             return  ;  
  310.     }  
  311.   
  312.     hr = m_lpDDraw->CreateClipper(0,&m_pDirectDrawCliper,NULL);  
  313.     if (FAILED(hr))  
  314.         return ;  
  315.   
  316.     hr = m_pDirectDrawCliper->SetHWnd(0,this->m_pPlayControl->m_hWnd);  
  317.     if (FAILED(hr))  
  318.         return ;  
  319.   
  320.     hr = m_lpDDSPrimary->SetClipper(m_pDirectDrawCliper);  
  321.     if (FAILED(hr))  
  322.         return ;  
  323. }  
  324.   
  325. void CCameraTestDlg::DisplayLine(LPBYTE pBuf,int nPixelBytes)  
  326. {  
  327.     HRESULT     hr;   // DirectDraw 函数返回值  
  328.   
  329.     hr = m_lpDDSOverlay->Lock(NULL,&m_stOverlayDdsd,DDLOCK_WAIT|DDLOCK_WRITEONLY,NULL);  
  330.     if (FAILED(hr))  
  331.         return ;  
  332.   
  333.     LPBYTE p_YUV_RGB = pBuf ;  
  334.   
  335.     int dwByteCountPerLine = m_stOverlayDdsd.dwWidth*nPixelBytes; //m_stOverlayDdsd.ddpfPixelFormat.dwRGBBitCount/8 ;  
  336.   
  337.     //摄像头读取的画面上下是反过来的,这个就自己处理了,就在下面的循环里处理就好了。  
  338.     LPBYTE lpSurface = (LPBYTE)m_stOverlayDdsd.lpSurface;  
  339.     if(lpSurface)  
  340.     {  
  341.         for (int i=0;i<m_stOverlayDdsd.dwHeight;i++)  
  342.         {  
  343.             memcpy(lpSurface, p_YUV_RGB, dwByteCountPerLine);  
  344.             p_YUV_RGB += dwByteCountPerLine;  
  345.             lpSurface += m_stOverlayDdsd.lPitch;  
  346.         }  
  347.     }  
  348.   
  349.     hr = m_lpDDSOverlay->Unlock(NULL);  
  350.     if (FAILED(hr))  
  351.         return ;  
  352.   
  353.     RECT rect;  
  354.     ::GetClientRect(m_pPlayControl->m_hWnd,&rect);  
  355.     POINT point = {0,0};  
  356.     ::ClientToScreen(m_pPlayControl->m_hWnd,&point);  
  357.     rect.right = rect.right - rect.left + point.x;  
  358.     rect.left = point.x;  
  359.     rect.bottom = rect.bottom - rect.top + point.y;  
  360.     rect.top = point.y;  
  361.   
  362.     hr = m_lpDDSPrimary->Blt(&rect, m_lpDDSOverlay, NULL, DDBLT_WAIT, NULL);  
  363.     if (FAILED(hr))  
  364.         return ;  
  365. }  

运行截图如下:




补充说明:

对于DirectDraw创建Surface的时候,显卡内存模式支持的像素格式比系统内存支持像素格式要少。比方说这个例子里面直接初始化的是RGB32的像素格式的,而其实系统显卡通常默认是不支持的,但是软件Surface是支持的。为了获得更快的渲染效率,通常实际开发的时候还是采用系统显卡支持的像素格式,比如YUYV NV12等等。



多媒体编程——摄像头录像预览


1、 新建MFC工程,选择对话框工程。


2、新建一个static控件。


3、修改ID,并且在OnInitDialog里面获取指针。





4、加一个成员函数,并且在OnInitDialog里面调用,作为我们的例子代码的放置位置。





5、添加完整头文件


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <qedit.h>  
  2. #include <dshow.h>  
  3. #include <dxtrans.h>  
  4. #pragma comment(lib,"strmiids.lib")  
  5.    
  6. //DirectDraw  
  7. #include <ddraw.h>  
  8. #pragma comment(lib,"ddraw.lib")  
  9. #pragma comment(lib,"dxguid.lib")  

并且让Dialog同时继承类型 ISampleGrabberCB


6、添加读取摄像头的代码

摄像头读取,使用的是DirectXSDK中的DirectShow组件

 

需要编写的代码如下

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CCameraTestDlg::initCameraPreview()  
  2. {  
  3.     HRESULT hr = CoInitialize(NULL);  
  4.     if(FAILED(hr))  
  5.         return ;  
  6.   
  7.     IBaseFilter* pCameraFilter = NULL ;  
  8.   
  9.     //检查并加载系统摄像头。  
  10.     CComPtr <IMoniker> pMoniker =NULL;  
  11.     ULONG cFetched;  
  12.     CComPtr <ICreateDevEnum> pDevEnum =NULL;  
  13.     hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,IID_ICreateDevEnum, (void **) &pDevEnum);  
  14.     if (FAILED(hr))  
  15.         return ;  
  16.     CComPtr <IEnumMoniker> pClassEnum = NULL;  
  17.     hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);  
  18.     if (FAILED(hr))  
  19.         return ;  
  20.     if (pClassEnum == NULL)  
  21.         return ;  
  22.     if (SUCCEEDED(pClassEnum->Next (1, &pMoniker, &cFetched)))  
  23.     {  
  24.         hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pCameraFilter);  
  25.         if (FAILED(hr))  
  26.             return ;  
  27.     }  
  28.   
  29.     if(pCameraFilter == NULL)  
  30.         return ;  
  31.   
  32.     //加载DirectShow对象  
  33.     IGraphBuilder* pGraphBuilder = NULL ;  
  34.     hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,IID_IGraphBuilder, (void **) &pGraphBuilder);  
  35.     if (FAILED(hr))  
  36.         return ;  
  37.   
  38.     // Create the capture graph builder  
  39.     ICaptureGraphBuilder2* pCaptureGraphBuilder = NULL ;  
  40.     hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **) &pCaptureGraphBuilder);  
  41.     if (FAILED(hr))  
  42.         return ;  
  43.   
  44.     //Create sampleGrabber   
  45.     IBaseFilter* pSampleGrabberFilter = NULL ;  
  46.     hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC,IID_IBaseFilter, (void**)&pSampleGrabberFilter);  
  47.     if (FAILED(hr))  
  48.         return ;  
  49.   
  50.     ISampleGrabber* pSampleGrabber = NULL ;  
  51.     hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);  
  52.     if (FAILED(hr))  
  53.         return ;  
  54.   
  55.   
  56.     //设置视频格式  
  57.     AM_MEDIA_TYPE mt;  
  58.     ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));  
  59.     mt.majortype = MEDIATYPE_Video   ;  
  60.     mt.subtype   = MEDIASUBTYPE_RGB32;  
  61.   
  62.     hr = pSampleGrabber->SetMediaType(&mt);  
  63.     if (FAILED(hr))  
  64.         return ;  
  65.   
  66.     hr = pSampleGrabber->SetOneShot(FALSE);  
  67.     if (FAILED(hr))  
  68.         return ;  
  69.   
  70.     hr = pSampleGrabber->SetBufferSamples(FALSE);  
  71.     if (FAILED(hr))  
  72.         return ;  
  73.   
  74.     hr = pSampleGrabber->SetCallback(this, 1);  
  75.     if (FAILED(hr))  
  76.         return ;  
  77.   
  78.     // Obtain interfaces for media control and Video Window  
  79.     IMediaControl* pMediaControl = NULL ;  
  80.     hr = pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID *) &pMediaControl);  
  81.     if (FAILED(hr))  
  82.         return ;  
  83.   
  84.     // Attach the filter graph to the capture graph  
  85.     hr = pCaptureGraphBuilder->SetFiltergraph(pGraphBuilder);  
  86.     if (FAILED(hr))  
  87.         return ;  
  88.   
  89.     // Add Capture filter to our graph.  
  90.     hr = pGraphBuilder->AddFilter(pCameraFilter, L"Video Capture");  
  91.     if (FAILED(hr))  
  92.         return ;  
  93.   
  94.     hr = pGraphBuilder->AddFilter(pSampleGrabberFilter, L"Sample Grabber");  
  95.     if (FAILED(hr))  
  96.         return ;  
  97.   
  98.     //将摄像头和采集连接  
  99.     hr = pCaptureGraphBuilder->RenderStream(NULL,&MEDIATYPE_Video,pCameraFilter,NULL,pSampleGrabberFilter);  
  100.     if (FAILED(hr))  
  101.         return ;  
  102.   
  103.     //连接之后取得来源视频格式  
  104.     AM_MEDIA_TYPE amt;  
  105.     hr = pSampleGrabber->GetConnectedMediaType(&amt);  
  106.     if (FAILED(hr))  
  107.         return ;  
  108.   
  109.     //获取摄像头采集画面的分辨率  
  110.     int width = 0 ;  
  111.     int height = 0 ;  
  112.     VIDEOINFOHEADER* pVideoHeader = reinterpret_cast<VIDEOINFOHEADER*>(amt.pbFormat);  
  113.     if(pVideoHeader)  
  114.     {  
  115.         width = pVideoHeader->bmiHeader.biWidth ;  
  116.         height= pVideoHeader->bmiHeader.biHeight ;  
  117.   
  118.         if (amt.cbFormat != 0)  
  119.         {  
  120.             CoTaskMemFree((PVOID)mt.pbFormat);  
  121.             mt.cbFormat = 0;  
  122.             mt.pbFormat = NULL;  
  123.         }  
  124.         if (amt.pUnk != NULL)  
  125.         {  
  126.             mt.pUnk->Release();  
  127.             mt.pUnk = NULL;  
  128.         }  
  129.     }  
  130.     else  
  131.         return ;  
  132.     //调用run之后才真正开始得到图像。  
  133.     pMediaControl->Run();  
  134. }  
  135.   
  136. HRESULT CCameraTestDlg::SampleCB(double SampleTime,IMediaSample *pSample)  
  137. {  
  138.     return E_FAIL;  
  139. }  
  140. HRESULT CCameraTestDlg::BufferCB(double SampleTime,BYTE *pBuffer, long BufferLen)  
  141. {  
  142.     OutputDebugString(_T("BufferCB image data!\n"));  
  143.     return E_FAIL;  
  144. }  
  145. HRESULT CCameraTestDlg::QueryInterface(REFIID riid,void** ppvObject)  
  146. {  
  147.     return S_OK ;  
  148. }  
  149. ULONG CCameraTestDlg::AddRef(void)  
  150. {  
  151.     return 0 ;  
  152. }  
  153. ULONG CCameraTestDlg::Release(void)  
  154. {  
  155.     return 0 ;  
  156. }  

此刻运行,已经能看到OutputDebugString不停的输出了,说明已经获取到了数据。只不过还没添加渲染,看不到图像。


7、添加视频渲染初始化函数,initDrawVideo(int width, int height)


并且在初始化摄像头成功,获取了分辨率那个地方,调用它。


新增加一个渲染函数。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void DisplayLine(LPBYTE pBuf,int nPixelBytes)  

第一个参数是数据buf,第二个参数是字节数。

后面完整代码:



[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // CameraTestDlg.h : 头文件  
  2. //  
  3.   
  4. #pragma once  
  5.   
  6. //DirectShow  
  7. #include <qedit.h>  
  8. #include <dshow.h>  
  9. #include <dxtrans.h>  
  10. #pragma comment(lib,"strmiids.lib")  
  11.   
  12. //DirectDraw  
  13. #include <ddraw.h>  
  14. #pragma comment(lib,"ddraw.lib")  
  15. #pragma comment(lib,"dxguid.lib")  
  16.   
  17. // CCameraTestDlg 对话框  
  18. class CCameraTestDlg : public CDialog  
  19.                      , public ISampleGrabberCB  
  20. {  
  21. // 构造  
  22. public:  
  23.     CCameraTestDlg(CWnd* pParent = NULL);   // 标准构造函数  
  24.   
  25. // 对话框数据  
  26.     enum { IDD = IDD_CAMERATEST_DIALOG };  
  27.   
  28.     protected:  
  29.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  30.   
  31.   
  32. // 实现  
  33. protected:  
  34.     HICON m_hIcon;  
  35.   
  36.     // 生成的消息映射函数  
  37.     virtual BOOL OnInitDialog();  
  38.     afx_msg void OnPaint();  
  39.     afx_msg HCURSOR OnQueryDragIcon();  
  40.     DECLARE_MESSAGE_MAP()  
  41.   
  42. protected:  
  43.     CStatic*                 m_pPlayControl ;  
  44.   
  45.     LPDIRECTDRAW7            m_lpDDraw;   // DirectDraw 对象指针  
  46.     LPDIRECTDRAWSURFACE7     m_lpDDSOverlay ; // DirectDraw 离屏表面指针  
  47.     DDSURFACEDESC2           m_stOverlayDdsd;   // DirectDraw 表面描述  
  48.     LPDIRECTDRAWSURFACE7     m_lpDDSPrimary; // DirectDraw 主表面指针  
  49.     DDSURFACEDESC2           m_stPrimaryDdsd;   // DirectDraw 表面描述  
  50.     LPDIRECTDRAWCLIPPER      m_pDirectDrawCliper ;//  
  51.   
  52.     void  initCameraPreview() ;  
  53.     void  initDrawVideo(int width, int height);  
  54.     void  DisplayLine(LPBYTE pBuf,int nPixelBytes);  
  55. public:  
  56.     HRESULT STDMETHODCALLTYPE SampleCB(double SampleTime,IMediaSample *pSample);  
  57.     HRESULT STDMETHODCALLTYPE BufferCB(double SampleTime,BYTE *pBuffer, long BufferLen);  
  58.     HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,void**ppvObject);  
  59.     ULONG STDMETHODCALLTYPE AddRef(void);  
  60.     ULONG STDMETHODCALLTYPE Release(void);  
  61. };  

实现文件代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // CameraTestDlg.cpp : 实现文件  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include "CameraTest.h"  
  6. #include "CameraTestDlg.h"  
  7.   
  8. #ifdef _DEBUG  
  9. #define new DEBUG_NEW  
  10. #endif  
  11.   
  12.   
  13. // CCameraTestDlg 对话框  
  14.   
  15.   
  16.   
  17. CCameraTestDlg::CCameraTestDlg(CWnd* pParent /*=NULL*/)  
  18.     : CDialog(CCameraTestDlg::IDD, pParent)  
  19. {  
  20.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
  21. }  
  22.   
  23. void CCameraTestDlg::DoDataExchange(CDataExchange* pDX)  
  24. {  
  25.     CDialog::DoDataExchange(pDX);  
  26. }  
  27.   
  28. BEGIN_MESSAGE_MAP(CCameraTestDlg, CDialog)  
  29.     ON_WM_PAINT()  
  30.     ON_WM_QUERYDRAGICON()  
  31.     //}}AFX_MSG_MAP  
  32. END_MESSAGE_MAP()  
  33.   
  34.   
  35. // CCameraTestDlg 消息处理程序  
  36.   
  37. BOOL CCameraTestDlg::OnInitDialog()  
  38. {  
  39.     CDialog::OnInitDialog();  
  40.   
  41.     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动  
  42.     //  执行此操作  
  43.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  44.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  45.   
  46.     this->m_pPlayControl = (CStatic*)GetDlgItem(IDC_STATIC_PLAYCONTROL);  
  47.   
  48.     this->initCameraPreview();  
  49.   
  50.     return TRUE;  // 除非将焦点设置到控件,否则返回TRUE  
  51. }  
  52.   
  53. // 如果向对话框添加最小化按钮,则需要下面的代码  
  54. //  来绘制该图标。对于使用文档/视图模型的MFC 应用程序,  
  55. //  这将由框架自动完成。  
  56.   
  57. void CCameraTestDlg::OnPaint()  
  58. {  
  59.     if (IsIconic())  
  60.     {  
  61.         CPaintDC dc(this); // 用于绘制的设备上下文  
  62.   
  63.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  
  64.   
  65.         // 使图标在工作区矩形中居中  
  66.         int cxIcon = GetSystemMetrics(SM_CXICON);  
  67.         int cyIcon = GetSystemMetrics(SM_CYICON);  
  68.         CRect rect;  
  69.         GetClientRect(&rect);  
  70.         int x = (rect.Width() - cxIcon + 1) / 2;  
  71.         int y = (rect.Height() - cyIcon + 1) / 2;  
  72.   
  73.         // 绘制图标  
  74.         dc.DrawIcon(x, y, m_hIcon);  
  75.     }  
  76.     else  
  77.     {  
  78.         CDialog::OnPaint();  
  79.     }  
  80. }  
  81.   
  82. //当用户拖动最小化窗口时系统调用此函数取得光标  
  83. //显示。  
  84. HCURSOR CCameraTestDlg::OnQueryDragIcon()  
  85. {  
  86.     return static_cast<HCURSOR>(m_hIcon);  
  87. }  
  88.   
  89.   
  90. void CCameraTestDlg::initCameraPreview()  
  91. {  
  92.     HRESULT hr = CoInitialize(NULL);  
  93.     if(FAILED(hr))  
  94.         return ;  
  95.   
  96.     IBaseFilter* pCameraFilter = NULL ;  
  97.   
  98.     //检查并加载系统摄像头。  
  99.     CComPtr <IMoniker> pMoniker =NULL;  
  100.     ULONG cFetched;  
  101.     CComPtr <ICreateDevEnum> pDevEnum =NULL;  
  102.     hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,IID_ICreateDevEnum, (void **) &pDevEnum);  
  103.     if (FAILED(hr))  
  104.         return ;  
  105.     CComPtr <IEnumMoniker> pClassEnum = NULL;  
  106.     hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);  
  107.     if (FAILED(hr))  
  108.         return ;  
  109.     if (pClassEnum == NULL)  
  110.         return ;  
  111.     if (SUCCEEDED(pClassEnum->Next (1, &pMoniker, &cFetched)))  
  112.     {  
  113.         hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pCameraFilter);  
  114.         if (FAILED(hr))  
  115.             return ;  
  116.     }  
  117.   
  118.     if(pCameraFilter == NULL)  
  119.         return ;  
  120.   
  121.     //加载DirectShow对象  
  122.     IGraphBuilder* pGraphBuilder = NULL ;  
  123.     hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,IID_IGraphBuilder, (void **) &pGraphBuilder);  
  124.     if (FAILED(hr))  
  125.         return ;  
  126.   
  127.     // Create the capture graph builder  
  128.     ICaptureGraphBuilder2* pCaptureGraphBuilder = NULL ;  
  129.     hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **) &pCaptureGraphBuilder);  
  130.     if (FAILED(hr))  
  131.         return ;  
  132.   
  133.     //Create sampleGrabber   
  134.     IBaseFilter* pSampleGrabberFilter = NULL ;  
  135.     hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC,IID_IBaseFilter, (void**)&pSampleGrabberFilter);  
  136.     if (FAILED(hr))  
  137.         return ;  
  138.   
  139.     ISampleGrabber* pSampleGrabber = NULL ;  
  140.     hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);  
  141.     if (FAILED(hr))  
  142.         return ;  
  143.   
  144.   
  145.     //设置视频格式  
  146.     AM_MEDIA_TYPE mt;  
  147.     ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));  
  148.     mt.majortype = MEDIATYPE_Video   ;  
  149.     mt.subtype   = MEDIASUBTYPE_RGB32;  
  150.   
  151.     hr = pSampleGrabber->SetMediaType(&mt);  
  152.     if (FAILED(hr))  
  153.         return ;  
  154.   
  155.     hr = pSampleGrabber->SetOneShot(FALSE);  
  156.     if (FAILED(hr))  
  157.         return ;  
  158.   
  159.     hr = pSampleGrabber->SetBufferSamples(FALSE);  
  160.     if (FAILED(hr))  
  161.         return ;  
  162.   
  163.     hr = pSampleGrabber->SetCallback(this, 1);  
  164.     if (FAILED(hr))  
  165.         return ;  
  166.   
  167.     // Obtain interfaces for media control and Video Window  
  168.     IMediaControl* pMediaControl = NULL ;  
  169.     hr = pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID *) &pMediaControl);  
  170.     if (FAILED(hr))  
  171.         return ;  
  172.   
  173.     // Attach the filter graph to the capture graph  
  174.     hr = pCaptureGraphBuilder->SetFiltergraph(pGraphBuilder);  
  175.     if (FAILED(hr))  
  176.         return ;  
  177.   
  178.     // Add Capture filter to our graph.  
  179.     hr = pGraphBuilder->AddFilter(pCameraFilter, L"Video Capture");  
  180.     if (FAILED(hr))  
  181.         return ;  
  182.   
  183.     hr = pGraphBuilder->AddFilter(pSampleGrabberFilter, L"Sample Grabber");  
  184.     if (FAILED(hr))  
  185.         return ;  
  186.   
  187.     //将摄像头和采集连接  
  188.     hr = pCaptureGraphBuilder->RenderStream(NULL,&MEDIATYPE_Video,pCameraFilter,NULL,pSampleGrabberFilter);  
  189.     if (FAILED(hr))  
  190.         return ;  
  191.   
  192.     //连接之后取得来源视频格式  
  193.     AM_MEDIA_TYPE amt;  
  194.     hr = pSampleGrabber->GetConnectedMediaType(&amt);  
  195.     if (FAILED(hr))  
  196.         return ;  
  197.   
  198.     //获取摄像头采集画面的分辨率  
  199.     int width = 0 ;  
  200.     int height = 0 ;  
  201.     VIDEOINFOHEADER* pVideoHeader = reinterpret_cast<VIDEOINFOHEADER*>(amt.pbFormat);  
  202.     if(pVideoHeader)  
  203.     {  
  204.         width = pVideoHeader->bmiHeader.biWidth ;  
  205.         height= pVideoHeader->bmiHeader.biHeight ;  
  206.   
  207.         if (amt.cbFormat != 0)  
  208.         {  
  209.             CoTaskMemFree((PVOID)mt.pbFormat);  
  210.             mt.cbFormat = 0;  
  211.             mt.pbFormat = NULL;  
  212.         }  
  213.         if (amt.pUnk != NULL)  
  214.         {  
  215.             mt.pUnk->Release();  
  216.             mt.pUnk = NULL;  
  217.         }  
  218.     }  
  219.     else  
  220.         return ;  
  221.   
  222.     this->initDrawVideo(width, height);  
  223.   
  224.     pMediaControl->Run();  
  225. }  
  226.   
  227. HRESULT CCameraTestDlg::SampleCB(double SampleTime,IMediaSample *pSample)  
  228. {  
  229.     return E_FAIL;  
  230. }  
  231. HRESULT CCameraTestDlg::BufferCB(double SampleTime,BYTE *pBuffer, long BufferLen)  
  232. {  
  233.     this->DisplayLine(pBuffer, 32/8);  
  234.     return E_FAIL;  
  235. }  
  236. HRESULT CCameraTestDlg::QueryInterface(REFIID riid,void** ppvObject)  
  237. {  
  238.     return S_OK ;  
  239. }  
  240. ULONG CCameraTestDlg::AddRef(void)  
  241. {  
  242.     return 0 ;  
  243. }  
  244. ULONG CCameraTestDlg::Release(void)  
  245. {  
  246.     return 0 ;  
  247. }  
  248.   
  249.   
  250.   
  251.   
  252.   
  253. void CCameraTestDlg::initDrawVideo(int width, int height)  
  254. {  
  255.     HRESULT hr = DirectDrawCreateEx(NULL, (LPVOID*)&m_lpDDraw,IID_IDirectDraw7, NULL);  
  256.     if (FAILED(hr))  
  257.         return ;  
  258.   
  259.     // 设置协作层  
  260.     hr = m_lpDDraw->SetCooperativeLevel(this->m_hWnd, DDSCL_NORMAL);  
  261.     if (FAILED(hr))  
  262.         return ;  
  263.   
  264.     // 创建主表面  
  265.     ZeroMemory(&m_stPrimaryDdsd, sizeof(DDSURFACEDESC2));  
  266.     m_stPrimaryDdsd.dwSize = sizeof(DDSURFACEDESC2);  
  267.     m_stPrimaryDdsd.dwFlags = DDSD_CAPS ;  
  268.     m_stPrimaryDdsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;  
  269.     hr = m_lpDDraw->CreateSurface(&m_stPrimaryDdsd, &m_lpDDSPrimary, NULL);  
  270.     if (FAILED(hr))  
  271.         return ;  
  272.   
  273.     // 创建缓存表面  
  274.     ZeroMemory(&m_stOverlayDdsd, sizeof(DDSURFACEDESC2));  
  275.     m_stOverlayDdsd.dwSize = sizeof(DDSURFACEDESC2);  
  276.     m_stOverlayDdsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN ;  
  277.     m_stOverlayDdsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT ;  
  278.     m_stOverlayDdsd.dwWidth = width;  
  279.     m_stOverlayDdsd.dwHeight = height;  
  280.   
  281.     struct DDPIXELFORMATDEF : public DDPIXELFORMAT  
  282.     {  
  283.         DDPIXELFORMATDEF(UINT dwFlags,  
  284.             UINT dwFourCC = 0x0,  
  285.             UINT dwUnionBitCount = 0x0,  
  286.             UINT dwUnionBitMask1 = 0x0,UINT dwUnionBitMask2 = 0x0,  
  287.             UINT dwUnionBitMask3 = 0x0,UINT dwUnionBitMask4 = 0x0)  
  288.         {  
  289.             __super::dwFlags = dwFlags ;  
  290.             __super::dwFourCC = dwFourCC ;  
  291.             __super::dwRGBBitCount = dwUnionBitCount ;  
  292.             __super::dwRBitMask = dwUnionBitMask1 ;  
  293.             __super::dwGBitMask = dwUnionBitMask2 ;  
  294.             __super::dwBBitMask = dwUnionBitMask3 ;  
  295.             __super::dwRGBAlphaBitMask = dwUnionBitMask4 ;  
  296.         }  
  297.     };  
  298.   
  299.     //上面摄像头那里强制的设置的RGB32,则这里就使用RGB32。  
  300.     m_stOverlayDdsd.ddpfPixelFormat = DDPIXELFORMATDEF(DDPF_RGB,0x0,32,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000) ;  
  301.     m_stOverlayDdsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);  
  302.   
  303.     hr = m_lpDDraw->CreateSurface(&m_stOverlayDdsd, &m_lpDDSOverlay, NULL);  
  304.     if (FAILED(hr))  
  305.     {  
  306.         m_stOverlayDdsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN ;//使用内存再次尝试创建。  
  307.         hr = m_lpDDraw->CreateSurface(&m_stOverlayDdsd, &m_lpDDSOverlay, NULL);  
  308.         if (FAILED(hr))  
  309.             return  ;  
  310.     }  
  311.   
  312.     hr = m_lpDDraw->CreateClipper(0,&m_pDirectDrawCliper,NULL);  
  313.     if (FAILED(hr))  
  314.         return ;  
  315.   
  316.     hr = m_pDirectDrawCliper->SetHWnd(0,this->m_pPlayControl->m_hWnd);  
  317.     if (FAILED(hr))  
  318.         return ;  
  319.   
  320.     hr = m_lpDDSPrimary->SetClipper(m_pDirectDrawCliper);  
  321.     if (FAILED(hr))  
  322.         return ;  
  323. }  
  324.   
  325. void CCameraTestDlg::DisplayLine(LPBYTE pBuf,int nPixelBytes)  
  326. {  
  327.     HRESULT     hr;   // DirectDraw 函数返回值  
  328.   
  329.     hr = m_lpDDSOverlay->Lock(NULL,&m_stOverlayDdsd,DDLOCK_WAIT|DDLOCK_WRITEONLY,NULL);  
  330.     if (FAILED(hr))  
  331.         return ;  
  332.   
  333.     LPBYTE p_YUV_RGB = pBuf ;  
  334.   
  335.     int dwByteCountPerLine = m_stOverlayDdsd.dwWidth*nPixelBytes; //m_stOverlayDdsd.ddpfPixelFormat.dwRGBBitCount/8 ;  
  336.   
  337.     //摄像头读取的画面上下是反过来的,这个就自己处理了,就在下面的循环里处理就好了。  
  338.     LPBYTE lpSurface = (LPBYTE)m_stOverlayDdsd.lpSurface;  
  339.     if(lpSurface)  
  340.     {  
  341.         for (int i=0;i<m_stOverlayDdsd.dwHeight;i++)  
  342.         {  
  343.             memcpy(lpSurface, p_YUV_RGB, dwByteCountPerLine);  
  344.             p_YUV_RGB += dwByteCountPerLine;  
  345.             lpSurface += m_stOverlayDdsd.lPitch;  
  346.         }  
  347.     }  
  348.   
  349.     hr = m_lpDDSOverlay->Unlock(NULL);  
  350.     if (FAILED(hr))  
  351.         return ;  
  352.   
  353.     RECT rect;  
  354.     ::GetClientRect(m_pPlayControl->m_hWnd,&rect);  
  355.     POINT point = {0,0};  
  356.     ::ClientToScreen(m_pPlayControl->m_hWnd,&point);  
  357.     rect.right = rect.right - rect.left + point.x;  
  358.     rect.left = point.x;  
  359.     rect.bottom = rect.bottom - rect.top + point.y;  
  360.     rect.top = point.y;  
  361.   
  362.     hr = m_lpDDSPrimary->Blt(&rect, m_lpDDSOverlay, NULL, DDBLT_WAIT, NULL);  
  363.     if (FAILED(hr))  
  364.         return ;  
  365. }  

运行截图如下:




补充说明:

对于DirectDraw创建Surface的时候,显卡内存模式支持的像素格式比系统内存支持像素格式要少。比方说这个例子里面直接初始化的是RGB32的像素格式的,而其实系统显卡通常默认是不支持的,但是软件Surface是支持的。为了获得更快的渲染效率,通常实际开发的时候还是采用系统显卡支持的像素格式,比如YUYV NV12等等。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Delphi 7 是一个集成开发环境(IDE),可用于开发Windows操作系统上的应用程序。如果需要在 Delphi 7 中使用摄像头进行录像,可以通过引用相应的组件来实现。 首先,需要使用一个适用于 Delphi 7 的视频捕获组件,例如Delphi VCL 的 TVideoCapture 组件。这个组件可以让我们方便地访问摄像头并进行视频捕获。 在使用 TVideoCapture 组件之前,需要确保已安装摄像头的驱动程序,并确保摄像头可以正常工作。 接下来,我们可以创建一个 Delphi 7 的窗体应用程序,并在窗体上放置一个按钮和一个显示视频的组件,例如一个 TImage 组件。 在按钮的 OnClick 事件中,我们可以进行一些初始化操作,例如设置视频捕获的分辨率、帧率等。然后,调用 TVideoCapture 组件的 Start 方法开始视频捕获。 在每一帧视频捕获完成后,可以在 TVideoCapture 的 OnNewVideoFrame 事件中进行处理,例如将捕获到的视频帧显示在 TImage 组件上。 如果需要停止录像,可以在按钮的 OnClick 事件中调用 TVideoCapture 的 Stop 方法停止视频捕获。 需要注意的是,使用摄像头进行录像可能还涉及到一些其他的功能,例如录音、编码、保存等。在 Delphi 7 中,可能需要使用其他组件或函数库来实现这些功能。 总结起来,使用 Delphi 7 进行摄像头录像首先要引用适合的视频捕获组件,然后在应用程序中进行初始化、开始和停止视频捕获,并在每一帧视频捕获完成后进行处理。 ### 回答2: 在Delphi7中,可以使用DirectShow和简单的代码来实现摄像头录像。首先,需要使用TFilterGraph和TFilterDisplay组件来连接摄像头录像器。接下来,使用TMediaControl组件来控制录像、停止和保存录像文件。以下是一个简单的例子代码: ``` var FilterGraph: TFilterGraph; FilterDisplay: TFilterDisplay; MediaControl: TMediaControl; procedure TForm1.FormCreate(Sender: TObject); begin FilterGraph := TFilterGraph.Create(nil); FilterDisplay := TFilterDisplay.Create(nil); MediaControl := TMediaControl.Create(nil); FilterGraph.GraphBuilder := CoFilterGraph.Create; FilterDisplay.FilterGraph := FilterGraph; MediaControl.FilterGraph := FilterGraph; end; procedure TForm1.btnRecordClick(Sender: TObject); begin if not MediaControl.Running then begin FilterGraph.ClearGraph; FilterGraph.RenderPreviewGraph(nil, nil); if FilterGraph.RenderCameraURL('摄像头URL') then begin FilterGraph.RenderCaptureGraph(nil, nil); FilterGraph.StartPreview; FilterGraph.RecordFromFile('保存录像文件路径', true); end; end; end; procedure TForm1.btnStopClick(Sender: TObject); begin if MediaControl.Running then begin FilterGraph.StopPreview; MediaControl.Stop; FilterGraph.ClearGraph; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin FilterGraph.Free; FilterDisplay.Free; MediaControl.Free; end; ``` 需要替换上述代码中的'摄像头URL'为摄像头的URL地址,'保存录像文件路径'为要保存录像文件的路径。 以上就是在Delphi7中使用DirectShow进行摄像头录像的简单例子。使用Delphi7可以灵活操作DirectShow组件库来控制摄像头录像功能。 ### 回答3: Delphi 7 是一款编程语言,可以用来开发窗体应用程序。如果想要在 Delphi 7 中实现摄像头录像功能,可以借助第三方库来实现。 一种常用的方式是使用 DirectShow 组件,它是一个用于多媒体处理的 API,可以在 Delphi 程序中控制摄像头和视频录制。首先,需要在 Delphi 7 中导入 DirectShow 组件库。然后,可以使用 TFilterGraph 和 TFilterGraph 构件来创建一个过滤器图形,用于捕获摄像头的视频数据。接下来,可以使用 TSampleGrabber 组件来捕获视频帧,并将其保存到文件中。具体的代码可以参考 DirectShow 的文档和示例。 另一种常用的方式是使用开源库如 OpenCV,它是一个强大的计算机视觉库,支持多种视频捕获和处理功能。可以在 Delphi 7 中集成 OpenCV 库,并使用其提供的函数来控制摄像头和进行视频录制。首先,需要在 Delphi 7 中导入 OpenCV 库,并进行相关配置。然后,可以使用 OpenCV 提供的函数来打开摄像头并开始录制视频。可以设置录制帧率、分辨率和保存路径等参数,具体的代码可以参考 OpenCV 的文档和示例。 不管是使用 DirectShow 还是 OpenCV,都需要在 Delphi 7 中编写相应的代码来调用相关函数和组件,实现摄像头的打开、视频的捕获和保存等功能。具体的实现方式取决于具体需求和环境。希望上述信息对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值