Visual+C++視頻技術(shù)方案寶典_第1頁
Visual+C++視頻技術(shù)方案寶典_第2頁
Visual+C++視頻技術(shù)方案寶典_第3頁
Visual+C++視頻技術(shù)方案寶典_第4頁
已閱讀5頁,還剩441頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第二章視頻采集方案視頻采集是開發(fā)視頻監(jiān)控系統(tǒng)的首要步驟,它關(guān)系到采集視頻數(shù)據(jù)的質(zhì)量,因此,視頻采集會影響到其后的各種操作(包括視頻預(yù)覽、視頻錄像、視頻回放、圖像識別等)。本章將從VFW(VideoForWindows,Windows視頻)ヽDirectShow和SDK(SoftwareDevelopmentKit,軟件開發(fā)包)3個方面介紹視頻采集的解決方案。視頻采集方案分析在開發(fā)視頻監(jiān)控系統(tǒng)時,通常有3種視頻采集的方法。分別為VFW、DirectShow和SDK。其中,VFW是ー種較老的視頻采集方法,它是Microsoft提供的數(shù)字視頻軟件包,提供了一組庫函數(shù),能夠?qū)崿F(xiàn)視頻捕捉、影像壓縮及影像播放等功能。使用VFW的優(yōu)點是它隨從Windows操作系統(tǒng)ー起安裝,可執(zhí)行文件不需要附帶額外的庫文件就可以運行,但是許多監(jiān)控卡不支持VFW,因此,在開發(fā)專業(yè)的監(jiān)控系統(tǒng)時很少使用VFW技術(shù)。DirectShow是Microsoft推出的流媒體開發(fā)包,使用它可以在支持WDM驅(qū)動的各種監(jiān)控卡上采集數(shù)據(jù),因此,使用DirectShow可以開發(fā)通用的視頻監(jiān)控程序。DirectShow支持ASF、MPEG、AV!、MP3、WAV等多種媒體格式,使得它很容易實現(xiàn)媒體數(shù)據(jù)的采集、回放。SDK是監(jiān)控卡廠家提供的開發(fā)視頻監(jiān)控系統(tǒng)的ー組庫函數(shù),使用SDK庫函數(shù),用戶可以在不了解視頻壓縮、回放、網(wǎng)絡(luò)傳輸?shù)燃夹g(shù)的前提下,進(jìn)行視頻程序開發(fā)(SDK中通常都包含了這些技術(shù)的實現(xiàn))。但是,由于不同廠家提供的監(jiān)控卡SDK并不兼容,因此編寫的應(yīng)用程序無法移植到新的環(huán)境中。VFW視頻采集方案VFW是Microsoft于1992年推出的數(shù)字視頻軟件包,它不依賴于專用的硬件設(shè)備,提供了通用的數(shù)字視頻開發(fā)方案。VFW主要由AVICap.dll、MSVideo.dlkMQAvi.drv、AVIHIe.dlkvfw32.lib等庫文件組成,這些庫提供了相關(guān)視頻、音頻、AV!文件的函數(shù),本節(jié)將介紹如何利用這些函數(shù)進(jìn)行視頻采集。開發(fā)流程分析

VFW使用的視頻函數(shù)被封裝在vfw32.lib庫文件中,該庫文件默認(rèn)情況下沒有被連接到MFC工程中,因此使用VFW進(jìn)行視頻開發(fā)的第一步是導(dǎo)入vfw32.lib庫文件。方法如下:(1)引用vfw.h頭文件。#include"vfw.h"(2)導(dǎo)入vfw32.lib庫文件。#pragmacomment(Iib,"vfw32")步驟2也可以在通過工程選項窗D的連接選項卡進(jìn)行設(shè)置。如圖2.1所示。連接vfw32.lib庫文件圖2.1工程選項窗口在導(dǎo)入vfw32.lib庫文件后便可以使用視頻函數(shù)了。苜先調(diào)用capCreateCaptureWindow函數(shù)創(chuàng)建具有W2POPUP風(fēng)格的視頻捕捉窗口。然后調(diào)用capDriverConnect函數(shù)連接驅(qū)動程序,設(shè)置視頻捕捉窗口的大小、顯示位置。最后調(diào)用capPreviewRate函數(shù)設(shè)置預(yù)覽速率,調(diào)用capPreview函數(shù)進(jìn)行視頻預(yù)覽??偨Y(jié)上述流程分析,VFW視頻捕捉開發(fā)流程具體步驟如下:(1)引用“vfw.h”頭文件并導(dǎo)入vfw32.lib庫。(2)創(chuàng)建一個線程,在線程函數(shù)中調(diào)用capCreateCaptureWindow創(chuàng)建視頻捕捉窗口。(3)調(diào)用capDriverConnect連接驅(qū)動程序,設(shè)置視頻捕捉窗口風(fēng)格、大小及父窗口。

(4)調(diào)用capPreviewRate函數(shù)設(shè)置預(yù)覽速度,調(diào)用capPreview函數(shù)開始預(yù)覽。視頻窗口創(chuàng)建在進(jìn)行視頻程序開發(fā)時,第一步需要創(chuàng)建一個視頻預(yù)覽窗口。在程序中可以使用capCreateCapturewindow函數(shù)來創(chuàng)建視頻預(yù)覽窗ロ,該函數(shù)語法如ド:HWNDVFWAPIcapCreateCaptureWindow(LPCSTRIpszWindowName,DWORDdwStyle,intx,inty,intnWidth,intnHeight,HWNDhWnd,intnID);參數(shù)說明:IpszWindowName:表示視頻捕捉窗口的名稱。dwStyle:表示視頻捕獲窗口的風(fēng)格,一般包含有WS_CHILD和W^VISIBLE風(fēng)格。x、y:表示視頻捕捉窗口的左上角坐標(biāo)。nWidth、nHeight:表示視頻捕捉窗口的寬度和高度。hWnd:表示視頻捕捉窗ロ父窗口的句柄。nID:表示視頻捕捉窗口標(biāo)識。在創(chuàng)建視頻捕捉窗口之后,需要將其顯示在對話框中的適當(dāng)位置??梢栽趯υ捒蛑蓄A(yù)先放置一個靜態(tài)文本控件,調(diào)整其大小和位置,然后將視頻捕捉窗口放置在該控件的位置處就可以了。例如:m_Captured=FALSE;m_hWndVideo=capCreateCaptureWindow(NULL,WS_POPUP,1,1,10,10,m_hWnd,0);::SetParent(m_hWndVideo,*this);::SetWindowLong(m_hWndVideo,GWL_SrYLE,WS^CHILD);CRectwndRC;m_Panel.GetQientRect(wndRC);m_Panel.MapWindowPoints(this,wndRC);wndRC.DefIateRect(1,1,1,1);::SetWindowPos(m_hWndVideo,NULL,wndRC.left,wndRC.top,wndRC.Width(),wndRC.Height(),SWP_NOZORDER);

::ShowWindow(m_hWndVideo,SW_SHOW);視頻預(yù)覽實現(xiàn)在開發(fā)視頻應(yīng)用程序時,第一步需要實現(xiàn)的功能便是視頻預(yù)覽。在2.2.1節(jié)中筆者曾分析了視頻預(yù)覽的實現(xiàn)過程,下面以ー個具體實例來說明VFW視頻預(yù)覽的實現(xiàn)過程。效果如圖2.2所示。程序開發(fā)程序開發(fā)明日科技宋坤劉蛻寧圖2.2視頻預(yù)覽實現(xiàn)程序設(shè)計步驟如下:嗡實例位置:光盤'm列2\2.2\2.2.3\01(1)創(chuàng)建一個基于對話框的工程,在對話框中添加Picture控件,如圖2.3所示。

