10.3摄像头捕捉示例
10.3.1摄像头捕捉概述
现在很多嵌入式电脑、智能手机上都配有内置摄像头,用户可以非常方便地使用摄像头进行监控视频、录像视频以及抓拍图片。微软提供了一套WDM视频采集流驱动标准,大多厂家也都遵循此标准,这样就使开发人员开发上端应用程序非常方便。封装成视频采集过滤器(Fiker),此Filter -般会包含最基本的捕捉Pin和静态捕捉Pin.还可以包含预览Piri,这样就可以使开发人员基于DSHOW技术非常方便地开发上端应用程序。如图10-10所示的是视频过滤器连接图。
图10-10视频捕捉过滤器连接图
DSHOW提供了一个辅助组件Capture Graph Builder,使用Capture Oraph Builder组件将会非常方便地创建视频捕捉过滤器,Capture Graph Builder组件在DSHOW中采用ICaptureGraphBuilder2接口实现。开发视频捕捉应用程序的第1步就是调用CoCreatelnstance创建Capture Graph Builder组件和Filter Graph Manager组件,如图10-11所示。
图10-11创建Capture Graph Builder组件和Filter Graph Manager组件
将Capture Oraph Builer组件和Filter Graph Manager组件关联起来,即初始化Capter GraphBuilder组件。调用ICaptureGraphBuilder2接口的SetFilterGraph方法,将Filter Graph Manager对象指针设置给它,具体示意如图10-12所示。
图 10-12初始化Capter Graph Builder组件
下面将通过摄像头捕捉示例来详细介绍如何使用DSHOW技术来预览视频、录像视频文件以及拍照。
10.3.2摄像头捕捉示倒
(1)建立新项目。使用VS2008 MFC智能设备应用程序向导创建一个基于对话框的应用程序CameraDemo,编译环境设置为yinchengOSSDK。
(2)新建CPropertyBag类,用于实现IPropertyBag接口。由于在后面会调用IPropertyBag接口来设置摄像头设备的相关属性,如指定视频捕捉设备名等,因此在这里要先实现IPropertyBag接口,本接口的实现完全参考Microsogt中的DEMO.CProperWBag类的定义如下所示。
#pragma once
struct VAR_LIST
{
VARIANT var;
VAR_LIST *pNext;
BSTR pBSTRName;
};
class CPropertyBag : public IPropertyBag
{
public:
CPropertyBag();
~CPropertyBag();
HRESULT STDMETHODCALLTYPE
Read(
LPCOLESTR pszPropName,
VARIANT *pVar,
IErrorLog *pErrorLog
);
HRESULT STDMETHODCALLTYPE
Write(
LPCOLESTR pszPropName,
VARIANT *pVar
);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
private:
ULONG _refCount;
VAR_LIST *pVar;
};
CPropertyBag类的实现如下所示。
#include "StdAfx.h"
#include "PropertyBag.h"
#include <Ocidl.h>
#include <oleauto.h>
//构造函数
CPropertyBag::CPropertyBag() : _refCount(1), pVar(0)
{
}
//析构函数
CPropertyBag::~CPropertyBag()
{
VAR_LIST *pTemp = pVar;
HRESULT hr = S_OK;
while(pTemp)
{
VAR_LIST *pDel = pTemp;
VariantClear(&pTemp->var);
SysFreeString(pTemp->pBSTRName);
pTemp = pTemp->pNext;
delete pDel;
}
}
//属性读方法
HRESULT STDMETHODCALLTYPE
CPropertyBag::Read(LPCOLESTR pszPropName,
VARIANT *_pVar,
IErrorLog *pErrorLog)
{
VAR_LIST *pTemp = pVar;
HRESULT hr = S_OK;
while(pTemp)
{
if(0 == wcscmp(pszPropName, pTemp->pBSTRName))
{
hr = VariantCopy(_pVar, &pTemp->var);
break;
}
pTemp = pTemp->pNext;
}
return hr;
}
//属性写方法
HRESULT STDMETHODCALLTYPE
CPropertyBag::Write(LPCOLESTR pszPropName,
VARIANT *_pVar)
{
HRESULT hr = S_OK;
VAR_LIST *pTemp = new VAR_LIST();
ASSERT(pTemp);
if( !pTemp )
{
return E_OUTOFMEMORY;
}
VariantInit(&pTemp->var);
pTemp->pBSTRName = SysAllocString(pszPropName);
pTemp->pNext = pVar;
pVar = pTemp;
return VariantCopy(&pTemp->var, _pVar);
}
ULONG STDMETHODCALLTYPE
CPropertyBag::AddRef()
{
return InterlockedIncrement((LONG *)&_refCount);
}
ULONG STDMETHODCALLTYPE
CPropertyBag::Release()
{
ASSERT(_refCount != 0xFFFFFFFF);
ULONG ret = InterlockedDecrement((LONG *)&_refCount);
if(!ret)
delete this;
return ret;
}
HRESULT STDMETHODCALLTYPE
CPropertyBag::QueryInterface(REFIID riid, void** ppv)
{
if(!ppv)
return E_POINTER;
if(riid == IID_IPropertyBag)
*ppv = static_cast<IPropertyBag*>(this);
else
return *ppv = 0, E_NOINTERFACE;
return AddRef(), S_OK;
}
(3)新建CEricCamera类,用于封装摄像头视频操作。
CEricCamera类是一个通用c++类,无基类。其类图如图10-13所示。
图 10-13CEricCamera类是一个通用c++类
CEricCamera类中将提供6个共有方法。
·OetFirstCameraDriver方法用于获取系统中注册的第一个视频捕捉设备名,以便指定后面要预览、捕捉的是哪个摄像头。
·FreeDShow方法用于释放创建的DirectShow接口对象。
·PreviewCamera方法是最为重要的,此方法的直接效果是在窗体上预览视频。在此方法里还做了大量视频过滤器的创建以及相关接口的初始化、渲染工作,例如创建视频捕捉过滤器,并指定录像文件编码格式以及创建静态捕捉STILL PIN。这里需要注意的是,在进行录像、抓拍前,要确保先调用PreviewCamera方法,因为此方法还负责DirectShow接口的初始化工作。
·StartRecard方法和StopRecord方法分别用于开始录像和停止录像,这里录像采用的是WMV9 DMO Encoder编码方式。
·SnapPicture方法用于抓拍视频中的一幅图片,并保存到文件中,这里图像的文件格式为JPG。
下面来介绍CEricCamera类的创建过程。
1)为CEricCamera类添加DShow接口私有变量,这些接口将综合起来实现摄像头视频的预览、录像、抓拍等助能,具体定义如下:
#pragma once
#include <streams.h>
#include <dmodshow.h>
#include <dmoreg.h>
#include <wmcodecids.h>
class CEricCamera
{
public:
CEricCamera(void);
~CEricCamera(void);
private:
//-----DSHOW接口-----------
//视频捕捉图形管理器接口
CComPtr<ICaptureGraphBuilder2> m_pCaptureGraphBuilder;
//图形管理器接口
CComPtr<IGraphBuilder> m_pGraphBuilder;
//视频捕捉过滤器
CComPtr<IBaseFilter> m_pVideoCaptureFilter;
//视频设备属性页
CComPtr<IPersistPropertyBag> m_pPropertyBag ;
//静态捕捉PIN过滤器
CComPtr<IBaseFilter> m_pImageSinkFilter;
//媒体播放控制器
CComPtr<IMediaControl> m_pMediaControl ;
//视频窗口接口
CComPtr<IVideoWindow> m_pVideoWindow ;
//视频播放进度控制接口
CComPtr<IMediaSeeking> m_pMediaSeeking;
//媒体事件接口
CComPtr<IMediaEvent> m_pMediaEvent;
public:
//释放DSHOW接口
void FreeDShow();
public:
//查找第1个摄像头设备名
BOOL GetFirstCameraDriver( WCHAR *pwzName );
public:
//预览视频
BOOL PreviewCamera(HWND hVideoWnd /*视频显示窗口*/
,LPCTSTR strFileName /*录像文件名*/);
public:
//开始录像
BOOL StartRecord();
//停止录像
BOOL StopRecord();
public:
//抓拍
BOOL SnapPicture(LPCTSTR strFileName /*图象文件名,格式为JPG*/);
};
所以应包含如下DSHOW头文件
#include <wmcodecids.h>
另外,在工程中,应添加dmoguids.lib和strmiids.lib两个静态库链接。具体操作为选择“CameraDemo属性页”一“链接器”一“输入”一“附加依赖项”,输入dmoguids.lib strmiids.lib。这里再定义CHK和ERR两个宏函数,用于DSHOW接口方法返回值的判断。这两个宏函数的定义如下:
#define CHKtx) do{ if (FAILED(hResult - (x))){goto Cleanup;}}whileIFALSEl;
#define ERR(x}do{ hResult -xj goto Cleanup;} while(FALSE);
2)为CEricCamera类添加FreeDShow私有方法,用于释放创建的DShow对象。该函数的定义如下;
public:
//释放DSHOW接口
void FreeDShow()j
FreeDShow方法的实现如程序清单10-14所示。
void CEricCamera::FreeDShow()
{
//释放IMediaControl接口
if (m_pMediaControl != NULL)
{
m_pMediaControl->Stop();
m_pMediaControl.Release();
m_pMediaControl = NULL;
}
//释放IPropertyBag接口
if (m_pPropertyBag != NULL)
{
m_pPropertyBag.Release();
m_pPropertyBag = NULL;
}
//释放IVideoWindow接口
if (m_pVideoWindow != NULL)
{
//隐藏视频窗口
m_pVideoWindow->put_Visible(OAFALSE);
//设置视频播放窗口句柄为空
m_pVideoWindow->put_Owner(NULL);
m_pVideoWindow.Release();
m_pVideoWindow = NULL;
}
//释放IMediaSeeking接口
if (m_pMediaSeeking != NULL)
{
m_pMediaSeeking.Release();
m_pMediaSeeking = NULL;
}
//释放IMediaEvent接口
if (m_pMediaEvent != NULL)
{
m_pMediaEvent.Release();
m_pMediaEvent = NULL;
}
//释放IVideoCaptureFilter接口
if (m_pVideoCaptureFilter != NULL )
{
m_pVideoCaptureFilter.Release();
m_pVideoCaptureFilter = NULL;
}
//释放IImageSinkFilter接口
if (m_pImageSinkFilter != NULL )
{
m_pImageSinkFilter.Release();
m_pImageSinkFilter = NULL;
}
//释放IGraphBuilder接口
if (m_pGraphBuilder != NULL)
{
m_pGraphBuilder.Release();
m_pGraphBuilder = NULL;
}
//释放ICaptureGraphBuilder2接口
if (m_pCaptureGraphBuilder != NULL)
{
m_pCaptureGraphBuilder->SetFiltergraph(NULL);
m_pCaptureGraphBuilder.Release();
m_pCaptureGraphBuilder = NULL;
}
}
3)实现CEricCamera类的构造函数和析构函数。在构造函数里初始化COM环境;在析构函数里释放COM接口,并释放COM环境。
CEricCamera类构造函数和析构函数的实现如下所示。
//构造函数
CEricCamera::CEricCamera(void)
{
//初始化 COM 环境
CoInitialize(NULL);
}
//析构函数
CEricCamera::~CEricCamera(void)
{
//释放DSHOW接口
FreeDShow();
//释放COM 环境
CoUninitialize();
}
4)添加GetFirstCameraDriver方法,用于获取第一个视频采集设备名。在嵌入式电脑中,一般默认只会有1个注册的视频采集设备,默认名一般为CAMI:。但是有些嵌入式电脑中,也可能注册多个视频采集设备。这些注册的视频采集设备可以是实际的摄像头.也可以是虚拟的摄像头。GetFirstCameraDriver方法用于获取系统中注册的第一个视频采集设备名,定义如下:
public:
//查找第一个摄像头设备名
BOOL GetFirstCameraDriver( WCHAR *pwzName );
GetFirstCameraDriver方法的实现如下所示。
/*
*函数介绍: 查找第1个摄像头设备
*入口参数: pwzName : 存储摄像头设备名称,应提前分配好内存
*出口参数:pwzName :存储摄像头设备名称
*返回值:TRUE:成功;FALSE:失败
*/
BOOL CEricCamera::GetFirstCameraDriver( WCHAR *pwzName )
{
HRESULT hr = S_OK;
HANDLE handle = NULL;
DEVMGR_DEVICE_INFORMATION di;
GUID guidCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A, 0x93, 0x3E, 0x4D, 0x7E, 0x3C, 0x86 };
if( pwzName == NULL )
{
return FALSE;
}
di.dwSize = sizeof(di);
//查到第1个摄像头设备
handle = FindFirstDevice( DeviceSearchByGuid, &guidCamera, &di );
if(( handle == NULL ) || ( di.hDevice == NULL ))
{
FindClose( handle );
return FALSE;
}
//复制设备名
StringCchCopy( pwzName, MAX_PATH, di.szLegacyName );
//关闭查找设备
FindClose( handle );
return TRUE;
}
5)添加PreviewCamera方法,用于初始化和预览视频。在PreviewCamera方法中建立了整个视频捕捉链图,包括预览视频过滤器、捕捉视频过滤器以及抓拍静态图过滤器。此方法是CEricCamera类的核心,理解了此方法,也就大概了解了视频捕捉程序的流程。
在实现此函数之前,先添加对CPropertyBag类的引用。
tinclude”PropertyBag.h”
PreviewCamera方法的定义如下:
public:
//预览视频
BOOL PreviewCamera(HWND hVideoWnd ,LPCTSTR strFileName /*录像文件名*/);
PreviewCamera方法的实现如下所示。
/*
*函数介绍: 初始化DSHOW接口,并预览视频
*入口参数: hVideoWnd : 显示视频的窗口句柄
strFileName :录像文件名
*出口参数:(无)
*返回值:TRUE:成功;FALSE:失败
*/
BOOL CEricCamera::PreviewCamera(HWND hVideoWnd /*视频显示窗口*/
,LPCTSTR strFileName /*录像文件名*/)
{
HRESULT hResult = S_FALSE;
LONGLONG dwStart = 0, dwEnd = 0;
WORD wStartCookie = 1, wEndCookie = 2;
CRect rectVideo; //视频窗口尺寸
CComVariant varCamName; //定义摄像头设备名称
WCHAR wzDeviceName[ MAX_PATH + 1 ]; //摄像头设备名称
CPropertyBag PropBag; //摄像头属性页
//--定义录像用到的编码、写文件等FILTER
CComPtr<IBaseFilter> pVideoEncoder;
CComPtr<IBaseFilter> pASFMultiplexer;
CComPtr<IFileSinkFilter> pFileSinkFilter;
CComPtr<IDMOWrapperFilter> pWrapperFilter;
//默认先释放DSHOW接口
FreeDShow();
//1,创建ICaptureGraphBuilder2接口,用于管理媒体捕捉对象
CHK(m_pCaptureGraphBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder));
//2,创建IGraphBuilder接口
CHK(m_pGraphBuilder.CoCreateInstance(CLSID_FilterGraph));
//3,
CHK(m_pCaptureGraphBuilder->SetFiltergraph(m_pGraphBuilder ));
//4,得到IMediaControl接口,用于控制流播放
CHK(m_pGraphBuilder.QueryInterface(&m_pMediaControl));
//5,得到IMediaSeeking接口,用于设置播放位置
CHK(m_pGraphBuilder.QueryInterface(&m_pMediaSeeking));
//6,得到m_pMediaEvent接口,用于获取媒体事件
CHK(m_pGraphBuilder.QueryInterface(&m_pMediaEvent));
//7,创建视频捕捉Filter
CHK(m_pVideoCaptureFilter.CoCreateInstance(CLSID_VideoCapture));
//8,得到视频捕捉属性页接口
CHK(m_pVideoCaptureFilter->QueryInterface(&m_pPropertyBag ));
//9,选择视频捕捉设备
//得到第1个视频捕捉设备名。
if (!GetFirstCameraDriver( wzDeviceName ))
{
goto Cleanup;
}
varCamName = wzDeviceName;
if(( varCamName.vt == VT_BSTR ) == NULL ) {
return FALSE;
}
//设置视频捕捉为第1个捕捉设备
PropBag.Write( L"VCapName", &varCamName );
CHK(m_pPropertyBag->Load( &PropBag, NULL ));
//10,将视频捕捉FILTER添加到FILTER图中。
CHK(m_pGraphBuilder->AddFilter( m_pVideoCaptureFilter, L"Video capture source" ));
//11,创建IDMOWrapperFilter接口
CHK(pVideoEncoder.CoCreateInstance( CLSID_DMOWrapperFilter ));
CHK(pVideoEncoder.QueryInterface( &pWrapperFilter ));
//12,加载WMV9 DMO
CHK(pWrapperFilter->Init( CLSID_CWMV9EncMediaObject, DMOCATEGORY_VIDEO_ENCODER ));
// 13,将编码器FILTER加入到过滤器图中
CHK(m_pGraphBuilder->AddFilter( pVideoEncoder, L"WMV9 DMO Encoder" ));
//14,创建ASF多路(复用)器,并加入到过滤器图中
CHK(m_pCaptureGraphBuilder->SetOutputFileName( &MEDIASUBTYPE_Asf,strFileName, &pASFMultiplexer, &pFileSinkFilter ));
//15,渲染预览视频PIN
CHK(m_pCaptureGraphBuilder->RenderStream( &PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video, m_pVideoCaptureFilter,
NULL, NULL ));
//16,设置视频预览窗口
CHK(m_pGraphBuilder.QueryInterface(&m_pVideoWindow));
////设置视频播放的WINDOWS窗口
m_pVideoWindow->put_Owner((OAHWND)hVideoWnd);
m_pVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
//设置视频尺寸
GetClientRect(hVideoWnd,&rectVideo);
m_pVideoWindow->SetWindowPosition(0,0,rectVideo.Width(),rectVideo.Height());
m_pVideoWindow->put_Visible(OATRUE);
//17,渲染捕捉PIN, 用于录像
CHK(m_pCaptureGraphBuilder->RenderStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoCaptureFilter, pVideoEncoder, pASFMultiplexer ));
//18,创建Still Pin,用于抓图
CHK(m_pImageSinkFilter.CoCreateInstance(CLSID_IMGSinkFilter));
CHK(m_pGraphBuilder->AddFilter(m_pImageSinkFilter, L"Still image filter" ));
CHK(m_pCaptureGraphBuilder->RenderStream( &PIN_CATEGORY_STILL, &MEDIATYPE_Video, m_pVideoCaptureFilter, NULL, m_pImageSinkFilter ));
//19,设置捕捉流暂停
CHK(m_pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoCaptureFilter, 0, 0 ,0,0 ));
//20,预览视频
CHK(m_pMediaControl->Run());
Sleep(1000);
Cleanup:
//释放接口
if (pVideoEncoder != NULL)
{
pVideoEncoder.Release();
pVideoEncoder = NULL;
}
if (pASFMultiplexer != NULL)
{
pASFMultiplexer.Release();
pASFMultiplexer = NULL;
}
if (pFileSinkFilter != NULL)
{
pFileSinkFilter.Release();
pFileSinkFilter = NULL;
}
if (pWrapperFilter != NULL)
{
pWrapperFilter.Release();
pWrapperFilter = NULL;
}
if( FAILED( hResult ))
{
return FALSE;
}
else
{
return TRUE;
}
}
StartRecord和StopRecord方法的实现如下所示。
/*
*函数介绍:开始录像
*入口参数: (无)
*出口参数:(无)
*返回值:TRUE:成功;FALSE:失败
*/
BOOL CEricCamera::StartRecord()
{
LONGLONG dwStart = 0, dwEnd = 0;
WORD wStartCookie = 1, wEndCookie = 2;
HRESULT hResult = 0;
if( m_pCaptureGraphBuilder == NULL )
{
return FALSE;
}
//开始录制
dwStart=0;
dwEnd=MAXLONGLONG;
hResult = m_pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, NULL, &dwStart, &dwEnd, wStartCookie, wEndCookie );
TRACE(L"开始录制\n");
if( FAILED( hResult ))
{
return FALSE;
}
else
{
return TRUE;
}
}
/*
*函数介绍:停止录像
*入口参数: (无)
*出口参数:(无)
*返回值:TRUE:成功;FALSE:失败
*/
BOOL CEricCamera::StopRecord()
{
HRESULT hResult = S_OK;
LONGLONG dwStart = 0, dwEnd = 0;
WORD wStartCookie = 1, wEndCookie = 2;
LONG lEventCode = 0;
LONG lParam1 = 0;
LONG lParam2 = 0;
if( m_pCaptureGraphBuilder == NULL )
{
return FALSE;
}
//停止视频捕捉流,并存入到文件中
dwStart = 0;
hResult = m_pMediaSeeking->GetCurrentPosition( &dwEnd );
hResult = m_pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, NULL, &dwStart, &dwEnd, wStartCookie, wEndCookie );
//检测录像文件生成结束
while (true)
{
m_pMediaEvent->GetEvent( &lEventCode, &lParam1, &lParam2, INFINITE );
m_pMediaEvent->FreeEventParams( lEventCode, lParam1, lParam2 );
if( lEventCode == EC_STREAM_CONTROL_STOPPED ) {
TRACE(L"录像停止\n");
break;
}
}
//
if( FAILED( hResult ))
{
return FALSE;
}
else
{
return TRUE;
}
}
7)掭加SnapPicture方法,用于拍照并保存为JPG图像文件。SnapPicture方法的定义如下。
public:
//抓拍
BOOL CEricCamera::SnapPicture(LPCTSTR strFileName /*图象文件名,格式为JPG*/);
SnapPicture方法实现如下所示。
/*
*函数介绍:抓拍
*入口参数: strFileName:抓拍保存的文件名,图象格式为JPG.
*出口参数:(无)
*返回值:TRUE:成功;FALSE:失败
*/
BOOL CEricCamera::SnapPicture(LPCTSTR strFileName /*图象文件名,格式为JPG*/)
{
HRESULT hResult = S_FALSE;
CComPtr<IFileSinkFilter> pFileSink;
CComPtr<IUnknown> pUnkCaptureFilter;
CComPtr<IPin> pStillPin;
CComPtr<IAMVideoControl> pVideoControl;
if( m_pCaptureGraphBuilder == NULL )
{
goto Cleanup;
}
//得到IFileSinkFilter接口
CHK( m_pImageSinkFilter.QueryInterface( &pFileSink ));
//设置抓拍保存的图象文件名
CHK( pFileSink->SetFileName( strFileName, NULL ));
//得到StillPin
CHK( m_pVideoCaptureFilter.QueryInterface( &pUnkCaptureFilter ));
CHK( m_pCaptureGraphBuilder->FindPin( pUnkCaptureFilter, PINDIR_OUTPUT, &PIN_CATEGORY_STILL, &MEDIATYPE_Video, FALSE, 0, &pStillPin ));
//设置抓拍动作
CHK( m_pVideoCaptureFilter.QueryInterface( &pVideoControl ));
CHK( pVideoControl->SetMode( pStillPin, VideoControlFlag_Trigger ));
Cleanup:
//释放DSHOW接口
if (pFileSink != NULL)
{
pFileSink.Release();
pFileSink = NULL;
}
if (!pUnkCaptureFilter != NULL)
{
pUnkCaptureFilter.Release();
pUnkCaptureFilter = NULL;
}
if (pStillPin != NULL)
{
pStillPin.Release();
pStillPin = NULL;
}
if (pVideoControl != NULL)
{
pVideoControl.Release();
pVideoControl = NULL;
}
if( FAILED( hResult ))
{
return FALSE;
}
else
{
return TRUE;
}
}
至此,CEricCamera类就实现完毕了。下面可以非常方便地基于此类来演示如何预览摄像头视频、录像、抓拍等操作。
1)设计主窗口,演示摄像头视频预览、录像、抓拍功能。
2)为CCameraDemoDlg类添加m_Camera成员变量,类型为之前创建的CEricCamera类。
定义如下:
private:
CEricCamera m_Camera; //摄像头控制类
备注:由于引用了CEricCamera类,因此要在CameraDemoDlg.h文中件添加对CEricCamera类定义文件的引用。
tlnclude "EricCamera.h”
3)实现“预览”按钮单击事件,用于初始化摄像头,并预览视频。具体代码清单如下所示。
//预览视频
void CCameraDemoDlg::OnBnClickedBtnPreview()
{
CWnd *pVideoWnd = (CWnd*)GetDlgItem(IDC_WND_VIDEO);
m_Camera.PreviewCamera(pVideoWnd->m_hWnd,L"\\EricVideo.asf");
}
4)实现“抓拍”按钮单击事件,用于将视频中的一帧图片抓拍并保存到文件中。具体代码如程序清单如下所示。
//抓拍图片
void CCameraDemoDlg::OnBnClickedBtnSnap()
{
//定义媒体播放文件名
CString strFileName;
TCHAR szFilters[]= _T("Image File (*.jpg)|*.jpg||");
CFileDialog fileDlg (FALSE, _T("Save Image files"), _T("\\My Documents\\"),
OFN_OVERWRITEPROMPT , szFilters, this);
//打开文件选择对话框
if( fileDlg.DoModal () !=IDOK )
{
return;
}
//得到要保存的图象文件名
strFileName = fileDlg.GetPathName();
//抓拍
m_Camera.SnapPicture(strFileName);
}
5)实现“录像”按钮单击事件。在“录像”按钮单击事件中,首先开始录制视频,然后启用定时器,5秒后,停止录像。因此这里只录制了5秒的视频。“录像”按钮单击事件的实现如下所示.
//录像
void CCameraDemoDlg::OnBnClickedBtnRecord()
{
if (m_Camera.StartRecord())
{
//启动定时器,录制5秒视频
SetTimer(1,5000,NULL);
}
}
这里启用了定时器来终止录像,因此要先实现WINDOWS定时器WM_TIMER函数。定时器函数的实现如下所示。
//5秒后停止录像
void CCameraDemoDlg::OnTimer(UINT_PTR nIDEvent)
{
KillTimer(1);
if (m_Camera.StopRecord())
{
AfxMessageBox(L"录像完毕");
}
else
{
AfxMessageBox(L"录像失败");
}
CDialog::OnTimer(nIDEvent);
}
至此,摄像头示例就实现完毕了。
将该程序编译成可执行文件,启动Windows Embedded Compact 7虚拟机,复制到共享目录,执行之。如图10-14
图10-14选择运行程序运行之
效果如图10-15
图10-15程序效果图
在虚拟机上共享USB串口,挂接一个摄像头,截取个美女的照片,如下图10-16
所示
图10-16程序效果图
10.4小节
本章主要讲解了多媒体播放与视频捕获的多媒体开发,读者需要认真实践工程代码案例,以便在自己开发应用程序的时候能够得心应手。