Windows Embedded Compact 7中的多媒體編程(下)

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.libstrmiids.lib兩個靜態庫連接。具體操做爲選擇「CameraDemo屬性頁」一「連接器」一「輸入」一「附加依賴項」,輸入dmoguids.lib strmiids.lib。這裏再定義CHKERR兩個宏函數,用於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;

}

}

StartRecordStopRecord方法的實現如下所示。

/*

*函數介紹:開始錄像

*入口參數: ()

*出口參數:()

*返回值: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小節

本章主要講解了多媒體播放與視頻捕獲的多媒體開發,讀者須要認真實踐工程代碼案例,以便在本身開發應用程序的時候可以駕輕就熟。

相關文章
相關標籤/搜索