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小节 本章主要讲解了多媒体播放与视频捕获的多媒体开发,读者需要认真实践工程代码案例,以便在自己开发应用程序的时候能够得心应手。 |
|
来自: BeautymengRoom > 《wince6.0》