圖2.3視頻預(yù)覽設(shè)計窗口(2)在類向?qū)У?MemberVariables"選項卡中為Picture控件命名,如圖2.4所示。圖2.4類向?qū)Т翱?3)在對話框的頭文件中引用“vfw.h”頭文件,然后鏈接“vfw32.lib”庫文件。include"vfw.h"pragmacomment(Iib,"vfw32")(4)在對話框中定義ー個視頻預(yù)覽窗口的句柄。HWNDm_hWndVideo;〃視頻顯示窗口

(5)在對話框初始化時創(chuàng)建視頻預(yù)覽窗口,連接視頻驅(qū)動程序,設(shè)置預(yù)覽幀率,開始視頻預(yù)覽。BOOLCVideoPreviewDIg::OnlnitDialog()(CDialog::OnlnitDialog();ASSERT((IDM_ABOL)TBOX&OxFFFO)==IDM_ABOL)TBOX);ASSEFU(IDM_ABOUTBOX<OxFOOO);CMenu*pSysMenu=GetSystemMenu(FALSE);if(pSysMenu!=NULL)(CStringstrAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if(IstrAboutMenu.lsEmptyO){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF^STRING,IDM_ABOUTBOX,strAboutMenu);})Setlcon(m_hlcon,TRUE);Setlcon(m_hlcon,FALSE);〃創(chuàng)建預(yù)覽窗口m_hWndVideo=capCreateCaptureWindow(NULL,WS_POPUP,1,1,10,10,m_hWnd,0);〃連接驅(qū)動程序if(capDriverConnect(m_hWndVideo,0))(::SetParent(m_hWndVideo,*this);::SetWindowLong(m_hWndVideo,GWL^STYLE,WS_CHILD);CRectwndRC;

m_Panel.GetQientRect(wndRC);m_Ranel.MapWindowPoints(this,wndRC);wndRC.DeflateRect(1,1,1,1);::SetWindowPbs(m_hWndVideo,NULL,wndRC.Ieft,wndRC.top,wndRC.Width(),wndRC.Height(),SWP_NOZORDER);::ShowWindow(m_hWndVideo,SW_SHOW);capPreviewRate(m_hWndVideo,30);capPreview(m_hWndVideo,TRUE);}returnTRUE;)(6)在對話框關(guān)閉時斷開視頻驅(qū)動程序。voidCVideoPreviewDlg::OnCancel(){〃斷開驅(qū)動程序連接capDriverDisconnect(m_hWndVideo);CDialog::OnCancel();)捕捉參數(shù)設(shè)置在進(jìn)行視頻捕捉時,通常需要設(shè)置視頻捕捉參數(shù)。VFW提供了capCaptureSetSetup函數(shù)用于設(shè)置視頻捕捉參數(shù),該函數(shù)語法如下:BOOLcapCaptureSetSetup(HWNDhwnd,LPCAPTUREPARMSpsCapParms.UINTwSze);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。psCapParms:表示視頻捕捉參數(shù),該參數(shù)是CAFTUREPARMS結(jié)構(gòu)指針。CAPTUREPARMS結(jié)構(gòu)成員描述如表2.1所示。

