Visual C++编程实现摄像头视频捕捉
原文:http://blog.csdn.net/nemojiang/article/details/653033?locationNum=7&fps=1
前言
DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,与DirectX开发包一起发布。DirectShow为多媒体流的捕捉和回放提供了强有力的支持。用DirectShow开发应用程序,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。
DirectShow是基于COM的,为了编写DirectShow应用程序,需要了解COM客户程序编写的基础知识。DirectShow提供了大量的接口,但在编程中发现还是不够方便,如果能构建一个视频捕捉类把常用的一些动作封装起来,那么就更方便了。
编程思路
为了更加容易建立视频捕捉应用程序,DirectShow提供了一个叫做Capture Graph Builder的对象,Capture Graph Builder提供IcaptureGraphBuilder2接口,该接口可以建立和控制Capture Graph。
建立视频捕捉程序,必须首先获取并初始化IcaptureGraphBuilder2接口,然后选择一个适当的视频捕捉设备。选择好设备后,为该设备创建Capture filter,然后调用AddFilter把Capture filter添加到Filter Graph。
如果仅仅希望用摄像头来进行实时监控的话,只需要在上面的基础上调用ICaptureGraphBuilder2::RenderStream就可以了:
| ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder //省略初始化部分代码 IBaseFilter *pCap; // Video capture filter. //省略初始化和添加到Filter Graph部分代码 pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL); |
DirectShow提供了一个捕捉静态图像的方法:使用Sample Grabber filter。依次按照以下三个步骤就可以了:
第一步, 定义一个类实现Sample Grabber的回调接口IsampleGrabberCB:
| class CSampleGrabberCB : public ISampleGrabberCB { //在后面提供的类中具体完成 } CSampleGrabberCB mCB; |
第二步、调用RenderStream依次把Still pin、Sample Grabber和系统默认Renderer Filter连接起来。
第三步、配置Sample Grabber以捕获数据。
视频捕捉类CCaptureVideo的具体实现
| // CCaptureVideo视频捕捉类头文件 ///////////////////////////////////////////////////////////////////// #if !defined(AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCLUDED_) #define AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCLUDED_ ///////////////////////////////////////////////////////////////////// // CaptureVideo.h : header file ///////////////////////////////////////////////////////////////////// #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <atlbase.h> #include <windows.h> #include <dshow.h> #ifndef SAFE_RELEASE #define SAFE_RELEASE( x ) / if ( NULL != x ) / { / x->Release( ); / x = NULL; / } #endif class CSampleGrabberCB; class CCaptureVideo : public CWnd { friend class CSampleGrabberCB; public: void GrabOneFrame(BOOL bGrab); HRESULT Init(int iDeviceID,HWND hWnd); int EnumDevices(HWND hList); CCaptureVideo(); virtual ~CCaptureVideo(); private: HWND m_hWnd; IGraphBuilder *m_pGB; ICaptureGraphBuilder2* m_pCapture; IBaseFilter* m_pBF; IMediaControl* m_pMC; IVideoWindow* m_pVW; CComPtr<ISampleGrabber> m_pGrabber; protected: void FreeMediaType(AM_MEDIA_TYPE& mt); bool BindFilter(int deviceId, IBaseFilter **pFilter); void ResizeVideoWindow(); HRESULT SetupVideoWindow(); HRESULT InitCaptureGraphBuilder(); }; #endif // !defined(AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCLUDED_) //------------------------------------------------------------------- // CCaptureVideo视频捕捉类实现文件CaptureVideo.cpp //------------------------------------------------------------------- // CaptureVideo.cpp: implementation of the CCaptureVideo class. // ///////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "CaptureVideo.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif BOOL bOneShot=FALSE;//全局变量 class CSampleGrabberCB : public ISampleGrabberCB { public: long lWidth; long lHeight; TCHAR m_szFileName[MAX_PATH];// 位图文件名称 CSampleGrabberCB( ){ strcpy(m_szFileName, "c://donaldo.bmp"); } STDMETHODIMP_(ULONG) AddRef() { return 2; } STDMETHODIMP_(ULONG) Release() { return 1; } STDMETHODIMP QueryInterface(REFIID riid, void ** ppv){ if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ){ *ppv = (void *) static_cast<ISampleGrabberCB*> ( this ); return NOERROR; } return E_NOINTERFACE; } STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample ){ return 0; } STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ){ if( !bOneShot )return 0; if (!pBuffer)return E_POINTER; SaveBitmap(pBuffer, lBufferSize); bOneShot = FALSE; return 0; } //创建位图文件 BOOL SaveBitmap(BYTE * pBuffer, long lBufferSize ) { HANDLE hf = CreateFile( m_szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL ); if( hf == INVALID_HANDLE_VALUE )return 0; // 写文件头 BITMAPFILEHEADER bfh; memset( &bfh, 0, sizeof( bfh ) ); bfh.bfType = ’MB’; bfh.bfSize = sizeof( bfh ) + lBufferSize + sizeof( BITMAPINFOHEADER ); bfh.bfOffBits = sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER ); DWORD dwWritten = 0; WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL ); // 写位图格式 BITMAPINFOHEADER bih; memset( &bih, 0, sizeof( bih ) ); bih.biSize = sizeof( bih ); bih.biWidth = lWidth; bih.biHeight = lHeight; bih.biPlanes = 1; bih.biBitCount = 24; WriteFile( hf, &bih, sizeof( bih ), &dwWritten, NULL ); // 写位图数据 WriteFile( hf, pBuffer, lBufferSize, &dwWritten, NULL ); CloseHandle( hf ); return 0; } }; CSampleGrabberCB mCB; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCaptureVideo::CCaptureVideo() { //COM Library Intialization if(FAILED(CoInitialize(NULL))) /*, COINIT_APARTMENTTHREADED)))*/ { AfxMessageBox("CoInitialize Failed!/r/n"); return; } m_hWnd = NULL; m_pVW = NULL; m_pMC = NULL; m_pGB = NULL; m_pCapture = NULL; } CCaptureVideo::~CCaptureVideo() { // Stop media playback if(m_pMC)m_pMC->Stop(); if(m_pVW){ m_pVW->put_Visible(OAFALSE); m_pVW->put_Owner(NULL); } SAFE_RELEASE(m_pCapture); SAFE_RELEASE(m_pMC); SAFE_RELEASE(m_pGB); SAFE_RELEASE(m_pBF); CoUninitialize( ); } int CCaptureVideo::EnumDevices(HWND hList) { if (!hList) return -1; int id = 0; //枚举视频扑捉设备 if (hr != NOERROR)return -1; if (hr != NOERROR)return -1; //设置视频格式 if( FAILED( hr ) ){ // try to render preview/capture pin if( FAILED( hr ) ){ VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat; //设置视频捕捉窗口 // enumerate all video capture devices HRESULT CCaptureVideo::InitCaptureGraphBuilder() // 创建IGraphBuilder接口 |
如何使用视频捕捉类CCaptureVideo
构建CCaptureVideo类以后,使用就方便多了,我们在编程中只需要是要下面三个类成员函数就可以实现用摄像头进行视频捕捉:
①int EnumDevices(HWND hList); //hList是下拉列表框的句柄,本函数用于枚举当前系统安装的所有视频捕捉设备
②HRESULT Init(int iDeviceID,HWND hWnd);//iDeviceID是视频捕捉设备序号,hWnd是视频捕捉窗口的句柄
③void GrabOneFrame(BOOL bGrab);//调用GrabOneFrame(true)就可以捕获当前的静态图像并保存到硬盘上
具体示例:用MFC AppWizard(exe)创建一个对话框应用程序,取名为ds,给对话框添加一个下拉列表框(IDC_COMBO1)、两个按钮(IDC_PHOTO、IDC_HAVEALOOK)和一个Picture控件(ID:IDC_STATIC_SCREEN,Type: Rectangle,Color:Gray)。
1、使用向导添加成员变量
| CStatic m_staticScreen; // IDC_STATIC_SCREEN CComboBox m_ListCtrl; // IDC_COMBO1 CCaptureVideo m_cap; |
2、为BOOL CDsDlg::OnInitDialog()添加如下代码:
| // TODO: Add extra initialization here m_cap.EnumDevices (m_ListCtrl); m_ListCtrl.SetCurSel (0); |
3、为确定按钮添加代码如下:
| void CDsDlg::OnOK() { //只需要四行代码就可以进行视频捕捉了 UpdateData(); HWND hWnd = m_staticScreen.GetSafeHwnd() ; HRESULT hr = m_cap.Init(m_ListCtrl.GetCurSel (),hWnd); GetDlgItem(IDOK)->EnableWindow(FALSE); } |
4、如果希望捕捉静态图像,为照相按钮添加如下代码:
| void CDsDlg::OnPhoto() { m_cap.GrabOneFrame(true); } |
运行程序时,选定摄像头后只需要按确定就可以了,实际效果如下图所示:
结束语
本文提供的视频捕捉类CcaptureVideo和示例,在Win2K + DirectX9 SDK + VC6 环境下调试通过。注意:编译时需要Strmiids.lib Quartz.lib两个库文件(DirectX9 SDK自带)。
Visual C++编程实现摄像头视频捕捉的更多相关文章
- 摄像头视频捕捉(简单通用--通过IsampleGrabberCB实现)
前言 DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,与DirectX开发包一起发布.DirectShow为多媒体流的捕捉和回放提供了强有力的支持.用Direct ...
- Delphi - 利用DLL编程控制摄像头实现拍照、录制视频
Delphi利用avicap32.dll编程控制摄像头实现拍照.录制视频 项目需求:平板电脑(Windows系统)一维/二维码扫描功能: 需求分析: 需要扫描一维/二维码时,分两步实现. 第一步,av ...
- 视频处理控件TVideoGrabber视频捕捉设设备相关问题
选择一个视频捕捉设备 首先设置 VideoSource = vs_VideoCaptureDevice来选择一个视频捕捉设备作为一个视频源. 通过指定VideoDevice属性来选择当前的视频捕捉设备 ...
- 视频捕捉全教程(vc+vfw)
目 录 一. 视频捕获快速入门 二.基本的捕获设置 1.设置捕获速度: 2.设置终止捕获 3.捕获的时间限制 三.关于捕获窗口 1.创建一个AVICAP捕获窗口 2.将一个捕获窗口连接至捕获设备 3. ...
- VirtualDub - 开源视频捕捉及线性处理软件
VirtualDub是一个开放源代码的视频捕捉及线性处理软件.它由Avery Lee编写,遵循GPL协议.VirtualDub可以通过摄像头捕捉视频. 官方网站http://virtualdub.or ...
- Direcshow中视频捕捉和参数设置报告
Direcshow中视频捕捉和参数设置报告 1. 关于视频捕捉(About Video Capture in Dshow) 1视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图 ...
- Direcshow之视频捕捉<转>
关于视频捕捉(About Video Capture in Dshow) 1. 视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图都称之为捕捉graph图.捕捉graph图比一般的文件回 ...
- Direcshow中视频捕捉和參数设置报告
Direcshow中视频捕捉和參数设置报告 1. 关于视频捕捉(About Video Capture in Dshow) 1视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图 ...
- Linux v4l2编程(摄像头信息采集)
基于Linux3.4.2,自己做一点儿视频信息采集及网络传输的小实验,边做边学,一些基础知识同步整理..... 1. 定义 V4L2(Video For Linux Two) 是内核提供给应用程序访问 ...
随机推荐
- python高级(六)——用一等函数实现设计模式
本文主要内容 经典的“策略”模式 python高级——目录 文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级 ...
- tomcat下各个文件夹的作用
1.bin目录:这个文件夹包含的是启动/关闭tomcat的脚本,里面有startup.sh(Linux环境下启动tomcat脚本)和startup.bat(Windows环境下启动tomcat脚本), ...
- JAVA中 this关键字的用法
this 在类中就是代表当前对象,可以通过 this 关键字完成当前对象的成员属性.成员方法和构造方法的调用. 那么何时用 this? 当在定义类中的方法时,如果需要调用该类对象,就可以用 this来 ...
- proxyTable设置跨域
如何设置跨域 1.在config--index.js 中配置 proxyTable: { '/api': { target: 'http://www.xxx.com', //目标接口域名 change ...
- golang io.ReadFull
buf := make([]byte, 10, 10) file, _ := os.Open("./data.txt") n, err := io.ReadFull(file, b ...
- setSelectionRange方法解决光标错位问题
inputElement.setSelectionRange(value.length, value.length);
- [原]SuperMap GIS(JavaScript) 拉框放大和缩小功能实现
版权声明:本文为博主原创文章,未经博主允许不得转载. var ZoomControl; /* * 拉框缩小 */ function ZoomOut(){ if(ZoomControl==null||Z ...
- Mac 下安装mysqldb 问题:一条命令解决mysql_config not found
遇到过几次pip安装mysql-python的时候出现如题的问题,在这里记录一下解决方法. 找不到mysql_config一般是由于通过lnmp.org或者其他方式安装mysql以后mysql_con ...
- jmeter(2)——元件简介、作用域及执行顺序
上一篇主要介绍了一下 jmeter还有安装配置,这一篇来说一下它的目录组成和元件 1.目录组成 1>bin目录是可执行文件,双击jmeter.bat启动工具,也可以编辑这个批处理文件,设置jvm ...
- no jpeg in java.library.path;java.lang.NoClassDefFoundError: Could not initialize class sun.awt.image.codec.JPEGImageEncoderImpl
no jpeg in java.library.path;java.lang.NoClassDefFoundError: Could not initialize class sun.awt.imag ...