10.3攝像頭捕捉示例c++
10.3.1攝像頭捕捉概述app
如今不少嵌入式電腦、智能手機上都配有內置攝像頭,用戶能夠很是方便地使用攝像頭進行監控視頻、錄像視頻以及抓拍圖片。微軟提供了一套WDM視頻採集流驅動標準,大多廠家也都遵循此標準,這樣就使開發人員開發上端應用程序很是方便。封裝成視頻採集過濾器(Fiker),此Filter -般會包含最基本的捕捉Pin和靜態捕捉Pin.還能夠包含預覽Piri,這樣就可使開發人員基於DSHOW技術很是方便地開發上端應用程序。如圖10-10所示的是視頻過濾器鏈接圖。ide
圖10-10視頻捕捉過濾器鏈接圖函數
DSHOW提供了一個輔助組件Capture Graph Builder,使用Capture Oraph Builder組件將會很是方便地建立視頻捕捉過濾器,Capture Graph Builder組件在DSHOW中採用ICaptureGraphBuilder2接口實現。開發視頻捕捉應用程序的第1步就是調用CoCreatelnstance建立Capture Graph Builder組件和Filter Graph Manager組件,如圖10-11所示。ui
圖10-11建立Capture Graph Builder組件和Filter Graph Manager組件this
將Capture Oraph Builer組件和Filter Graph Manager組件關聯起來,即初始化Capter GraphBuilder組件。調用ICaptureGraphBuilder2接口的SetFilterGraph方法,將Filter Graph Manager對象指針設置給它,具體示意如圖10-12所示。編碼
圖 10-12初始化Capter Graph Builder組件spa
下面將經過攝像頭捕捉示例來詳細介紹如何使用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小節
本章主要講解了多媒體播放與視頻捕獲的多媒體開發,讀者須要認真實踐工程代碼案例,以便在本身開發應用程序的時候可以駕輕就熟。