表2.1CAFTUREPARMS結(jié)構(gòu)成員描述成員名稱成員類型描述dwRequestMicroSecPerFrameDWORD以毫秒為單位設(shè)置捕捉幀率,默認(rèn)值為66667,即每秒15幀fMakeUserHitOKToCaptureBOOL如果為TRUE,將顯示?個對話框幫助用戶快速地進(jìn)行捕捉設(shè)置wPerentDropForErrorUINT在捕捉過程中允許棄幀的最大百分比fYieldBOOL如果為TRUE,將產(chǎn)生一個后臺線程來進(jìn)行視頻捕捉dwIndexSzeDWORD表示AVI文件最大的索引入口數(shù)wChunkGranularityUINT以字節(jié)為單位表示AV!文件的大小fUsingDOSMemoryBOOL未使用wNumVideoRequestedUINT分配視頻緩沖區(qū)的加大數(shù)量fCaptureAudioBOOL為TRUE,表示音頻被捕捉,默認(rèn)值依賴ア安裝的咅頻設(shè)備wNumAudioRequestedUINT表示分配的音頻緩沖Iメ的最大數(shù)量vKeyAbortUINT表示終止捕捉的虛擬鍵fAbortLeftMouseBOOL為TRUE,表示單擊鼠標(biāo)左鍵停止捕捉fAbortRightMouseBOOL為TRUE,表示單擊鼠標(biāo)右鍵停止捕捉fUmitEnabledBOOL為TRUE,表示設(shè)置捕捉時間限制wTimeLimitUINT以秒為單位設(shè)置捕捉的超時時間fMCIControlBOOL為TRUE,控制MCI(媒體設(shè)備接口)兼容的視頻源fStepMCIDeviceBOOL為TRUE,使用MC!設(shè)備使用步進(jìn)幀進(jìn)行捕捉,為FALSE,使用MQ設(shè)備進(jìn)行時時捕捉,如果fMQControl成員為FALSE,該成員被忽略dwMQStartTimeDWORD以毫秒為單位標(biāo)識MC(設(shè)備視頻捕捉序列的起始位置,如果fMCICont⑹成員為FALSE,該成員被忽略dwMQStopTimeDWORD以毫秒為單位標(biāo)識MC!設(shè)備視頻捕捉序列的停止位置,如果fMCIControl成員為FALSE,該成員被忽略fStepCaptureAt2xBOOL為TRUE,捕捉的視頻幀使用兩個分辨率,它可以使用軟件在某個分辨率的基礎(chǔ)I:改”像素,將其該為髙清晰度的圖像wStepCaptureAverageFramesUINT在捕捉時每幀圖像使用的時間大小dwAudioBufferSzeDWORD咅頻緩沖區(qū)大小fDisableWriteCacheBOOL未使用AVStreamMasterUINT確定在寫入AVI文件時,咅頻流是否控制時鐘wSize:表示psCapParms參數(shù)的大小。在進(jìn)行視頻捕捉時,通常會根據(jù)實際需要設(shè)置捕捉參數(shù)。例如,在視頻錄像時,通常會將fYield成員設(shè)置為TRUE,啟動后臺線程來進(jìn)行視頻錄像,這樣,前臺用戶依然可以進(jìn)行其他界面有關(guān)操作?;卣{(diào)函數(shù)設(shè)計

在開發(fā)視頻應(yīng)用程序時,可以為視頻捕捉窗口設(shè)計ー些回調(diào)函數(shù),這樣,當(dāng)視頻應(yīng)用程序的某些狀態(tài)改變時,可以在回調(diào)函數(shù)中進(jìn)行處理。VFW提供了如下的函數(shù)進(jìn)行回調(diào)函數(shù)注冊。capSetCalIbackOnCapControl該函數(shù)提供了視頻捕捉時精確地控制捕捉開始和結(jié)束的時間。語法如下:BOOLcapSetCallbackOnCapControl(HWNDhwnd,CAPOONTROLCALLBACKfpProc);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。fpProc:表示視頻捕捉冋調(diào)函數(shù)指針,其定義如下:typedefLRESULT(CALLBACK*CAPOONTROLCALLBACK)(HWNDhWnd,intnState);其中,hWnd表示視頻捕捉窗口句柄,nState參數(shù)如果設(shè)置為OONTROLCALLBACK_PREROLL,表示將要開啟視頻源,為OONTROLCALLBACK_CAPTURING,表示應(yīng)用程序允許通過返回FALSE去結(jié)束視頻捕捉。capSetCalIbackOnError該函數(shù)用于為客戶端應(yīng)用程序設(shè)置錯誤處理的回調(diào)函數(shù)。語法如下:BOOLcapSetCallbackOnError(HWNDhwnd,CAPERRORCALLBACKAfpProc);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。fpProc:表示錯誤處理的回調(diào)函數(shù)指針,其定義如下:typedefLRESULT(CALLBACK*CAPERRORCALLBACKA)(HWNDhWnd,intnID,LPCSTRIpsz);其中,hWnd表示視頻捕捉窗口句柄,nID表示消息ID,Ipsz表示消息文本描述。capSetCalIbackOnFrame該函數(shù)用于設(shè)置預(yù)覽回調(diào)函數(shù),回調(diào)函數(shù)在預(yù)覽幀之前調(diào)用。語法如下:BOOLcapSetCallbackOnFrame(HWNDhwnd,CAPVIDEOCALLBACKfpProc);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。fpProc:表示預(yù)覽回調(diào)函數(shù)指針,其定義如下:

typedefLRESULT(CALLBACK*CAPVIDEOCALLBACK)(HWNDhWnd,LPVIDEOHDRIpVHdr);其中,hWnd表示視頻捕捉窗口句柄,IpVHdr是ー個VIDEOHDR結(jié)構(gòu)指針,表示視頻數(shù)據(jù)頭。capSetCalIbackOnStatus該函數(shù)用于在程序中設(shè)置ー個狀態(tài)回調(diào)函數(shù)。語法如下:BOOLcapSetCallbackOnStatus(HWNDhwnd,GAPSTATUSCALLBACKAfpProc);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。fpProc:表示回調(diào)函數(shù)指針,當(dāng)應(yīng)用程序的狀態(tài)改變時將調(diào)用該函數(shù)。其定義如下:typedefLRESULT(CALLBACK*GAPSTATUSCALLBACKA)(HWNDhWnd,intnID,LPCSTRIpsz);其中,hWnd表示視頻捕捉窗口句柄,nID表示狀態(tài)碼,Ipsz表示狀態(tài)文本描述。capSetCalIbackOnVideoStream該函數(shù)用于注冊ー個回調(diào)函數(shù),使得視頻緩沖區(qū)被填充時調(diào)用回調(diào)函數(shù)。語法如下:BOOLcapSetCallbackOnVideoStream(HWNDhwnd,CAPVIDEOCALLBACKfpProc);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。fpProc:表示回調(diào)函數(shù)指針,當(dāng)視頻緩沖區(qū)被填充時調(diào)用回調(diào)函數(shù),其定義與capSetCallbackOnFrame函數(shù)的fpProc參數(shù)相同。capSetCalIbackOnWaveStream該函數(shù)用于注冊ー個回調(diào)函數(shù),使得音頻緩沖區(qū)被填充時調(diào)用回調(diào)函數(shù)。語法如下:BOOLcapSetCallbackOnWaveStream(HWNDhwnd,CAPWAVECALLBACKfpProc);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。fpProc:表示回調(diào)函數(shù)指針,當(dāng)音頻緩沖區(qū)被填充時調(diào)用回調(diào)函數(shù)。其定義如下:typedefLRESULT(CALLBACK*CAPWAVECALLBACK)(HWNDhWnd,LPWAVEHDRIpWHdr);

其中,hWnd表示視頻捕捉窗口句柄,IpWHdr是ー個WAVEHDR結(jié)構(gòu)指針,表示音頻數(shù)據(jù)頭。capSetCalIbackOnYield該函數(shù)用于注冊ー個回調(diào)函數(shù),使得在每一次捕捉視頻幀時調(diào)用一次回調(diào)函數(shù)。語法如下:BCXDLcapSetCallbackOnYield(HWNDhwnd,fpProc);參數(shù)說明:hwnd:表示視頻捕捉窗ロ句柄。fpFYoc:表示回調(diào)函數(shù)指針,其定義如下:typedefLRESULT(CALLBACK*CAPYIELDCALLBACK)(HWNDhWnd);其中,hWnd表示視頻捕捉窗口句柄。通常,該函數(shù)由消息循環(huán)構(gòu)成。VFW的回調(diào)函數(shù)在視頻預(yù)覽、視頻錄像、視頻壓縮等多個地方被廣泛使用。ド面以統(tǒng)計預(yù)覽幀數(shù)為例介紹VFW回調(diào)函數(shù)的使用。效果如圖2.5所示。統(tǒng)計預(yù)覽幀數(shù)預(yù)策帳微:24%圖2.5回調(diào)函數(shù)設(shè)計程序設(shè)計步驟如下:分實例位置:在席'm列2\2.2\2.2.5\01(1)創(chuàng)建一個基于對話框的工程,在對話框中添加靜態(tài)文本、圖像等控件,如圖2.6所示。

圖2.6回調(diào)函數(shù)設(shè)計窗口(2)利用類向?qū)閳D像、靜態(tài)文本控件命令,如圖2.7所示。圖2.7MFC類向?qū)Т翱?3)在對話框的頭文件中引用“vfw.h”頭文件,并導(dǎo)入“vfw32.lib”庫文件。include"vfw.h”pragmacomment(Iib,nvfw32")(4)向?qū)υ捒蛑刑砑映蓡T變量m_hWndVideo,作為預(yù)覽窗口的句柄。

HWNDm_hWndVide〇;〃視頻顯示窗口(5)定義ー個全局變量,記錄當(dāng)前的預(yù)覽幀數(shù)。longnum=0;(6)定義ー個全局函數(shù),作為視頻預(yù)覽的回調(diào)函數(shù)。LRESULTCALLBACKPreviewCallback(HWNDhWnd)(num++;return0;}(7)處理對話框的WM_TIMER消息,將num數(shù)值顯示在界面中。voidCCallbackDesigendDIg::OnTimer(UINTnIDEvent)(CStringstr;str.Format(*'%iM,num);m_FrameNum.SetWindowText(str);CDialog::OnTimer(nlDEvent);}(8)在對話框初始化時創(chuàng)建視頻預(yù)覽窗口,設(shè)置預(yù)覽回調(diào)函數(shù),開始視頻預(yù)覽。BOOLCCallbackDesigendDIg::OnlnitDialog()(CDialog::OnlnitDialog();ASSERT((IDM_ABOUTBOX&OxFFFO)==IDM_ABOUTBOX);ASSEF!T(IDM_ABOUTBOX<OxFOOO);CMenu*pSysMenu=GetSystemMenu(FALSE);if(pSysMenu!=NULL)CStringstrAboutMenu;strAboutMenu.LoadString(lDS_ABOUTBOX);

if(IstrAboutMenu.lsEmptyO)pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);}}Setlcon(m_hlcon,TRUE);Setlcon(m_hlcon,FALSE);〃創(chuàng)建預(yù)覽窗口m_hWndVideo=capCreateCaptureWindow(NULL,WSLPOPUP,1,1,10,10,m_hWnd,0);〃連接驅(qū)動程序if(capDriverConnect(m_hWndVideo,0))(::SetParent(m_hWndVideo,*this);::SetWindowLong(m_hWndVideo,GWL^STYLE,WS_CHILD);CRectwndRC;m_Panel.GetQientRect(wndRC);m_Panel.MapWindowPoints(this,wndRC);wndRC.DefIateRect(1,1,1,1);::SetWindowPbs(m_hWndVideo,NULL,wndRGIeft,wndRC.top,wndRC.Width(),wndRC.Height(),SWP_NOZORDER);::ShowWindow(m_hWndVideo,SW_SHOW);capSetCallbackOnFrame(m_hWndVideo,PreviewCallback);capPreviewRate(m_hWndVideo,30);capPreview(m_hWndVideo,TRUE);}

