VFW技術資料基本解析。
2011-08-25 18:48 by 沐海, 831 visits, 收藏, 編輯
VFW概念
VFW是微軟公司1992年推出的關于數字視訊的一個軟體包,它能使應用程式通過數字化裝置從傳統的模拟視訊源得到數字化的視訊剪輯。VFW的一個關鍵思想是播放時不需要專用硬體,為了解決數字視訊資料量大的問題,需要對資料進行壓縮。它引進了一種叫AVI的檔案标準,該标準未規定如何對視訊進行捕獲、壓縮及播放,僅規定視訊和音頻該如何存儲在硬碟上,以及在AVI檔案中交替存儲視訊幀和與之相比對的音頻資料。
VFW給程式員提供.VBX和AVICap視窗類的進階程式設計工具,使程式員能通過發送消息或設定屬性來捕獲、播放和編輯視訊剪輯。
VFW提供了基于消息的接口,而這些接口,也可以利用它本省定義的宏來實作。
在Windows 9x系統中,當使用者在 安裝VFW時,安裝程式會自動地安裝配置視訊所需要的元件,如裝置驅動程式、視訊壓縮程式等。
VFW主要由以下6個子產品組成:
●AVICAP.DLL:包含執行視訊捕獲的函數,它給AVI檔案的I/O處理和視訊、音頻裝置驅動程式提供一個進階接口;
●MSVIDEO.DLL:包含一套特殊的DrawDib函數,用來處理螢幕上的視訊操作;
●MCIAVI.DRV:包括對VFW的MCI指令解釋器的驅動程式;
●AVIFILE.DLL:包含由标準多媒體I/O(mmio)函數提供的更高的指令,用來通路.AVI檔案;
●視訊壓縮管理器(ICM):用于管理的視訊壓縮/解壓縮的編譯碼器(Codec);
●音頻壓縮管理器ACM:提供與ICM相似的服務,适用于波形音頻。
AVICap在顯示視訊時提供的兩種模式:
(A)預覽(Preview)模式:該模式使用CPU資源,視訊幀先從捕獲硬體傳到系統記憶體,接着采用GDI函數在捕獲窗中顯示。在實體上,這種模式需要通過VGA卡
在螢幕上顯示。
(B)疊加(Overlay)模式:該模式使用硬體疊加進行視訊顯示,疊加視訊的顯示不經過VGA卡,疊加視訊的硬體将VGA的輸出信号與其自身的輸出信号合并,形
成組合信号顯示在計算機的螢幕上。隻有部分視訊捕獲卡才具有視訊疊加能力。
AVICap為應用程式提供了一個簡單的、基于消息的接口,使之能通路視訊和波形音頻硬體,并能在将視訊流捕獲到硬碟上的過程中進行控制。
Microsoft Video for Windows(VFW) 提供的函數可以讓應用程式去處理視訊資料。 VFW 在16位Windows的時候就被引入了。它的許多重要功能已經被DirectX取代了。 下面介紹VFW的視訊捕獲:
你可以使用windows的AVICap 類輕松地完成視訊捕獲。AVICap 提供給應用程式一個簡單的、基于消息的接口去通路視訊裝置和錄音裝置,并且可以控制處理視訊流捕獲。AVICap支援實是視訊流捕獲和實時單幀圖像捕獲。另外,AVICap 提供了對視訊源的控制(MCI媒體控制接口裝置),是以使用者可以通過應用程式控制一個視訊源開始和結束的位置,并且可以加大對幀捕獲的控制。
VFW 是Microsoft公司為開發Windows平台下的視訊應用程式提供的軟體工具包,
提供了一系列應用程式程式設計接口(API),
使用者可以通過這些接口很友善地實作視訊捕獲、視訊編輯及視訊播放等通用功能,
還可利用回調函數開發比較複雜的視訊應用程式。
該技術的特點是播放視訊時不需要專用的硬體裝置,而且應用靈活,可以滿足視訊應用程式開發的需要。Windows作業系統自身就攜帶了VFW技術,系統安裝時,會自動安裝VFW的相關元件。
VFW處理視訊原理
用AVICAP.DLL實作圖像采集,首先要用函數capCreateCaptureWindowA建立一個視訊采集視窗,然後向視訊采集視窗發送相應的消息,實作視訊裝置的連接配接、回調函數設定、預覽比例和速率設定、預覽和疊加模式的設定、圖像檔案設定等操作。如果以上操作成功,就可以通過視訊裝置采集圖像了。回調函數由程式員編寫,用于特殊的視訊采集中,例如,在視訊會議中用回調函數将采集的視訊和音頻實時地傳遞到遠端計算機中。
在VC++中,頭檔案VFW.H中不僅包含了AVICAP.DLL中函數的原型定義,還定義了與視訊采集有關的資料結構、消息和發送消息的宏。利用這些函數、資料結構、消息和發送消息的宏可以友善地編寫圖像采集程式,如果要對采集的圖像實時處理,可以通過編寫回調函數實作。
2.1 建立捕獲視窗
利用AVICAP 元件函數 capCreateCaptureWindow() 建立視訊捕獲視窗,它是所有捕獲工作及設定的基礎,其主要功能包括:① 動态地同視訊和音頻輸入器連接配接或斷開;② 設定視訊捕獲速率;③ 提供視訊源、視訊格式以及是否采用視訊壓縮的對話框;④ 設定視訊采集的顯示模式為Overlay或為Preview; ⑤ 實時擷取每一幀視訊資料;⑥ 将一視訊流和音頻流捕獲并儲存到一個AVI檔案中; ⑦ 捕獲某一幀數字視訊資料,并将單幀圖像以DIB格式儲存;⑧指定捕獲資料的檔案名,并能将捕獲的内容拷貝到另一檔案。
2.2 登記回調函數[2]
登記回調函數用來實作使用者的一些特殊需要。在以一些實時監控系統或視訊會議系統中,需要将資料流在寫入磁盤以前就必須加以處理,達到實時功效。應用程式可用捕獲窗來登記回調函數,以便及時處理以下情況:捕獲窗狀态改變、出錯、使用視訊或音頻緩存、放棄控制權等,相應的回調函數分别為 capStatusCallback(), capErrorCallback(), capVideoStreamCallback(), capWaveStreamCallback(),capYieldCallback()。
2.3 擷取捕獲視窗的預設設定
通過宏capCaptureGetSetup(hWndCap,&m_Parms,sizeof(m_Parms))來完成。
2.4 設定捕獲視窗的相關參數
通過宏capCaptureSetSetup(hWndCap,&m_Parms,sizeof(m_Parms))來完成。
2.5 連接配接捕獲視窗與視訊捕獲卡
通過宏capDriveConnect(hWndCap,0)來完成。
2.6 擷取采集裝置的功能和狀态
通過宏capDriverGetCaps(hWndCap,&m_CapDrvCap,sizeof(CAPDRIVERCAPS))來擷取
視訊裝置的能力,通過宏capGetStatus(hWndCap,&m_CapStatus,sizeof(m_CapStatus))
來擷取視訊裝置的狀态。
2.7 設定捕獲視窗顯示模式
視訊顯示有Overlay(疊加)和Preview(預覽)兩種模式。在疊加模式下,捕獲視訊資料布展系統資源,顯示速度快,視訊采集格式為YUV格式,可通過capOverlay(hWndCap,TRUE)來設定;預覽模式下要占用系統資源,視訊由系統調用GDI函數在捕獲窗顯示,顯示速度慢,它支援RGB視訊格式。
2.8 捕獲圖像到緩存或檔案并作相應處理
若要對采集資料進行實時處理,則應利用回調機制,由capSetCallbackOnFrame(hWndCap, FrameCall-
backProc)完成單幀視訊采集;由capSetCallbackOnVideoStream(hWndCap, VideoCallbackProc)完成視訊流采集。如果要儲存采集資料,則可調用capCaptureSequence(hWnd);要指定檔案名,可調用capFileSetCap-
ture(hwnd, Filename)。
2.9 終止視訊捕獲 斷開與視訊采集裝置的連接配接
調用capCatureStop(hWndCap)停止采集,調用capDriverDisconnect(hWndCap), 斷開視訊視窗與捕獲驅動程式的連接配接。
3 視訊編輯和播放
利用VFW,不僅可以實作視訊流的實時采集,還提供了編輯和播放功能,主要通過AVIFILE、ICM、ACM、MCIWnd 等元件之間的協作來完成。
3.1 編輯處理AVI[3]視訊檔案的一般流程(圖2)
圖2 編輯視訊檔案的一般流程圖
Fig.2 General flow chart of editing video files
1) AVIFileInit();//初始化;
2) AVIFileOpen(); //打開一個AVI檔案并獲檔案的句柄;
3) AVIFileInfo(); //擷取檔案的相關資訊,如圖像的Width和Height等;
4) AVIFileGetStream(); //建立一個指向需要通路的資料流的指針;
5) AVIStreamInfo(); //擷取存儲資料流資訊的AVISTREAMINFO結構;
6) AVIStreamRead(); //讀取資料流中的原始資料, 對AVI檔案進行所需的編輯處理;
7) AVIStreamRelease(); //釋放指向視訊流的指針;
8) AVIFileRelease();AVIFileExit(); //釋放AVI檔案。
若資料是壓縮過的,則用AVIStreamGetFrameOpen(),AVIStreamGetFrame()和AVIStreamGetFrameClose()來操作,可以完成對視訊流的逐幀分解。
3.2 視訊播放
對于實作視訊流的播放,VFW提供了MCIWnd視窗類[4],主要用于建立視訊播放區,控制并修改MCI視窗目前加載媒體的屬性。一個由函數、消息和宏組成的庫與MCIWnd相關聯,通過它們可以進行AVI檔案操作,很友善地使應用程式完成視訊播放功能。
1)MCIWndCreate(); //注冊MCIWnd視窗類,建立MCIWnd視窗,并指定視窗風格;
2)AVIFileInit(); //初始化;
3) AVIFileOpen(); //打開AVI檔案;
4) AVIFileGetStream(); //獲得視訊流;
5)運用相關函數進行各種播放任務:MCIWndPlay()正向播放AVI檔案内容,MCIWndPlayReverse()反向播放,MCIWndResume() 恢複播放,MCIWndPlayPause()暫停播放,MCIWndStop()停止播放等等。
6) AVIStreamRelease(); //釋放視訊流;
7)AVIFileRease();AVIFileExit(); //斷開與AVI檔案的連接配接,釋放視訊源。
由以上步驟可以看出,視訊播放是視訊編輯其中的一種操作。
——————————————————————————————————————————
●CapCreateCaptureWindow : 在進行視訊捕獲之前必需要先建立一個“捕獲窗”,并以它為基礎進行所有的捕獲及設定操作。
捕獲窗類似于标準控件(如按鈕、清單框等),并具有下列功能:
将視訊流和音頻流捕獲到一個AVI檔案中;
動态地同視訊和音頻輸入器件連接配接或斷開;
以Overlay或Preview模式對輸入的視訊流進行實時顯示;
在捕獲時,可指定所用的檔案名并能将捕獲檔案的内容拷貝到另一個檔案;
設定捕獲速率;
顯示控制視訊源、視訊格式、視訊壓縮的對話框;
建立、儲存或載入調色闆;
将圖像和相關的調色闆拷貝到剪貼闆;
将捕獲的單幀圖像儲存為DIB格式的檔案。
●CapDriverConnect : 使一個捕獲窗與一個裝置驅動程式相關聯。單獨定義的一個捕獲窗是不能工作的,它必需與一個裝置相關聯,這樣才能取得視訊信号。
●CapCaptureSetSetup,CapPreviewScale,CapPreviewRate : 設定視訊裝置的屬性。
通過設定TcaptureParms結構變量的各個成員變量,可以控制裝置的采樣頻率、中斷采樣按鍵、狀态行為等等。
設定好 TCaptureParms結構變量後,可以用函數CapCaptureSetSetup使設定生效。
之後還可以用CapPreviewScale、 CapPreviewRate來設定預覽的比例與速度,也可以直接使用裝置的預設值。
●CapOverlay,CapPreview :打開預覽。 利用函數CapOverlay選擇是否采用疊加模式預覽,這樣占用系統資源小,并且視訊顯示速度快。然後用CapPreview啟動預覽功能,這時就可以在螢幕上看到來自錄影機的圖像了。
VFW函數API總結
所有的執行個體主要使用AVICAP32.DLL中的函數和USER32.DLL中的函數,函數文法及結構如下。
(1)capCreateCaptureWindow函數
該函數用于建立一個視訊捕捉視窗。文法如下:
[DllImport("avicap32.dll")]
public static extern IntPtr capCreateCaptureWindowA
(byte[] lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int nID);
參數說明如下。
l lpszWindowName:辨別視窗的名稱。
l dwStyle:辨別視窗風格。
l x、y:辨別視窗的左上角坐标。
l nWidth、nHeight:辨別視窗的寬度和高度。
l hWnd:辨別父視窗句柄。
l nID:辨別視窗ID。
l 傳回值:視訊捕捉視窗句柄。
capCreateCaptureWindowA
Declare capCreateCaptureWindow in "avicap32.dll" as "capCreateCaptureWindowA" ;
String lpszWindowName,;
Long dwStyle ,;
Long x ,;
Long y ,;
Long nWidth,;
Long nHeight ,;
Long hwndParent,;
Long nID
函數傳回打開的句柄值。
· lpszWindowName:視訊視窗的名字
· dwStyle:樣式
· x:左邊距(相對于父視窗,一般為0)
· y:上邊距(相對于父視窗,一般為0)
· nWidth:視訊視窗的寬度(注:此項并不會改變攝像頭的分辨率,超出部分不會被重新整理)
· nHeight:視訊視窗的高度
· hWndParent:父視窗句柄
· nID:辨別符(一般為0)
這是VFW程式設計最基本的函數了,例如:
lwndC = capCreateCaptureWindowA("我的視訊監視視窗", WS_CHILD , 0, 0, 160, 120, hwnd, 0)
AVICAP.DLL是微軟公司提供的用于視訊采集的動态連結庫檔案,其中定義了視訊采集的函數。AVICAP.DLL支援實時的視訊流采集和單幀采集并提供對視訊源的控制。利用AVICAP.DLL可以友善地編寫視訊和圖像采集程式。
在AVICAP.DLL中定義了如下的接口函數:
(1)建立視訊采集視窗函數
HWND WINAPI capCreateCaptureWindowA (
LPCSTR lpszWindowName,
DWORD dwStyle,
int x, int y, int nWidth,
int nHeight,
HWND hwndParent, int nID);
其中,參數lpszWindowName指明視窗的名稱,參數dwStyle指明視窗的風格,參數x、y、nWidth和nHeight指明視窗的位置和大小,參數hwndParent指明父視窗的句柄,參數nID指明視窗辨別。
在AVICAP.DLL中還定義了一個建立視訊采集視窗函數,是capCreateCaptureWindowW,其函數原型與capCreateCaptureWindowA相同,它們的差別是前一個函數用于ANSI字元編碼方式下,而後一個函數用于UNICODE字元編碼方式下。在頭檔案VFW.H中用條件編譯和宏定義統一為capCreateCaptureWindow。
capGetDriverDescriptionA
(2)取得視訊采集裝置描述資訊函數
BOOL WINAPI capGetDriverDescriptionA (UINT wDriverIndex,LPSTR lpszName,
int cbName,LPSTR lpszVer, int cbVer);
其中,參數wDriverIndex指明裝置的索引号,參數lpszName指明裝置的名稱緩沖區的位址,參數cbName指明裝置的名稱緩沖區的大小,參數lpszVer指明裝置的描述緩沖區的位址,參數cbVer指明裝置的描述緩沖區的大小。
同樣,在AVICAP.DLL中還定義了一個取得視訊采集裝置描述資訊函數,是capGetDriverDescriptionW,它們的差別也是使用于不同的編碼方式下。在頭檔案VFW.H中統一為capGetDriverDescription。
(2)SendMessage函數
用于向Windows系統發送消息機制。
[DllImport("User32.dll")]
private static extern bool SendMessage
(IntPtr hWnd, int wMsg, int wParam, int lParam);
參數說明如下。
l hWnd:視窗句柄。
l wMsg:将要發送的消息。
l wParam、lParam:消息的參數,每個消息都有兩個參數,參數設定由發送的消息而定。
捕獲一個視訊流或目前裝置狀态時分别使用以下函數:
//捕獲一個視訊流
CapSetCallbackOnVideoStream;
//得到一個裝置錯誤
CapSetCallbackOnError;
//得到一個裝置狀态
CapSetCallbackOnStatus
}
自定義的函數1 //定義一個幀捕獲回調函數
CapSetCallbackOnFrame (ghCapWnd,LongInt(@VideoStreamCallBack));
//将一個捕獲視窗與一個裝置驅程相關聯,第二個參數是個序号,當系統中裝有多個顯視驅動程式時,其值分别依次為0到總個數
CapDriverConnect(ghCapWnd, 0);
//設定裝置屬性的結構變量
CapParms.dwRequestMicroSecPerFrame:=40000;
CapParms.fLimitEnabled := FALSE;
CapParms.fCaptureAudio := FALSE; // NO Audio
CapParms.fMCIControl := FALSE;
CapParms.fYield := TRUE;
CapParms.vKeyAbort := VK_ESCAPE;
CapParms.fAbortLeftMouse := FALSE;
CapParms.fAbortRightMouse := FALSE;
//使設定生效
CapCaptureSetSetup(ghCapWnd,LongInt(@CapParms),sizeof(TCAPTUREPARMS));
//設定預覽時的比例
CapPreviewScale(ghCapWnd, 1);
//設定預覽時的幀頻率
CapPreviewRate(ghCapWnd,66);
//如果要捕獲視訊流,則要使用函數指定不生成檔案。否則将會自動生成AVI檔案
CapCaptureSequenceNoFile(ghCapWnd);
//指定是否使用疊加模式,使用為1,否則為0
CapOverlay(ghCapWnd, 1);
//打開預覽
CapPreview(ghCapWnd, 1);
//停止捕獲
capCaptureAbort(ghCapWnd);
//将捕獲窗同驅動器斷開
capDriverDisconnect(ghCapWnd);
VFW示例
名詞解釋
avicap32.dll
avicap32.dll是Windows API應用程式接口相關子產品,用于對攝像頭和其它視訊硬體進行AVI電影和視訊的截取。
API程式設計使用方法:
'// Capture Function Declares
Declare Function capCreateCaptureWindow Lib "avicap32.dll" Alias "capCreateCaptureWindowA" _
(ByVal lpszWindowName As String, _
ByVal dwStyle As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal hwndParent As Long, _
ByVal nID As Long) As Long 'returns HWND
Declare Function capGetDriverDescription Lib "avicap32.dll" Alias "capGetDriverDescriptionA" _
(ByVal dwDriverIndex As Long, _
ByVal lpszName As String, _
ByVal cbName As Long, _
ByVal lpszVer As String, _
ByVal cbVer As Long) As Long 'returns C BOOL
user32.dll
user32.dll是Windows使用者界面相關應用程式接口,用于包括Windows處理,基本使用者界面等特性,如建立視窗和發送消息。
在早期32-bit 版本的Windows中,使用者控件是在ComCtl32中實作的,但是一些控件的顯示功能是在User32.dll中實作的。例如在一個視窗中非客戶區域(邊框和菜單)的繪制就是由User32.dll來完成的。User32.dll 是作業系統的一個核心控件,它和作業系統是緊密聯系在一起的。也就是說,不同版本的Windows中User32.dll 是不同。是以,應用程式在不同版本的Windows中運作的時候,由于User32.dll的不同,會導緻應用程式的界面通常會有微小的不同
VFW開發總結
使用VFW寫的C#控制攝像頭最大的問題就在于需要自己手動另起一個線程。(這裡,我們定義一個叫AviCapture.cs的類,用于引入avicap32.dll以及相關的内容)在avicap32.dll中,CAPTUREPARMS結構裡有一個fYield的東東,代表的意思是另起線程标志位,如果為真,則程式重新啟動一個線程用于視訊流的捕獲,預設值是假。但是如果你是為了真,你必須要在程式中處理一些潛在的操作,因為當視訊捕獲時,其他操作并沒有被屏蔽。。在AviCapture這個類的基礎上定義一個叫Video的類(自己定義的),實作控制設想頭的一些方法,如打開攝像頭,關閉攝像頭,開始錄像,結束錄像,拍照片等等。。。。在Video類中還要定義兩個C#控制攝像頭函數如下:
使用如下代碼加入視訊捕獲,
function capCreateCaptureWindow(
lpszWindowName : LPCSTR;
dwStyle : DWORD;
x, y : int;
nWidth, nHeight : int;
hwndParent : HWND;
nID : int
): HWND;
lpszWindowName: 是捕獲視窗的名稱,可以是任意字元串,delphi中是pchar類型
dwStyle: 是捕獲視窗的類型,一般設為WS_CHILD | WS_VISIBLE.
x, y, nWidth, nHeight: 是顯示捕獲視訊的rect
hwndParent: 是顯示視訊視窗的句柄
nID : 預設為0;
函數傳回值Hwnd類型,即攝像裝置的句柄,以後的操作基本上都是針對裝置句柄進行的.
然後用function capDriverConnect(hwnd: HWND; i: INT): BOOL;連接配接裝置的驅動,
hwnd為裝置句柄,i是驅動的序号(如果系統裝有多個裝置驅動,要選擇一個正确的驅動才行,這些稍後在介紹).
驅動連接配接成功後
,用function capPreviewRate(hwnd: HWND; wMS: WORD):
BOOL
;函數設定預覽時的幀速,wMS為幀速值(機關:幀/秒),一般取值範圍(10-30).
設定完速率後
,用function
capPreview(hwnd: HWND; f: BOOL): BOOL;函數進行預覽了,設定f為true後就可以看到攝像頭的畫面了.
以上簡單的顯示了視訊畫面,但是在顯示視訊畫面的過程中還要進行一些參數的設定.今天就Ok了.
視窗句柄 (HWND)。
m_hCapWnd=capCreateCaptureWindow((LPTSTR)TEXT("視訊捕捉測試程式"),WS_CHILD|WS_VISIBLE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME,0,0,rect.Width(),rect.Width(),pWnd ->GetSafeHwnd(),0); // 設定預示視窗
ASSERT(m_hCapWnd);
if(capDriverConnect(m_hCapWnd,0)){// 連接配接第0 号驅動器
m_bInit=TRUE;
// 得到驅動器的性能
capDriverGetCaps(m_hCapWnd,sizeof(CAPDRIVE RCAPS), &m_CapDrvCap);
if(m_CapDrvCap.fCaptureInitialized){
// 如果初始化成功
capGetStatus(m_hCapWnd, &m_CapStatus,sizeof(m_CapStatus)); // 得到驅動器狀态
capPreviewRate(m_hCapWnd,30); // 設定預示幀頻
capPreview(m_hCapWnd,TRUE); // 設定預示方式
}
else{// 初始化未成功
AfxMessageBox("視訊捕捉卡初始化失敗!");
AfxGetMainWnd() ->PostMessage (WM_CLOSE);
}
}
else{// 未能連接配接到驅動器
AfxMessageBox("與視訊捕捉卡連接配接失敗!");
AfxGetMainWnd() ->PostMessage(WM_CLOSE);
}
m_CapFileName="c://Capture.avi";// 設定捕獲檔案
capFileSetCaptureFile(m_hCapWnd,m_CapFileName.GetBuffer(255));
5、在對話框類中加入響應“設定格式”消息的函數OnFormat()。
capDlgVideoFormat(m_hCapWnd);// 設定格式對話框
6、在對話框類中加入響應“設定圖像源”消息的函數OnSource()。
capDlgVideoSource(m_hCapWnd);// 設定圖像源對話框
7、在對話框類中加入響應“設定壓縮”消息的函數OnCompress()。
capDlgVideoCompression(m_hCapWnd);// 設定壓縮對話框
8、在對話框類中加入響應“捕捉”消息的函數OnCapture()。
capCaptureGetSetup(m_hCapWnd, &m_Parms,sizeof(m_Parms));// 得到設定參數
if(capCaptureSetSetup(m_hCapWnd, &m_Parms,sizeof(m_Parms))==TRUE){
BOOL suc=TRUE;
suc=capCaptureSequence(m_hCapWnd); // 捕捉到檔案
return suc};
else
return FALSE;
注意點:在VideoCaptureDlg.h中把afx_msg void OnCapture();改為afx_msg BOOL OnCapture();
在VideoCaptureDlg.cpp 修改為BOOL CVideoCaptureDlg::OnCapture() //捕捉
9、在對話框類中加入響應“定幀”消息的函數OnFreezed()。
capPreview(m_hCapWnd,FALSE);// 定幀
10、在對話框類中加入響應“單幀捕獲”消息的函數OnImage()。
capGrabFrameNoStop(m_hCapWnd);// 截獲目前圖像
capEditCopy(m_hCapWnd);// 将圖像拷貝到剪貼闆
11、在對話框類中加入響應“停止”消息的函數OnStop()。
capCaptureStop(m_hCapWnd);// 停止捕捉
12、在對話框類中加入響應“退出”消息的函數OnExit()退出前斷開捕捉器與驅動器的連接配接,并關閉視窗。
capDriverDisconnect(m_hCapWnd);
CDialog::OnCancel();
附加說明:以上添加的按鈕用于捕捉圖像(button);
另外添加(Static Text)用于建立并設定捕獲視窗;
儲存圖像的方法:點選“單幀捕獲”——>打開附近裡的“畫圖”——>“編輯”中的“粘貼”——>即可儲存捕捉的位圖。
以上方法主要是采用了VFW的函數和宏,有興趣的朋友可以嘗試用消息的方法,同樣也可以實作。
如:SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0, 0L);//用于連接配接裝置
要做的就是根據相關的功能改變相應的參數就可以了。
capCreateCaptureWindow(
lpszWindowName : LPCSTR;
dwStyle : DWORD;
x, y : int;
nWidth, nHeight : int;
hwndParent : HWND;
nID : int
): HWND;
lpszWindowName: 是捕獲視窗的名稱,可以是任意字元串,delphi中是pchar類型
dwStyle: 是捕獲視窗的類型,一般設為WS_CHILD | WS_VISIBLE.
x, y, nWidth, nHeight: 是顯示捕獲視訊的rect
hwndParent: 是顯示視訊視窗的句柄
nID : 預設為0;
函數傳回值Hwnd類型,即攝像裝置的句柄,以後的操作基本上都是針對裝置句柄進行的.
然後用function capDriverConnect(hwnd: HWND; i: INT): BOOL;連接配接裝置的驅動,hwnd為裝置句柄,i是驅動的序号(如果系統裝有多個裝置驅動,要選擇一個正确的驅動才行,這些稍後在介紹).
驅動連接配接成功後,用function capPreviewRate(hwnd: HWND; wMS: WORD): BOOL;函數設定預覽時的幀速,wMS為幀速值(機關:幀/秒),一般取值範圍(10-30).
設定完速率後,用function capPreview(hwnd: HWND; f: BOOL): BOOL;函數進行預覽了,設定f為true後就可以看到攝像頭的畫面了.
以上簡單的顯示了視訊畫面,但是在顯示視訊畫面的過程中還要進行一些參數的設定.今天就Ok了.
1、 int intDevice = 0;是什麼意思?起初我猜測0表示第一個攝像頭,那麼1不就表示第二個攝像頭嗎?經過我的嘗試發現并非如此,那麼0到底是什麼意思呢?
回答:這隻是捕獲視窗的視窗名稱而已。你可以看到實際上他轉換成了String類型,在capCreateCaptureWindow裡面作為第一個參數,這個參數就是表示視窗名稱。
2、hHwnd = Camera1.capCreateCaptureWindowA(ref refDevice, 1342177280, 0, 0, 640, 480, this.panel1.Handle.ToInt32(), 0);各個參數的含義,這個我從msdn中查到了,但是對于第二個參數和最後一個參數還是不了解,希望大家給以解答。
回答:第二個參數表示窗體風格,也就是CreateWindow的時候都要使用的,具體的說就是表示你窗體有沒得邊框啦,支援不支援拖放拉等等。這個可以去MSDN裡面查 CreateWindowEx 函數便知。
最後一個參數表示視窗辨別符。隻要每個窗體不一樣,能區分即可。
3、Camera1.SendMessage(hHwnd, 0x40a, 0, 0),第一個參數是句柄,第二個參數表示的是一個消息,是哪個消息呢?後兩個參數是到底為消息提供什麼樣的東西呢?
回答:0x40a 表示 WM_CAP_DRIVER_CONNECT消息,後面兩個參數表示消息附帶的兩個參數,每個消息都有兩個參數的。按照VFW的規定,第一個參數是捕獲裝置的索引。這兒是0,表示你的第一個捕獲裝置。第二參數恒為0。為什麼?VFW就是這麼規定的。
你要連接配接兩個攝像頭,着眼點就是這兒,隻需要重新建立一個鋪貨視窗,并連接配接到另外一個攝像頭的驅動上,事先知道裝置ID就行了。這個可以通過裝置枚舉獲得,具體參見MSND中Enumerating Installed Capture Drivers相關章節。就OK了。
4、 Camera1.SendMessage(this.hHwnd, 0x435, -1, 0);
Camera1.SendMessage(this.hHwnd, 0x434, 0x42, 0);
Camera1.SendMessage(this.hHwnd, 0x432, -1, 0);
分别表示的意思是什麼?
回答:0x435表示WM_CAP_SET_SCALE,可以打開或者關閉預覽的比例縮放,後面是參數,這些都可以在MSDN中查到。我就不說了。比如這裡是-1就是表示為真,也就是說圖像會根據視窗大小進行縮放。
0x434表示WM_CAP_SET_PREVIEWRATE,這個是設定顯示速度的。也就是幀率。
0x432表示WM_CAP_SET_PREVIEW,這個辨別打開關閉預覽模式。這兒是-1,自然表示為真,也就是打開了。
5、在一個程式中,能不能同時使用兩個攝像頭,需不需要第三方軟體的支援?
回答:當然可以。不需要三方支援。這是微軟的活兒,隻有别人依賴他支援,怎麼可能微軟還需要依賴别人。
解釋一下,什麼是回調函數呢,它有什麼用處?
回調函數,就是你自己寫的函數,符合規定的參數和傳回值類型,符合規定的調用約定,比如上面這個函數
就是回調函數,參數和傳回值類型都是規定好的,調用約定為CALLBACK,CALLBACK
其實是一個宏
#define CALLBACK__stdcall
滿足一定條件時,此函數可以被系統自動調用,在回調函數當中,你可以寫自己的代碼完成一定功能。
比如在這裡,用capSetCallbackOnFrame(m_hVideo, FrameCallbackProc)注冊後,當每得到一桢資料後,系統就
調用函數FrameCallbackProc。
但是,我的目的還沒有達到,我其實想在每一桢顯示之前,能處理一下這一桢的資料,那麼,去哪裡找這桢資料存
放的位置呢?
(8)為了完成我的目标,我把步驟(7)中的兩句代碼先注釋掉。在對話框上加一個按鈕,并在對單擊做出響應的響應函數
中寫下面代碼:
capGrabFrame(m_hVideo);
這是一個宏,将滑鼠移動到這段代碼上,右鍵單擊,選擇Go To Definition of capGrabFrame,你會看到
#define capGrabFrame(hwnd)((BOOL)AVICapSM(hwnd, WM_CAP_GRAB_FRAME, (WPARAM)0, (LPARAM)0L))
而繼續察看AVICapSM宏你會看到其實是在調用SendMessage函數呢,對吧,其實就是在發送消息。至于消息誰處理了,我們就不去
關心了,我們關心的是,發送消息後,系統會調用我們剛才注冊的回調函數
LRESULT CALLBACK FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) ;
(9)好了,如果你單擊按鈕,capGrabFrame(m_hVideo)就發送消息了,然後,我們就進入回調函數了,這太好了。
看到回調函數傳遞的兩個參數了麼?我們更關心第二個參數,這個就是單擊按鈕我們捕捉到的一桢資料的入口啊!
LPVIDEOHDR 是結構體VIDEOHDR的指針,而在MSDN中察看結構體VIDEOHDR,我們就可以找到桢資料的存貯位置指針了。
VIDEOHDR定義如下:
typedef struct videohdr_tag {
LPBYTElpData;
DWORDdwBufferLength;
DWORDdwBytesUsed;
DWORDdwTimeCaptured;
DWORDdwUser;
DWORDdwFlags;
DWORD_PTRdwReserved[4];
} VIDEOHDR, NEAR *PVIDEOHDR, FAR * LPVIDEOHDR;
看到結構體中第一個參數了麼?這個就是我們想要的桢資料的指針!後面參數,包括緩沖區長度等。
(10)終于得到了緩沖區的資料,可是,又一個問題出現了,緩沖區中的資料到底具體是啥含義啊?
這桢圖像多大啊?size 是多少乘多少的啊?就是我們想要的像素資訊麼?
好的,我先告訴你,緩沖區中全部是像素資訊,我們照着我的步驟這樣做,其實是預設了一些參數,包括圖像的
長度,寬度,色彩數,等等,那麼,這個預設的值是多少呢?
(11)用一下capGetVideoFormat宏吧,你會得到想要的東西。
在BOOL CGraspDlg::OnInitDialog()中繼續添加如下代碼:
BITMAPINFO bmpInfo;
capGetVideoFormat(m_hVideo,&bmpInfo,sizeof(BITMAPINFO));
BITMAPINFO結構體内容自己看MSDN.定義如下
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUADbmiColors[1];
} BITMAPINFO, *PBITMAPINFO;
而BITMAPINFOHEADER定義如下:
typedef struct tagBITMAPINFOHEADER{
DWORDbiSize;
LONGbiWidth;
LONGbiHeight;
WORDbiPlanes;
WORDbiBitCount;
DWORDbiCompression;
DWORDbiSizeImage;
LONGbiXPelsPerMeter;
LONGbiYPelsPerMeter;
DWORDbiClrUsed;
DWORDbiClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
加入步驟(11)的兩句話,調試運作,我發現,bmpInfo.bmiHeader.biWidth為320,就是采集的圖像寬度;
bmpInfo.bmiHeader.biHeight為240,就是采集的圖像高度,這些都是預設值,也可以改變這些值,通過
capSetVideoFormat宏來實作。
(12)那麼,我們在步驟(9)中,回調函數第二個參數對應的結構體VIDEOHDR中,圖像資料緩沖區的大小
dwBufferLength是多少呢?我們可以在回調函數中加一個MessageBox函數,輸出這個值,
我們就可以發現,為230400,這個數很好,正好等于圖像寬度X圖像高度的3倍,
也就是說,是圖像像素數目的3倍,這就對了,每個像素用3個位元組存儲的嘛。好啦,我們知道了,桢緩沖區中,存儲
的完全是圖像的像素資訊,那麼,具體哪個值對應哪個像素呢?
存儲順序是這樣的:先從圖像最下面一行開始,從左向右,依次存儲,每一個像素用連續的3個位元組,分别為B(藍色分量),
G(綠色分量),R(紅色分量)。然後存儲倒數第二行,仍然按照圖像從左向右存儲,然後倒數第三行,
倒數第四行。。。。。。等等,最後存儲正數第一行。
事件委托和委托有啥差別啊?委托不是就夠了嗎?為什麼還要事件委托呢
最佳答案
1.
事件在本類型外部隻能用“+=”和“-=”去訂閱/取消訂閱代理,
委托不管在本類型外部還是内部都可以用“+=”、“-=”和“=”訂閱/取消訂閱代理。
2.
事件隻能在本類型内部“觸發”,
委托不管在本類型内部還是外部都可以“調用”。
即:事件,隻有本類才能激發這個事件,如果用委托取代的話,可想而知,
舉個例子,按鈕的Click事件,隻有你的滑鼠點選按鈕才能由按鈕觸發,如果Click是委托的話,不管滑鼠點選不單擊那個按鈕,我隻要用程式調用這個委托,就可以使得按鈕激發Click事件,完全不符合事實,