SetTimer(1,800,NULL);(9)在對話框關(guān)閉時斷開視頻驅(qū)動程序。voidCCallbackDesigendDIg::OnCancel(){〃斷開驅(qū)動程序連接capDriverDisconnect(m_hWndVideo);CDialog::OnCancel();}2.2.6視頻錄像設(shè)計方案在VFW中,可以有3種方式實現(xiàn)視頻錄像。其中,最簡單的方式是調(diào)用capFileSetCaptureFile函數(shù)和capCaptureSequence函數(shù)。該種方式存在許多缺點,例如,在錄像時無法響應(yīng)用戶界面,無法實現(xiàn)視頻壓縮等。笫二種方式是調(diào)用capCaptureSetSetup函數(shù),將CAFTUREPARMS結(jié)構(gòu)的fYield成員設(shè)置為TRUE,啟動后臺線程來實現(xiàn)錄像,然后調(diào)用capDIgVideoCompression函數(shù)讓用戶選擇壓縮器進(jìn)行壓縮,最后調(diào)用capRIeSetCaptureRle函數(shù)和capCaptureSequence函數(shù)開始錄像。第二種方式的缺點是每次錄像時都需要彈出?個對話框,讓用廣,選擇ー種壓縮器。第三種方式是注冊回調(diào)函數(shù)capSetCallbackOnVideoStream,在回調(diào)函數(shù)中壓縮數(shù)據(jù)并寫入AVI文件。相對于前兩種方式,第三種方式更為靈活和實用,因此在進(jìn)行視頻錄像時,通常采用該種方式實現(xiàn)。具體實現(xiàn)過程如下:(1)定義ー個回調(diào)函數(shù),該回調(diào)函數(shù)實現(xiàn)數(shù)據(jù)壓縮,并將壓縮的數(shù)據(jù)寫入文件流中。(2)調(diào)用capSetCallbackOnVideoStream注冊回調(diào)函數(shù)。(3)調(diào)用100pen函數(shù)打開ー個壓縮器,并調(diào)用180mpressBegin函數(shù)開始壓縮。(4)調(diào)用AVIRIeOpen函數(shù)打開ー個AVI文件,并調(diào)用AVIRIeCreateStream函數(shù)創(chuàng)建文件流。(5)調(diào)用capCaptureSequenceNoRle函數(shù)開始錄像。下面以ー個具體實例介紹如何采用第三種方式實現(xiàn)視頻錄像。效果如圖2.8所示。

圖2.8視頻錄像設(shè)計方案分實例位置:次席、mr\2\2.2\2.2.6\01(1)創(chuàng)建一個基于對話框的工程,在對話框中添加按鈕、圖像控件,如圖2.9所示。圖2.9對話框資源設(shè)計(2)在對話框的頭文件中引用"vfw.h”頭文件,并導(dǎo)入"vfw32.lib”庫文件。include"vfw.h"pragmacomment(Iib,nvfw32n)(3)向?qū)υ捒蝾愔刑砑映蓡T變量。DWORDm_Frame; 〃記錄幀數(shù)OOMPVARSm_Com;〃壓縮參數(shù)

OOMPVARSm_Com;〃壓縮參數(shù)BlTMAPINFOm_lnlnfo,m_Outlnfo;〃位圖格式PAVIFILE rnjoRle; 〃AVI文件AVISTREAMINFOstrhdr; 〃AVI流信息PAVISTREAMps; //AV!流指針BOOLm_Captured; 〃是否開始捕捉(4)定義ー個回調(diào)函數(shù),在流捕捉時執(zhí)行。LRESULTWINAPIEncodeCallback(HWNDhWnd,LPVIDEOHDRIpVHdr)(CVideoEncodeDIg*pDIg=(CVideoEncodeDlg*)AfxGetMainWnd();if{(pDlg->m_Captured)&&(IpVHdr->dwFlags&VHDR_DONE))(char*buffer=newchar[IpVHdr->dwBytesUsed+1];memset(buffer,0,lpVHdr->dwBytesUsed+1);DWORDdwCkID;DWORDdwCompFlags;DWORDdwQuality=100;〃視頻壓縮if(ICCompress(pDlg->m_Com.hic,0,&pDlg->m_OutInfo.bmiHeader,buffer,&pDlg->m」nInfo.bmiHeader,(unsignedchar*)lpVHdr->lpData,SdwCklD,&dwCompFlags,pDlg->m_Frame++,0,dwQuality,NULL,NULL)==ICERR_OK){AVIStreamSetFormat(pDlg->ps,pDlg->m_Frame,&pDlg->m_Outlnfo,sizeof(pDlg->m_Outlnfo));AVIStreamWrite(pDlg->ps,pDlg->m_Frame,1,(LPBYTE)buffer,pDlg->m_Outlnfo.bmiHeader.biSizelmage,AVIIF_KEYFRAME,NULL,NULL);

delete[]buffer;return1;}(5)在對話框初始化時開始視頻預(yù)覽,設(shè)置視頻參數(shù)。m_Captured=FALSE;m_hWndVideo=capCreateCaptureWindow(NULL,WS_POPUP,1,1,10,10,m_hWnd,0);〃連接驅(qū)動程序if(capDriverConnect(m_hWndVideo,0))(::SetParent(m_hWndVideoJthis);::SetWindowLong(m_hWndVideo,GWL_STYLE,W^CHILD);CRectwndRC;m_Panel.GetOientRect(wndRC);m_Panel.MapWindowPoints(this,wndRC);wndRC.DeflateRect(1,1,1,1);::SetWindowPos(m_hWnd\/ideo,NULL,wndRC.Ieft,wndRC.top,wndRC.Width(),wndRC.Height(),SWP_NOZORDER);::ShowWindow(m_hWndVideo,SW_SHOW);CAPDRIVERCAPScaps;capDriverGetCaps(m_hWndVideo,sizeof(caps),&caps);if(caps.fHasOverlay)capOverlay(m_hWndVideo,TRUE);CAPTUREPARMSparams;capCaptureGetSetup(m_hWndVideo,¶ms,sizeof(params));params.fYield=TRUE;params,fAbortLeftMouse=FALSE;

params.fAbortRightMouse=FALSE;params.fLimitEnabled=FALSE;params.vKeyAbort=FALSE;params.fCaptureAudio=FALSE;capCaptureSetSetup(m_hWndVideo,¶ms,sizeof(params));capSetCallbackOnVideoStream(m_hWndVideo,EncodeCallback);capPreviewRate(m_hWndVideo,30);capPreview(m_hWndVideo,TRUE);}(6)向?qū)υ捒蛑刑砑覫nitCompress方法,設(shè)置壓縮參數(shù)信息。voidCVideoEncodeDIg::InitCompress()(capGetVideoFormat(m_hWndVideo,&m」nlnfo,sizeof(BITMAPINFO));capGetVideoFormat(m_hWndVideo,&m_Outlnfo,sizeof(BITMAPINFO));memset(&m_Com,0,sizeof(OOMPVARS));m_Com.cbSze=sizeof(m_Com);〃利用代碼選擇壓縮器m_Com.dwRags=16/!叱8MpVARS^VALID;m_Com.fccHandler=mmioFOURCC('x','v',T,'d');m_Com.fccType=ICTYPE_VIDEO;m_Com.lFrame=0;m_Com.lKey=15;m_Com.IKeyCount=0;m_Com.lDataRate=780;m_Com.lpbiOut=(BITMAPINFO*)&m_Outlnfo;m_Com.hic=IOOpen(ICTYPE_VIDEO,mmioFOUROC(,x,,'v,,,i\,d,),ICMODE_aDMPRESS);m_Com.cbState=1180;

〃利用對話框選擇壓縮器//ICCompressorChoose(NULL,ICMF_CHCXDSE_ALLOOMPRESSORS,(LPVOID)&m」nmfo,NULL&m_Com」選擇壓縮類型”);ICCompressGetFormat(m_Com.hic,&m_lnlnfo.bmiHeader,&m_Outlnfo.bmiHeader);〃開始壓縮intret=ICCompressBegin(m_Com.hic,(BlTMAPINFO*)&m_lnInfo,(BITMAPINFO*)&m_OutInfo);if(ret!=ICERR_OK)MessageBox("壓縮失敗)}(7)處理“錄像”按鈕的單擊事件,開始視頻錄像。voidCVideoEncodeDlg::OnOK()(CStringfilename;CHIeDialogRleDlg(FALSE,MaviM);if(FileDlg.DoModal()==IDOK)(filename=FiIeDig.GetPathName();capGetVideoFormat(m_hWndVideo,&m_lnlnfo,sizeof(m_lnlnfo));m_Frame=0;//AV!文件初始化AVIHIelnitO;〃設(shè)置壓縮參數(shù)lnitCompress();〃打開文件AVIFleOpen(&m_pFile,filename,OFLWRITE|OF_CREATE,NULL);memset(&strhdr,0,sizeof(strhdr));strhdr.fccType=streamtypeVIDSD;

strhdr.fccHandler=0;strhdr.dwScale=1;strhdr.dwRate=15;strhdr.dwSuggestedBufferSze=m_lnlnfo.bmiHeader.biSzelmage;SetRect(&strhdr.reFrame,0,0,m_lnlnfo.bmiHeader.biWidth,m_lnlnfo.bmiHeader.biHeight);ps=NULL;〃文件文件流AVIFileCreateStream(mjoFiIe,&ps,&strhdr);m_Captured=TRUE;〃開始捕捉capCaptureSequenceNoFile(m_hWndVideo);}}(8)在對話框關(guān)閉時停止視頻錄像。voidCVideoEncodeDlg::OnCancel()(〃終止回調(diào)函數(shù)capSetCallbackOnVideoStream(m_hWndVideo,NULL);〃結(jié)束數(shù)據(jù)壓縮ICCompressEnd(m_Com.hic);〃關(guān)閉壓縮句柄ICQose(m_Com.hie);if(m_Captured)(〃關(guān)閉AVI文件流AVIStreamQose(ps);if(m_pRle!=NULL)

AVIFileFtelease(m_pFile);AVIFIeExit();}〃停止捕捉capCaptureStop(m_hWndVideo);〃斷開驅(qū)動程序連接capDriverDisconnect(m_hWndVideo);CDialog::OnCancel();}2.3DirectShow視頻采集方案流媒體處理技術(shù)以其復(fù)雜性和技術(shù)性一直受到人們的關(guān)注。隨著網(wǎng)絡(luò)技術(shù)的不斷發(fā)展,流媒體在網(wǎng)絡(luò)上得到了廣泛地應(yīng)用。如何能夠簡單、有效地進(jìn)行流媒體處理,已成為ー個焦點問題。為此,Microsoft推出了DirectShow,DirectShow是Microsoft推出的基于Windows平臺的流媒體處理開發(fā)包,它與DirectX?起發(fā)布。DirectShow對流媒體的捕捉、回放提供了強(qiáng)大的支持,使用它還可以在基于WDM驅(qū)動的采集卡上進(jìn)行數(shù)據(jù)捕捉。本節(jié)將介紹有關(guān)DiredShow的相關(guān)知識。DirectShow系統(tǒng)結(jié)構(gòu)分析DiredShow主要由過濾器(FilterGraph)圖表構(gòu)成。過濾圖表屮包含了各種Filter,這些Filter能夠按一定順序連接在ー起,構(gòu)成一條流水線。從功能的角度劃分,Filter大體可以分為3類,SourceAlters,TransformAltersfllRenderingAlters=SourceFilters主要負(fù)責(zé)獲取數(shù)據(jù),可以是ー個文件、一個采集卡、聲卡或數(shù)碼相機(jī)等。TransformAlters負(fù)責(zé)數(shù)據(jù)的轉(zhuǎn)換、傳輸。例如各種編碼器、解碼器等。RenderingAlters負(fù)責(zé)數(shù)據(jù)的最終去向,例如將數(shù)據(jù)傳送到聲卡、顯卡或存儲為文件。在開發(fā)DiredShow應(yīng)用程序時,通常需要設(shè)計?個過濾圖表(AlterGraph),向過濾圖表中添加相應(yīng)的過濾器,最后連接過濾器的引腳就完成了功能的設(shè)計。例如,實現(xiàn)一個簡單的視頻預(yù)覽功能,需要向過濾圖表中添加一個視頻捕捉源過濾器和一個VideoRenderer過濾器,將視頻捕捉源過濾器的輸出引腳與VideoRenderer過濾器的輸入引腳相連就可以了。

而在程序中只需要按照設(shè)計過濾圖表的捕捉添加過濾器并連接過濾器弓I腳就可以了。在連接過濾器引腳時需要注意:只能是輸出過濾器引腳與輸入過濾器引腳相連,兩個輸出過渡器或兩個輸入過濾器引腳是不能相連的。為了在程序中使用DirectShow,需要單獨安裝DirectX,當(dāng)前DirectX的最新版本為9.0,即DirectX9.0,用戶可以從Microsoft的官方網(wǎng)站上免費下載。在安裝DirectX之后,程序中需要引用“dshow.h”頭文件,并導(dǎo)入“StrmiidsJib”庫文件和“quartzJib”庫文件オ可以使用DirectShow〇代碼如下:pragmacomment(lib,"Strmiids")pragmacomment(lib,"quartz")include<dshow.h>2.3.2Filter圖表設(shè)計為了方便用戶設(shè)計過濾圖表,DirectX提供了一個GraphEdit工具。用戶可以單擊“開始”菜單下的“MicrosoftDirectX9SDK\DirectXUtilities\GraphEdit”菜單項打開GaphEditT具,如圖2.10所示。

圖2.10GraphEdit工具下面筆者介紹如何使用GraphEdit工具設(shè)計過濾圖表,過濾圖表的功能是實現(xiàn)視頻的預(yù)覽功能。具體步驟如下:(1)在圖2.4中單擊“Graph/InsertFilters”菜單項打開“添加過濾器”窗口,如圖2.11所示。圖2.11添加過濾器窗口(2)在"VideoCaptureSources”節(jié)點下選擇ー個視頻捕捉源過濾器,單擊"InsertFilter”按鈕將其添加到過濾圖表中,如圖2.12所示,1□1x|。間。I&\ IIJ.?|n|?l.TJB??セ 甲.■圖2.12添加視頻捕捉源過濾器窗口提示:如果系統(tǒng)中沒有安裝攝像頭及其驅(qū)動程序,該節(jié)點下將不會有視頻捕捉源過濾器。

(3)it"DirectShowFilters”節(jié)點下選擇“VideoRenderer”過濾器,將其添加到圖表中,如圖2.13所示。圖2.13添加“VideoRenderer”過濾器窗口(4)利用鼠標(biāo)將視頻捕捉源過濾器的“Capture”引腳與“VideoRenderer”過濾器的“VMRInput。”引腳相連,如圖2.14所示。圖2.14連接過渡器引腳窗口(5)單擊工具欄中的“丄J”按鈕運行過濾圖表,將顯示ー個視頻預(yù)覽窗口,如圖2.15所示。

IBActiTelo<iefindov-1□1x|IBActiTelo<iefindovI!序員修毎三部偷B-BTheRogmoftcStcrto* i版本控制之道PragmaticVersionControl

—使用CVSUsingCVSUsingCVS蹴Con皿圖2.15視頻預(yù)覽窗口枚舉系統(tǒng)設(shè)備使用GraphEdit工具,用戶可以非常方便地獲得與某ー系統(tǒng)設(shè)備相關(guān)的過濾器。但是,在程序中該如何獲得這些過濾器呢?用戶可以采用枚舉的方式列舉系統(tǒng)中安裝的設(shè)備。以列舉系統(tǒng)中的視頻捕捉設(shè)備為例,首先定義ー個設(shè)備列舉接口ICreateDevEnum的ー個指針,調(diào)用CoQeatelnstance方法創(chuàng)建ICreateDevEnum實例,然后定義ー個列舉監(jiān)視器lEnumMoniker的ー個指針,調(diào)用ICreateDevEnum實例的CreateQass&iumerator方法創(chuàng)建lEnumMoniker實例,最后以循環(huán)的方式調(diào)用lEnumMoniker實例的Next方法遍歷系統(tǒng)設(shè)備,調(diào)用l&iumMoniker實例的BindToObject方法將系統(tǒng)設(shè)備綁定到過濾器上。在上面的描述中,ICreateDevEnum實例的CreateClass&iumerator方法的第?個參數(shù)確定枚舉的系統(tǒng)設(shè)備。例如,第一個參數(shù)為CLSID_VideoInputDeviceCategory,表示將要枚舉系統(tǒng)中的視頻捕捉卡,為CLSID_VideoCompressorCategory,表示枚舉系統(tǒng)中的視頻壓縮器。下面的代碼演示了如何枚舉系統(tǒng)中的視頻捕捉卡。〃枚舉視頻設(shè)備ICreateDevEnum*pDevEnum=NULL;CoCreatelnstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC,11D_lCreateDevEnum,(void**)&pDevEnum);lEnumMoniker*pQassEnum=NULL;

pDevEnum->CreateQassEnumerator(CLSID_VideolnputDeviceCategory,&pQassEnum,0);ULONGcFetched;while(pQassEnum->Next(1,&pMoniker,&cFetched)==S_OK)(pMoniker->BindToObject(0,0,11D_lBaseFilter,(void**)&pSrc);pMoniker->Release();break;}pQassEnum->Release。;而下面的代碼則用于判斷系統(tǒng)中是否安裝了指定的視頻壓縮器。ICreateDevEnum*pDevEnum=NULL;CoCreatelnstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC,11D_lCreateDevEnum,(void**)&pDevEnum);lEnumMoniker*pQassEnum=NULL;〃列舉視頻壓縮設(shè)備pDevEnum->CreateQassEnumerator(CLSID_VideoCompressorcategory,&pQassEnum,0);while(pQassEnum->Next(1,&pMoniker,&cFetched)==S_OK)(IPropertyBag*pProp=NULL;pMoniker->BindToStorage(0,0,IID_IPropertyBag,(void**)&pProp);VARIANTvarName;varName.vt=VT_BSTR;pProp->Read(LnFriendlyName*',&varName,0);CStringstr=varName.bstrVal;if(str.Fnd(MMicrosoftVideo1M,0)!=-1)

pMoniker->BindToObject(0,0,11D_lBaseAlter,(void**)&pCompress);pMoniker->Ftelease();break;}Variant0ear(&varName);}pQassEnum->Release。;查找FilterPin每ー個過濾器(Filter)至少應(yīng)有一個引腳(Pin),或者是輸入引腳或者是輸出引腳。有些過濾器還擁有多個引腳,即乂輸入引腳乂有輸出引腳。但是過濾器的輸入、輸出引腳并不是對應(yīng)的,有些過濾器可以有多個輸入引腳,而只有一個輸出引腳或者沒有輸出引腳。在程序中為了連接過濾器間的引腳,通常需要獲得過濾器的各個引腳。用戶可以使用lEnumRns接口來枚舉某ー個過濾器的輸入、輸出引腳。過濾器IBaseFilter提供了一個日umPins方法用于生成一個IEnumPins接口實例,這樣,通過調(diào)用IBnumPins的Next方法便可以訪問各個引腳了。下面的代碼定義了一個FindRn函數(shù),用于獲得某個過濾器的輸入或輸出引腳?!ú檎乙_IRn*CKinescopeDlg::FindRn(IBaseRlter*pRlter,RN_DIRECTIONdir)(lEnumRns*pEnumRns;IRn*pOutpin;PIN_DIRECTIONpDir;pFlter->EnumRns(&pEnumRns);while(pEnumRns->Next(1,&pOutpin,NULL)==S_OK)(pOutpin->QueryDirection(&pDir);if(pDir==dir)

returnpOutpin;)}return0;)用戶可以按下面的方式獲得某個過濾器的輸入、輸出引腳。IRn*pComOut/pComln;pComln=findRn(pCompress,PINDIRINPUT);pComOut=FindRn(pCompress,PINDIR_OUTPUT);連接FilterPin使用GraphEdit工具,用戶可以利用鼠標(biāo)非常方便地連接兩個過渡器間的引腳。但是在程序中卻沒這么簡單了。首先需要按照2.3.4節(jié)介紹的方法獲得兩個過濾器的輸入、輸出引腳,然后將笫ー個過濾器的輸出引腳連接到第二個過濾器的輸入引腳,其中,連接兩個引腳需要調(diào)用IGraphBuilder接口的00nnectDirect方法。下面的代碼演示了如何連接兩個過濾器的引腳。IRn*pComOut,*pComIn;pComln=FndRn(pCompress,PINDIRINPUT);pComOut=RndRn(pCompress,PINDIR_OLTTPUT);IRn*pOutpin=FindRn(pSrc,PINDIRJDUTPUT);〃pSrc的輸出引腳HRESULTresult;result=pGraph->ConnectDirect(pOutpin,pComln,NULL);視頻預(yù)覽設(shè)計方案在開發(fā)視頻應(yīng)用程序時,ー個最基本的功能是視頻預(yù)覽。本節(jié)將介紹如何應(yīng)用DirectShow實現(xiàn)視頻預(yù)覽,效果如圖2.16所示。

輪DirectSh”一視頻預(yù)覽設(shè)計方案****Delphi數(shù)據(jù)庫系統(tǒng)開發(fā)完全手冊確定」I二取消一3圖2.16視頻預(yù)覽設(shè)計方案在使用DirectShow開發(fā)應(yīng)用程序時,通常需要先設(shè)計過濾圖表,然后根據(jù)圖表來設(shè)計應(yīng)用程序。在設(shè)計視頻預(yù)覽過濾圖表時,只需要兩個步驟,第一個步驟是添加視頻捕捉的源過濾器,第二個步驟是添加VideoRender過濾器,并連接兩個過濾器引腳。過濾圖表具體設(shè)計步驟如下:(1)啟動GraphEdit工具,在GraphEdit工具中單擊"Graph\InsertFilters"菜單項打開“添加過濾器窗口”,在“VideoCaptureSources”節(jié)點下選擇ー個視頻捕捉源過濾器,單擊“InsertFilter”按鈕將其添加到過濾圖表中,如圖2.11所示。(2)在“DiredShowFilters”節(jié)點下將“VideoRender”過濾器添加到圖表中,如圖2.17所示。

Re^dy||NUM| /Re^dy||NUM| /圖2.17過濾圖表設(shè)計1(3)連接過濾器引腳,如圖2.18所示。-101x|。座舊I&\IIIA|u|?|t|InputVideoRendererInputVideoRenderer海天地QQ電腦眼(Vimicro301Neptune)Ready圖2.18過濾圖表設(shè)計2至此,完成視頻預(yù)覽過濾圖表的設(shè)計。單擊“Play”按鈕運行過濾圖表,將彈出ー個視頻預(yù)覽窗口,如圖2.19所示。

ActiveMovieWindow朗日科技VisualC++ActiveMovieWindow朗日科技VisualC++程序開發(fā)圖2.19DerictShow預(yù)覽窗口程序具體步驟如下:噂實例位置:光席、m列2\2.3\236\01(1)創(chuàng)建一個基于對話框的工程,在對話框類的頭文件中引用“dshow.h”頭文件。pragmacomment(lib,,,Strmiids,')pragma8mmem(lib/'quartz")include<dshow.h>(2)在對話框類中定義如下成員變量。IMediaControl*pMediaControl;〃媒體控制IGr叩hBuilder *pGraph;〃過濾圖表IBaseFIter*pSrc,*pPreview;〃過濾器IMoniker *pMoniker;〃監(jiān)視器(3)向?qū)υ捒蝾愔刑砑覴ndPin方法,查找過濾器的引腳?!ú檎乙_IPin*CPreviewDlg::FndRn(IBaseRlter*pHlter,PIN_DIRECTIONdir)(IEnumPins*pEnumPins;IPin*pOutpin;PIN_DIRECTIONpDir;pFlter->EnumPins(&pEnumPins);

while(pEnumPins->Next(1,&pOutpin,NULL)==S_OK)pOutpin->QueryDirection(&pDir);if(pDir==dir){returnpOutpin;}}return0;}(4)在應(yīng)用程序類的InitInstance方法中初始化Com接口?!ǔ跏蓟疌omColnitialize(NULL);(5)在對話框初始化時枚舉視頻捕捉設(shè)備,設(shè)計過濾圖表。ICaptureGraphBuilder2*pBuilder=NULL;pGraph=NULL;pMediaControl=NULL;〃枚舉視頻設(shè)備ICreateDevEnum*pDevEnum=NULL;CoCreatelnstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPR(3C,11D_lCreateDevBium,(void**)&pDevEnum);IBiumMoniker*pQassEnum=NULL;pDevEnum->CreateQassEnumerator(CLSID_VideolnputDeviceCategory,&p0ass&ium,0);ULONGcFetched;if(pQassEnum->Next(1,&pMoniker,&cFetched)==S_OK)pMoniker->BindToObject(0,0,IID」BaseFilter,(void**)&pSrc);

pMoniker->Release();pQassEnum->Release();CoCreatelnstance(CLSID_CaptureGraphBuilder2,0,CLSCTX_INPROCLSERVER,11D_lCaptureGraphBuilder2,(void**)&pBuilder);CoCreatelnstance(CLSID_FlterGraph,NULL,CLSCTX_INPROCLSERVER,IIDJQaphBuilder,(void**)&pGraph);pBuilder->SetRltergraph(pGraph);pGraph->Querylnterface(IID_lMediaControl,(void**)&pMediaControl);paaph->AddFlter(pSrc,L,,aviH);pPreview=NULL;CoCreatelnstance(CLSID_VideoRenderer,0,CLSCTX_ALL,IID_IBaseFlter,(void**)&pPreview);if(pPreview!=NULL)(pGraph->AddFIter(pPreview,Lnpreview");〃連接引腳IPin*pSourceOut;pSourceOut=FndPin(pSrc,PINDIR_OUTPUT);IPin*pPreln=RndPin(pPreview,PINDIR_lNPUT);pGraph->ConnectDirect(pSourceOut,pPreln,NULL);〃獲取預(yù)覽窗口IVideoWindow*pViewWnd=NULL;pPreview->Querylnterface(11D_lVideoWindow,(void**)&pViewWnd);if(pViewWnd)〃設(shè)置預(yù)覽窗口的擁有者

pViewWnd->put_Owner((long)m_hWnd);pViewWnd->put_Left(1);pViewWnd->put_Top(1);〃獲取預(yù)覽窗口風(fēng)格longstyle;pViewWnd->get_WindowStyle(&style);style=style&WSLCAFTION;style=style&-WS_DLGFRAME;style=style&WS_CHILD;pViewWnd->put_WindowStyle(style);〃設(shè)置預(yù)覽窗口寬度和高度CRectrc;GetQientFtect(rc);pViewWnd->put_Height(rc.Height()-60);pViewWnd->put_Width(rc.Width()-2);}pMediaControl->Run();}2.3.7事件通知設(shè)計方案在使用DiredShow開發(fā)應(yīng)用程序時,通常需要DiredShow與應(yīng)用程序之間進(jìn)行交互。例如,在使用DiredShow播放影視文件時,在文件播放完畢后,應(yīng)用程序需要得到通知,并通知用戶文件播放完畢。DiredShow采用了事件通知的機(jī)制與用戶應(yīng)用程序進(jìn)行交互。當(dāng)過濾器的狀態(tài)改變時,或者重畫視頻窗口時,都將產(chǎn)生相應(yīng)的事件,由DiredShow處理并轉(zhuǎn)發(fā)給應(yīng)用程序,應(yīng)用程序能夠接收到該事件,并根據(jù)事件的不同類型作出相應(yīng)的處理。DirectShow提供了3個有關(guān)事件通知的接口,分別為“IMediaEventSnk"、“IMediaEvent”和“IMediaEventEx"。其中,IMediaEventEx接口是IMediaEvent接口的擴(kuò)展,在應(yīng)用程序中經(jīng)常使用該接口類處理事件。IMediaEventEx接口的主要方法如下:

GetNotifyFlags方法該方法用于獲取事件通知是否被激活。語法如下:HRESULTGetNotifyRags(long*IpINoNotifyRags);參數(shù)說明:IpINoNotifyRags;確定事件通知是否被激活。如果為零,表示事件通知被激活,為AM_MEDIAEVENT_NONOTIFY,表示事件通知不可用。SetNotifyFlags方法該方法用于設(shè)置事件通知是否被激活。語法如下:HRESULTSetNotifyRags(longINoNotifyRags);IpINoNotifyFlags:如果為零,表示激活事件通知,為AM_MEDIAEVENT_NONOTIFY,表示禁止事件通知。SetNotifyWindow方法該方法用于注冊ー個窗口來處理事件通知。語法如下:HRESULTSetNotifyWindow(OAHWNDhwnd,longIMsg,longIlnstanceData);參數(shù)說明:hwnd:表示處理事件通知的窗口句柄。IMsg:表示與事件通知關(guān)聯(lián)的窗口消息。IlnstanceData:作為IMsg消息處理函數(shù)的IParam參數(shù)被傳遞。GetEventHandle方法該方法用于獲取人工重置事件對象的句柄。語法如下:HRESULTGetEventHandle(OAEVENT-Event);參數(shù)說明:hEvent:表示返冋的人工重置事件對象的句柄。

GetEvent方法該方法用于從消息隊列中返回下ー個事件通知。語法如下:HRESULT(long*IEventCode,long*IParam1,long*IParam2,longmsTimeout);參數(shù)說明:IEventCode:表示接收的事件通知代碼。IParam1:表示第一個事件參數(shù)。IParam2:表示第2個事件參數(shù)。msTimeout:表示超時時間,如果為NF1NITE,將一直等待,直到有事件通知為止。FreeEventParams方法該函數(shù)用于釋放事件參數(shù)。語法如下:HRESULTFreeEventParams(longIEventCode,longIParam1,longIParam2);參數(shù)說明:IEventCode:表示接收的事件通知代碼。IParam1:表示第一個事件參數(shù)。IParam2:表示第2個事件參數(shù)。CancelDefaultHandling方法該方法用于取消DirectShow對事件進(jìn)行的默認(rèn)處理。語法如下:HRESULTCancelDefaultHandling(longlEvCode);參數(shù)說明:lEvCode:表示事件通知代碼。RestoreDefaultHandling方法該方法用于恢復(fù)DirectShow對默認(rèn)消息的處理。語法如下:HRESULTRestoreDefaultHandling(longlEvCode);

參數(shù)說明:lEvCode:表示事件通知代碼。在應(yīng)用程序中可以有兩種方式來接收和處理DirectShow中的事件。第一種方式是讓DirectShow向應(yīng)用程序的窗口中發(fā)送消息。第2種方式是通過事件對象(這里的對象是指Wind。ws內(nèi)核對象)。向?qū)Χ?第一種方式比較簡單,也比較常用,而第2種方式多用于控制臺應(yīng)用程序或多線程應(yīng)用程序。下面筆者將分別以這兩種方式來實現(xiàn)事件通知消息。為了演示應(yīng)用程序獲得了DirectShow發(fā)送的事件通知,ド面的兩個例子均以播放ー個AVI文件為例,在DirectShow播放完AVI文件,將向應(yīng)用程序發(fā)出通知,應(yīng)用程序獲得通知后,將彈出對話框提供用戶,如圖2.20、圖2.21所示。圖2.20事件通知方式1效果圖

圖2.21事件通知方式2效果圖I 基于窗口消息的事件通知ッ實例位置:并席、mr\2\2.3\2.3.ハ01(1)創(chuàng)建一個基于對話框的工程,在對話框中添加按鈕、圖像控件,如圖2.22所示。圖2.22事件通知方式1對話框設(shè)計(2)在類向?qū)У?MemberVariables"選項卡中為圖像控件命名,如圖2.23所示。

圖2.23類向?qū)Т翱?3)在對話框類的頭文件中引用“dshow.h”頭文件,并導(dǎo)入相應(yīng)的庫文件。pragmacomment(lib/'Strmiids*')pragmacomment(libjquartz”)include<dshow.h>(4)在應(yīng)用程序的Initlnstance方法中初始化Com庫。BOOLCNotifyEventApp::lnitlnstance()(AfxEnableControlContainer();#ifdef_AFXDLLEnable3dControls();#elseEnable3dControlsStatic()#endifColnitialize(NULL);CNotifyEventDigdig;m_pMainWnd=&dlg;

intnResponse=dlg.DoModal();if(nResponse==IDOK)(}elseif(nResponse==IDCANCEL)(}returnFALSE;}(5)改寫應(yīng)用程序的Exitinstance方法,在應(yīng)用程序退出時卸載Com庫。intCNotifyEventApp::ExitInstance()(CoUninitialize();returnCWinApp::ExitInstance();}(6)在對話框類中添加如下成員變量。IMediaControl*pMediaControl;〃媒體控制IGraphBuilder*pGraph;〃過濾圖表IBasefilter*pSrc; 〃過濾器IMoniker*pMoniker;〃監(jiān)視器BOOLm_Previewed;〃是否進(jìn)行預(yù)覽IMediaEventEx*pEvent;〃事件IVideoWindow*pViewWnd;〃預(yù)覽窗口句柄(7)自定義?個消息,用于在完成文件播放時向窗口中發(fā)送通知。#defineCM_NOTIFYWM_USER+1(8)向?qū)υ捒蝾愔刑砑幼远x消息處理函數(shù)〇nGraphNoMfy。voidCNotifyEventDig::OnGraphNotify(WPARAMwParam,LPARAMIParam)

if(pEvent)LONGeventcode=0,param1=0,param2=0;while(SUCXDEEDED(pEvent->GetEvent(&eventcode,¶m1,¶m2,0))){pEvent->FreeEventParams(eventcode,param1,param2);switch(eventcode){caseEC_(X)MPLETE:{m_Previewed=FALSE;pMediaControl->Stop();pMediaControl->Release。;pGraph->Ftelease();pViewWnd->put_Visible(FALSE);MessageBox("預(yù)覽完成”,“提示");m_Panel.ShowWindow(SW_HIDE);m_Panel.ShowWindow(SW_SHOW);break;}})))(9)在對話框的消息映射部分添加消息映射宏,將消息與消息處理函數(shù)關(guān)聯(lián)起來。BEGIN_MESSAGE_MAP(CNotifyEventDlg,CDialog)//{{AFX_MSG_MAP(CNotifyEventDlg)ON_WM_SYSOOMMAND()

ON_WM_PAINT()ON_WM_QUERYDRAGI00N()ON_BN_CLICKED(IDJChOOSE,OnChooSE)ON_MESSAGE(CM_NOTIFY,On&aphNotify)//}}AFX_MSG_MAPEND_MESSAGE_MAP()(10)處理“設(shè)置文件”按鈕的單擊事件,開始播放AV!文件。voidCNotifyEventDlg::OnChooSE()(CFIeDialogfDlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,Havi文件|*.avi");if(fDlg.DoModal()==IDOK)(CStringstrRle=fDlg.GetPathName();ICaptureGraphBuilder2*pBuilder=NULL;pGaph=NULL;pMediaControl=NULL;CoCreatelnstance(CLSID_CaptureGraphBuilder2,0,CLSCTX_lNPROC_SERVER,11D_lCaptureGraphBuilder2,(void**)&pBuilder);CoCreatelnstance(CLSID_RlterGraph,NULL,CLSCTX_INPROCLSERVER,IID_IGaphBuilder,(void**)&pGraph);pBuilder->SetRltergraph(pGraph);pGraph->Querylnterface(llD_lMediaControl,(void**)&pMediaControl);pGraph->RenderFle(strFle.AllocSysString(),NULL);〃獲取預(yù)覽窗口pViewWnd=

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論