windows下編程控制攝像頭的詳細介紹

這段時間閒來無事,看了看MSDN的文檔,自己翻譯了一下。一是爲了學習,二是對空閒時間的打發。所以也希望大家在拍磚的同時,尊重我的勞動,如要轉貼請註明轉至blog.csdn.net/suntaoznz。謝謝!

                                                                                                                 孫濤 2005-8-6

Microsoft® Video for Windows® (VFW) 提供的函數可以讓應用程序去處理視頻數據。 VFW 在16位Windows的時候就被引入了。它的許多重要功能已經被DirectX取代了。 要獲得更多的信息,你可以參考DirectX 的文檔。
下面講介紹VFW的視頻捕獲:

3.視頻捕獲
你可以使用windows的AVICap 類輕鬆地完成視頻捕獲。AVICap 提供給應用程序一個簡單的、基於消息的接口去訪問視頻設備和錄音設備,並且可以控制處理視頻流捕獲。

3.1 關於視頻捕獲 
AVICap支持實是視頻流捕獲和實時單幀圖像捕獲。另外,AVICap 提供了對視頻源的控制(MCI媒體控制接口設備),因此使用者可以通過應用程序控制一個視頻源開始和結束的位置,並且可以加大對幀捕獲的控制。

你使用AVICap 類可以完成如下的任務:


 

l         捕獲聲音和視頻,並將他們寫入到一個AVI文件中。

l         動態連接和斷開視頻和音頻的輸入設備。

l         使用覆蓋或預覽的方法去顯示當前的視頻信號。

l         指定一個文件用於捕獲,並且把這個捕獲文件的內容拷貝給另一個文件。

l         設定捕獲圖像速度(好多幀)。

l         顯示對話框用於控制視頻源和格式。

l         創建、保存、加載調色板。

l         拷貝圖像和調色板到剪貼板中。

l         捕獲並把圖像作爲一個DIB位圖保存。


 

3.1.1視頻捕獲:最簡單的方法

 

視頻捕獲將數字化一個視頻流和音頻數據,並且將他們保存在硬盤和其他存儲設備上。

這裏將描述如何在應用程序中簡單地應用視頻捕獲,它通過三句代碼實現。它還介紹瞭如何通過發送消息給視頻捕獲窗口來結束或中斷一個視頻會話。

AVICap 捕獲窗口可以把捕獲的音視頻信息寫入一個AVI文件中。你的應用程序可以自由地處理這個AVI文件、管理緩存區的音視頻數據、還可以在底層訪問音視頻設備的驅動器。AVICap爲應用程序提供了一個靈活的接口。你可以使用下面的代碼,在你的應用程序中加入視頻捕獲:


 

HWndC  =  capCreateCaptureWindow ( "My Own Capture Window",

            WS_CHILD | WS_VISIBLE  ,  0 ,  0,  160,  120,  hwndParent,  nID);

SendMessage  ( hWndC,  WM_CAP_DRIVER_CONNECT,  0 /* wIndex */,  0L);

SendMessage  ( hWndC,  WM_CAP_SEQUENCE,  0,  0L);

 

宏接口同樣有用,你可以選擇是使用宏接口還是SendMessage 函數來實現上面的功能,不過宏接口可以讓你的代碼更加容易理解。下面就使用了宏接口。


 

HWndC  =  capCreateCaptureWindow (" My Own Capture Window ",

    WS_CHILD | WS_VISIBLE ,  0,  0,  160,  120,  hwndParent,  nID);

capDriverConnect  ( hWndC,  0);    // 宏接口

capCaptureSequence  ( hWndC);     // 宏接口

 

你的應用程序創建AVICap捕獲窗口,並和視頻設備建立連接後。你創建的這個捕獲窗口就準備捕獲數據了。這時,你可以通過發送WM_CAP_SEQUENCE消息(或capCaptureSequence 宏)開始對數據進行捕獲。


 

WM_CAP_SEQUENCE將使用默認設置,開始對視頻和音頻進行捕獲,並把數據放在一個CAPTURE.AVI的文件中,捕獲動作將一直持續,除非有下面的事件發生:

l         用戶按了ESC鍵或者鼠標的按鈕。

l         你的應用程序停止或者退出了捕獲操作。

l         磁盤寫滿了。

 

在應用程序中,你可以通過發送WM_CAP_STOP命令(或capCaptureStop)給捕獲窗口,讓它停止向文件寫數據。你還可以通過發送WM_CAP_ABORT命令(或capCaptureAbort)給捕獲窗口,讓它中斷捕獲操作。


 


 

3.1.2捕獲基本設置

 

通過對定義在CAPTUREPARMS結構中的捕獲參數進行修改,你可以完成:

l         改變捕獲的幀頻律(幀/秒);

l         指定用鍵盤或鼠標去結束一個捕獲會話;

l         爲一個捕獲會話指定時間週期;


 

捕獲的幀頻率


 

捕獲的幀頻率表示在一個捕獲會話中,每秒要捕獲多少幀。你通過WM_CAP_GET_SEQUENCE_SETUP 消息(capCaptureGetSetup宏)可以得到當前捕獲的幀頻率。當前的幀頻率被保存在CAPTUREPARMS結構的dwRequestMicroSecPerFrame 成員中。你可以對該值進行修改,從而去改變幀頻率。該值爲捕獲一幀要用的時間(單位是微秒 1/1000000秒),修改後,你可以發送WM_CAP_SET_SEQUENCE_SETUP消息(或capCaptureSetSetup宏)給你的捕獲窗體,來刷新CAPTUREPARMS 結構。dwRequestMicroSecPerFrame 默認值是66667微秒,表示每秒15幀。(1000000/15=66667)

 

 

退出數據捕獲


 

你可以讓用戶按這幾種方法退出一個捕獲會話,按鍵盤上的一個鍵或幾個組合鍵、或者按鼠標的左鍵或者是右鍵。如果用戶退出一個實時的捕獲會話,那麼捕獲文件中的內容將被系統丟棄掉。如果用戶退出一個步幀(step-frame)捕獲的會話,捕獲文件將保存到退出時刻前的所有數據。

       你可以通過發WM_CAP_GET_SEQUENCE_SETUP消息(或capCaptureGetSetup宏)給捕獲窗口,來獲得捕獲退出的設置信息。當前的退出按鈕設置保存在CAPTUREPARMS結構的vKeyAbort 成員中,當前的退出鼠標設置保存在fAbortLeftMouse和 fAbortRightMouse成員中。你可以改變這幾個成員,實現對當前值的修改。當你修改完成後,你可以發送WM_CAP_SET_SEQUENCE_SETUP消息(或capCaptureSetSetup宏)給你的捕獲窗體,來刷新CAPTUREPARMS 結構。

vKeyAbort 默認值是 VK_ESCAPE。在重新指定其他按鍵前,你必須調用RegisterHotKey 函數。fAbortLeftMouse 和 fAbortRightMouse 是TRUE。


 

時間限定


 

通過使用CAPTUREPARMS結構的fLimitEnabled 和wTimeLimit成員,你可以去限定一個捕獲操作的時間週期。fLimitEnabled 表示是否要對捕獲操作限定時間, wTimeLimit 用於指定限定時間的最大值。

    你發WM_CAP_GET_SEQUENCE_SETUP消息(capCaptureGetSetup宏)給捕獲窗口,就可以得到fLimitEnabled 和 wTimeLimit的值。 FLimitEnabled爲TRUE表示要指定時間週期。WTimeLimit單位爲秒。修改完成後,你可以發送WM_CAP_SET_SEQUENCE_SETUP消息(或capCaptureSetSetup宏)給你的捕獲窗體,來刷新CAPTUREPARMS 結構。

fLimitEnabled 默認值爲FALSE.


 


 

3.1.3捕獲窗口

 

捕獲窗體類似於一個標準控件(不如按鈕、列表框…),它一般使用WS_CHILD 和 WS_VISIBLE窗口類型。.


 

創建一個AVICap捕獲窗口

       使用capCreateCaptureWindow 函數可以創建一個AVICap的捕獲窗口。這個函數返回一個窗口句柄,這個句柄就是捕獲窗口的句柄,後面其他操作就是通過發送消息給該句柄來實現。你可以在一個程序中創建多個捕獲窗口,並且每個窗口連接到不同的捕獲設備上。


 

建立捕獲窗口到捕獲設備的連接

你可以動態地連接或斷開捕獲窗口與設備間的鏈接。通過使用WM_CAP_DRIVR_CONNECT消息(或capDriverConnect宏),可以實現捕獲窗體與設備驅動間的連接。當捕獲窗體和捕獲設備驅動連接後,你就可以發送針對設備的消息給該窗體了。

如果你的系統安裝了多個捕獲設備,你可以通過在發送WM_CAP_DRIVER_CONNECT消息時,設置wPrarm參數(integer)。來指定捕獲窗口與那個具體的視頻捕獲設備相連接。

WPrarm參數是一個整數,它表示一個系統已經安裝的視頻捕獲設備列表的索引(註冊表中或這System.ini [drivers]中的信息)。該列表的索引從0開始。

       通過capGetDriverDescription函數可以獲得安裝的捕獲驅動程序的名稱和版本。你的應用程序可以使用這個函數列舉除安裝的所有捕獲設備,讓用戶可以選擇其中一個去與捕獲窗口相聯。

通過發送WM_CAP_DRIVER_GET_NAME消息(capDriverGetName宏),可以獲得與指定窗體連接的捕獲設備的名稱。通過發送WM_CAP_DRIVER_GET_VERSION消息(capDriverGetVersion宏),可以獲得與指定窗體連接的捕獲設備的版本。

通過發送WM_CAP_DRIVER_DISCONNECT消息(capDriverGetDisconnect宏),可以斷開連接。當捕獲窗體銷燬後,任何連接的視頻捕獲設備都將自動斷開。


 

父子窗體交付

       一些系統級的消息,比如 WM_PALETTECHANGED、WM_QUERYNEWPALETTE,只被發送到頂層(top-level)和overlapped窗口。如果一個捕獲窗體是一個資窗體,那它的父窗口應該來轉寄這些消息。

       同樣地,假如父窗口尺寸改變了,它可能需要發送一個通知消息給捕獲窗口。相反,如果捕獲視頻尺寸變化了,捕獲窗口可能需要發一個通知消息給父窗口。最簡單的管理方法是讓捕獲窗口的尺寸等於捕獲視頻流的尺寸,隨時把改變的尺寸告訴給父窗口。


 

捕獲窗體狀態


 

通過發送WM_CAP_GET_STATUS消息(capGetStatus宏),可以獲得當前捕獲窗口的狀態。這個消息得到一個CAPSTATUS結構體的拷貝,狀態信息就在這個結構體的成員中。

CAPSTATUS 結構體包含了圖形尺寸大小、滾動位置(scroll position)、是否覆蓋(overlay)或者預覽(preview)等信息。因爲在CAPSTATUS 中的信息是動態的,你的應用程序應該隨時去刷新這個結構體中的內容。

改變捕獲窗口的尺寸對實際的視頻流的尺寸沒有影響。


3.1.4捕獲和音頻驅動器 
      

視頻捕獲可以做這幾個方面的工作:訪問 視頻源、顯示選項、格式和壓縮選項。音頻捕獲包括指定音頻格式和選擇壓縮方式。


 

捕獲驅動性能


 

通過發送WM_CAP_DRIVER_GET_CAPS消息(capDriverGetCaps宏),可以獲得當前連接的捕獲設備的性能。發送該消息後,會返回一個CAPDRIVERCAPS結構的對象。設備的性能信息,就在這個對象中。


 


 

視頻對話框(Video Dialog Boxes)

      

每個捕獲設備的驅動程序都可以爲控制視頻信號和捕獲處理和視頻壓縮提供4個對話框。這些對話框中的內容都是視頻捕獲驅動程序定義的。

      

視頻源對話框(Video Source dialog box)用於選擇視頻輸入通道和視頻圖像的動態參數。 它可以列舉出當前連接視頻設備的信號類型(SVHS和複合類型),並且可以通過該對話框去修改圖像的色調、亮度、飽和度。你可以通過使用WM_CAP_DLG_VIDEOSOURCE 消息 (或 capDlgVideoSource 宏)來顯示和刷新這個窗口。


 

視頻格式對話框(Video Format dialog box)用於選擇數字視頻的框架大小和視頻圖像的色深,以及捕獲視頻圖像的壓縮格式。你可以通過使用WM_CAP_DLG_VIDEOFORMAT消息 (或 capDlgVideoFormat宏)來顯示和刷新這個窗口。


 

視頻顯示對話框(Video Display dialog box)用於控制視頻外觀。在該對話框上進行了修改只是對視頻顯示起作用,對於實際的視頻數據是不會造成改變的。比如,可以改變顯示的顏色,飽和度等等....。你可以通過使用WM_CAP_DLG_VIDEODISPLAY消息 (或 capDlgVideoDisplay宏)來顯示和刷新這個窗口。


 

視頻壓縮對話框(Video Compression dialog box)用於設置視頻壓縮的格式。通過使用WM_CAP_DLG_VIDEOCOMPRESSION消息 (或 capDlgVideoCompression宏)來顯示和刷新這個窗口。


 

預覽和覆蓋模式 (Preview and Overlay )

      

一般,一個捕獲驅動提供兩種方式來觀看輸入的視頻流:預覽模式和覆蓋模式。如果捕獲驅動可以提供上面兩種模式,那麼用戶就可以選擇其中的模式來使用。


 

預覽模式從捕獲設備硬件傳輸數據幀到系統的內存中,並且在捕獲窗口中使用GDI函數來顯示這些數據幀。當捕獲窗口的父窗體失去焦點的時候,在應用程序的視頻預覽的數據將變慢,如果父窗體獲的焦點後,將對預覽顯示進行加速。因爲預覽處理的這種處理方式將大大提高整個系統的效率。

這裏用3個消息用於控制預覽操作。

l         WM_CAP_SET_PREVIEW消息(capPreview宏)可以打開或者關閉預覽模式。

l         WM_CAP_SET_PREVIEWRATE 消息(capPreviewRate宏)可以設置預覽模式下圖像的幀速度。

l         WM_CAP_SET_SCALE 消息 (capPreviewScale 宏) 打開或者關閉預覽視頻的縮放比例。

當預覽和縮放比例屬性都打開後,那麼視頻將被縮放到和捕獲窗口尺寸一樣大。打開預覽模式後,系統將自動關閉覆蓋模式。


 

覆蓋模式,將不佔用CPU的處理資源,直接在顯示器上顯示視頻內容。所用的處理是有捕獲設備硬件來完成。發送WM_CAP_SET_OVERLAY消息(或capOverlay宏)給捕獲窗口,可以打開覆蓋模式。打開覆蓋模式後,將自動關閉預覽格式。


 

無論是預覽模式還是覆蓋模式,都可以通過發送WM_CAP_SETSCROLL消息(capSetScroollPos宏),可以設置圖像的在整個視頻幀的滾動位置(scroll position)。


 


 

視頻格式


 

       通過發送WM_CAP_GET_VIDEOFORMAT消息(capGetVideoFormat宏)給視頻捕獲窗口可以得到一個結構,在這個結構體中就包含了視頻的格式、大小。

       通過發送WM_CAP_SET_VIDEOFORMAT消息(capSetVideoFormat宏)給視頻捕獲窗口可以對視頻格式進行修改設置。

You can set the format of captured video data by sending the WM_CAP_SET_VIDEOFORMAT message (or the capSetVideoFormat macro) to a capture window.


 

視頻捕獲設置


 

CAPTUREPARMS 數據結構包括了視頻流的控制參數。它允許完成如下的任務:

l         指定幀速度(Frame rate)。

l         指定爲視頻分配的緩存大小。

l         關閉或者打開音頻捕獲。

l         設定捕獲的時間間隔。

l         指定捕獲設備(MCI設備、VCR或者影碟)。

l         指定鍵盤或鼠標去控制結束捕獲。

l         指定適用的視頻類型


 

通過發送WM_CAP_GET_SEQENCE_SETUP消息(capCaptureGetSetup)給捕獲窗體,可以獲得一個CAPTUREPARMS數據結構的對象,當前視頻捕獲的設置信息就在這裏面。


 

你可以改寫CAPTUREPARMS對象的成員,來實現對視頻捕獲信息的修改。修改後,發送WM_CAP_SET_SEQUENCE_SETUP消息(capCaptureSetSetup)給捕獲窗體,並把這個CAPTUREPARMS 對象發給捕獲窗體,就可以實現修改。


 

音頻格式


 

通過發送WM_CAP_GET_AUDIOFORMAT消息(capGetAudioFormat 和capGetAudioFormatSize宏)給捕獲窗體,你就可以獲得當前的音頻數據格式或音頻數據結構的大小。默認音頻捕獲格式是 mono, 8-bit, 11 kHz PCM。

當你使用WM_CAP_GET_AUDIOFORMAT消息得到音頻格式後,通常會使用WAVEFORMATEX這個數據結構。

通過發送WM_CAP_SET_AUDIOFORMAT消息(capSetAudioFormat宏)給捕獲窗體,你可以設置音頻數據捕獲格式。當設置這個音頻格式時,你可以通過一個指針指向一個WAVEFORMAT ,WAVEFORMATEX,或者PCMWAVEFORMAT數據結構。


 

3.1.5捕獲文件和緩存區

 

捕獲文件名


 

AVICap默認,把音視頻數據從捕獲窗口保存到當前驅動得根目錄下,文件名稱爲CAPTURE.AVI。發送WM_CAP_FILE_SET_CAPTURE_FILE消息(capFileSetCaptureFile)給捕獲窗體,可以改變保存的文件名。這個消息指定文件名;它不實際創建文件,分配空間,也不能打開文件。通過發送WM_CAP_FILE_GET_CAPTURE_FILE消息(capFileFGetCaptureFile宏)給捕獲窗口,就可以得到當前文件名。


 

保存捕獲數據到一個新文件


 

如果用戶想保存捕獲數據,把數據存到另外一個文件中。可以使用WM_CAP_FILE_SAVEAS消息(capFileSaveAs宏) 。這個消息不能改變捕獲文件的名稱和內容。你必須去指定新建的文件名,因爲捕獲文件將保留原來的文件名稱。


 

爲捕獲文件預分配磁盤空間


 

在捕獲操作前,先在磁盤上爲捕獲文件建一個指定大小的文件。預分配空間將減少數據保存時的處理時間。可以通過WM_CAP_FILE_ALLOCATE消息(capFileAlloc宏)來預分配一個捕獲文件。

你要預分配足夠大的磁盤空間去保存預計最大的捕獲文件。預分配磁盤空間沒有限定捕獲文件的大小。如果捕獲的數據大於了分配的空間,文件尺寸將自動變大。對一個捕獲文件進行重寫數據,將對文件的已經分配的磁盤空間進行重寫。

通過對捕獲文件進行磁盤碎片整理可以提高捕獲性能。要對文件進行碎片整理,可以使用一個碎片整理工具來完成,比如Disk Defragmenter。

通過使用沒壓縮的磁盤來保存數據,同樣可以提高性能。因爲在捕獲期間壓縮數據將對磁盤的吞吐量進行限制。


 

索引大小


 

       在每個AVI文件中都會使用一個指定大小的索引去查找音視頻數據塊。在一個索引的入口定位了一個視頻幀或者一個波形聲音的緩存器。所以,這個索引的大小簡接地限定了一個捕獲文件所能保存的幀的數量上限。

通過發送WM_CAP_GET_SEQUENCE_SETUP消息(capCaptureGetSetup宏)給捕獲窗口就可以得到當前的索引大小。這個索引大小就保存在CAPTUREPARMS數據結構對象的一個成員中(dwIndexSize)。你可以在dwIndexSize中指定一個新的索引大小,並通過發送消息WM_CAP_SET_SEQUENCE_SETUP(capCaptureSetSetup宏)給捕獲窗口完成信息設置。索引默認大小34,952 (允許32K 幀和想匹配的聲音緩存器).


音視頻塊的間隔尺寸(Granularity)


 

數據塊的間隔尺寸是一個AVI文件的邏輯塊大小。它用於寫和讀音視頻數據塊。當向磁盤寫音視頻數據時, AVICap 將在每個數據塊中加入一個必須的填充塊(filler chunks (RIFF "JUNK" chunks)) 去填充滿該數據塊。

你可以使用WM_CAP_GET_SEQUENC_SETUP消息(capCaptureGetSetup)去獲得當前的塊間隔尺寸(Granularity)。CAPTUREPARMS的wChunkGranularity 成員保存的是當前的塊間隔尺寸信息。通過對該成員的改寫,併發送WM_CAP_GET_SEQUENC_SETUP消息(capCaptureSetSetup),可以對其進行修改。你設置該參數爲零的話,那麼塊間隔尺寸的值就爲磁盤的扇區大小。


 

視頻緩存區


 

這個緩存區將視頻數據放在內存的堆中。緩存區的大小可以改變,並且它的大小是由CAPTUREPARMS的wNumVideoRequested 成員和系統可以的內存大小來決定。

你可以使用WM_CAP_GET_SEQUENC_SETUP消息(capCaptureGetSetup)去獲得當前的視頻緩存區的大小。CAPTUREPARMS的wNumVideoRequested 成員保存的是當前的緩存區尺寸。通過對該成員的改寫,併發送WM_CAP_GET_SEQUENC_SETUP消息(capCaptureSetSetup),可以對其進行修改。


 

音頻緩存區


 

你可以使用下面三種方法來控制捕獲的音頻數據:


 

l         在捕獲中包含音頻或者不包含音頻

l         按要求指定音頻緩存區的大小

l         Request that audio buffers be a specific size.


 

你可以使用WM_CAP_GET_SEQUENC_SETUP消息(capCaptureGetSetup)去獲得當前的音頻緩存區的設置。CAPTUREPARMS的fCaptureAudio指定在這次捕獲操作中是否包括對聲音的捕獲。WNumAudioRequested保存當前要求的音頻緩存區的大小。dwAudioBufferSize 保存當前的音頻緩存區的大小。

通過對該成員的改寫,併發送WM_CAP_GET_SEQUENC_SETUP消息(capCaptureSetSetup),可以對其進行修改。

fCaptureAudio 默認值是TRUE。The default buffer size (the value of) can contain 0.5 seconds of audio data or 10K, whichever is greater.


 

3.1.6捕獲變化 
      

除了對基於持續時間間隔的流捕獲外,AVICap還支持如下的捕獲:

l         手控制幀捕獲

l         Still-image 捕獲

l         不使用磁盤存儲的捕獲

l         從一個MCI設備的流捕獲(real-time and step-frame)


 

手動幀捕獲


 

如果你向指定捕獲視頻流中個別幀,你可以通過WM_CAP_SINGLE_FRAME_OPEN消息、WM_CAP_SINGLE_FRAME消息、WM_CAP_SINGLE_FRMAE_CLOSE消息來控制幀序列(capCaptureSingleFrameOpen、/capCaptureSingleFrame、capCaptureSigleFrameClose)。


 

典型應用是,這些消息用於向捕獲文件添加單獨的幀來創建一個動畫, WM_CAP_SINGLE_FRAME_OPEN 爲手動捕獲操作打開一個文件,WM_CAP_SINGLE_FRAME用於捕獲一個單獨的幀放在文件中。

WM_CAP_SINGLE_FRMAE_CLOSE用於關閉這個捕獲文件。


 

注:  該操作支持音視頻同時捕獲。


Still-Image捕獲


 

如果要捕獲一個單獨的幀作爲一個靜態圖像,你可以使用WM_CAP_GRAB_FRAME_NOSTOP或者 WM_CAP_GRAB_FRAME 消息 ( capGrabFrameNoStop

或capGrabFrame 宏) 在一個幀緩存區中捕獲一個圖像。你可以通過使用下面的消息來抓獲當前顯示的圖形WM_CAP_GRAB_FRAME ,否則,使用WM_CAP_GRAB_FRAME_NOSTOP。

一旦開始捕獲,你可以拷貝圖像給其他應用程序。你可以從幀緩存區拷貝一個圖像到剪貼板(使用WM_CAP_EDIT_COPY 消息或capEditCopy宏)。你還可以使用如下的消息,將緩存區的一張圖像拷貝到一個DIB位圖中(WM_CAP_FILE_SAVEDIB消息或capFileSaveDIB宏)。


 

不使用磁盤存儲的捕獲

     

使用WM_CAP_SEUENCE_NOFILE消息(capCaptureSequenceNoFile宏),可以不向磁盤文件寫入數據。該消息僅在配合回調函數時有用,它允許你的應用程序直接使用音視頻數據。例如,在視頻會議中,應用程序使用該消息區獲得視頻流。回調函數將傳輸捕獲的圖像傳送給遠程的計算機。


 

從MCI設備進行流捕獲

MCI設備加強了實時捕獲和步進幀(step-frame)捕獲的處理操作。你可以指定一個MCI設備,比如一張影碟或者一盤錄像帶(VCR)來充當視頻源。通過發送消息並指定你要選定的MCI設備的名稱。消息:WM_CAP_SET_MCI_DEVICE (capSetMCIDeviceName宏)。獲得當前使用的設備可以使用WM_CAP_GET_MCI_DEVICE(capGetMCIDeviceName)消息。

在實時捕獲中, the capture window synchronizes the capture operation and compensates for delays associated with positioning the MCI video source and initializing the resources (such as capture buffers) required for capturing data. The capture window expects a valid MCI video device to be installed in the system for capturing data this way.

控制MCI設備的規格信息保存在CAPTRUEPARMS數據結構體的數據成員中。MCI兼容的視頻源包括錄像機(VCR)和光碟。如果fMCIControl數據成員爲TRUE,捕獲窗口採用MCI操作。捕獲窗口使用dwMCIStartTime和dwMCIStopTime來獲得開始和結束位置(毫秒)。 如果fMCIControl數據成員的值爲FALSE, dwMCIStartTime和dwMCIStopTime的值將被忽略不見。

你可以使用Media Player 去快速檢查MCI設備是否正確地連接到了你的系統上,如果在視頻顯示顯示了圖像,就表示這個視頻源正確連接到了捕獲硬件上。

在步進幀(step-frame)捕獲情況下, the capture window synchronizes the capture operation and compensates for the delays associated with positioning the MCI video source and initializing the resources required for capturing data. In addition, the capture window ensures that no frames are dropped; it steps through the video frames individually, ensuring that the frame is captured and stored before capturing the next frame in the video stream.

步進幀(step-frame)捕獲控制的規格信息保存在CAPTRUEPARMS數據結構體的數據成員中。步進幀(step-frame)捕獲除了使用視頻捕獲要用的數據成員外,還使用其他的數據成員:fStepMCIDevice, fStepCaptureAt2x, 和 wStepCaptureAverageFrames。如果數據成員fStepMCIDevice的值爲TRUE,捕獲窗口採用步進幀(step-frame)捕獲。捕獲窗口將使用這兩個參數來指定捕獲的開始和結束位置(dwMCIStartTime和dwMCIStopTime 毫秒)。捕獲窗口使用fStepCaptureAt2x 來決定捕獲硬件捕獲的視頻幀使用兩個普通的分辨率。使用 wStepCaptureAverageFrames 來指定捕獲時每幀圖像使用的時間大小。

       如果在一個步進幀(step-frame)捕獲中,指定fStepCaptureAt2x爲TRUE,那麼捕獲硬件將使用兩個指定的解析度來進行捕獲(高和寬的解析度都是雙倍的)。它使用軟件,在指定的解析度的基礎上改寫圖像的象素,讓其成爲更高解析度的圖像。如果硬件不支持基於硬件的批量處理,你也可以使用該選項。並且捕獲爲RGB格式。


 

注意:  如果你的硬件步支持基於硬件的批量處理(hardware-based decimation), it can capture samples at a higher rate than specified and use these additional samples to obtain color definitions that are more consistent with the original image. The additional samples are discarded after they are used, and the hardware passes samples to the capture driver at the specified rate。


 

如果指定了步進幀捕獲, wStepCaptureAverageFrames 成員用於指定捕獲一幀圖像要使用的時間,它是一個採樣的標準時間。以後捕獲圖像捕獲平均時間都會基於這個時間。採用這種機制,降會減少在一個圖像幀的隨機數字化噪音。這個數據成員的標準值是5。

關於MCI的信息可以查看MSDN上的信息。

  

3.1.7高級捕獲選項

 

這節描述在一個捕獲操作中,你還可以進行的其他選擇。

l         測量視頻質量

l         用戶初始化捕獲

l         和調色板一起工作

l         在AVI文件中的嵌入信息塊

l         用戶數據消息(Messages)


 

測量視頻質量

測量視頻質量的一個方法是去限定在一個捕獲操作期間丟掉的捕獲圖像幀的數字。當流捕獲完成後,質量 = 丟掉的幀 / 所有的幀。如果這個數(百分數)大於wPercentDropForError的值,AVICap將發一個錯誤信息給錯誤回調函數。WPercentDropForError是CAPTUREPARMS數據結構體的一個數據成員。

通過WM_CAP_GET_SEQUENCE_SETUP消息(capCaptureGetSetup宏)可以得到當前設定的丟掉幀的限定值。同樣對wPercentDropForError進行修改,再把修改後的數據結構體發送給捕獲窗體就可以完成對限定值的修改。WM_CAP_GET_SEQUENCE_SETUP消息(capCaptureSetSetup), wPercentDropForErrorm默認值10 (10%)。


 

用戶初始化捕獲

    通過WM_CAP_GET_SEQUENCE_SETUP消息(capCaptureGetSetup宏)可以得到當前用戶初始化捕獲的狀態值。該值存放在fMakeUserHitOKToCapture中。在開始一個捕獲會話前,設置該值爲TRUE,可以爲用戶提供精確的控制。系統爲所有的音視頻分配好數據緩存區後,AVICap會顯示一個對話框。它讓用戶清除因爲軟件初始化導致的捕獲延遲。如果你的應用程序爲視頻數據分配的數據緩存區很小,那麼這個對話框可能就沒的必要了。該值的默認值是FALSE。


 

和調色板一起工作

       最初,如果視頻捕獲格式需要一個調色板,那麼捕獲窗口將使用捕獲驅動提供的調色板來代替。這個調色板可能由灰度值,或者可選的彩色值組成。使用WM_CAP_PAL_PASTE或者WM_CAP_PAL_OPEN消息(capPalettePaste或capPaletteOpen)可以獲得一個現存的調色板去替換默認的調色板。你還可以創建一個自定義的調色板去替換默認的調色板,你要使用WM_CAP_PAL_AUTOCREATE 或者 WM_CAP_PAL_MANUALCREATE消息 ( capPaletteAuto 或 capPaletteManual )。當你替換了調色板後,捕獲窗體和驅動程序將使用替換後的調色板,直到你創建或打開其他的調色板爲止。


 

WM_CAP_PAL_AUTOCREATE 或者 WM_CAP_PAL_MANUALCREATE 消息將創建一個基於當前視頻輸入最優化的調色板。這個自定義的調色板將爲視頻提供一個最好的顏色逼真度,因爲這個調色板的顏色是基於這個視頻的。捕獲窗口創建一個採樣顏色的3維柱狀圖。它會減小真實顏色和漸近色間的值。

 

在發送WM_CAP_PAL_AUTOCREATE消息時, 你必須指定AVICap採樣的幀數以及調色板的顏色尺寸。在指定幀數時,要保證幀數足夠大以保證所有的視頻顏色可以被採樣收集到。

    使用WM_CAP_PAL_MANUALCREATE消息可以對當前幀進行採樣。通過該消息,進行幾次手動選擇幀採樣操作,你可以創建自己的調色板,它包含了你想要的顏色信息。


 

一個調色板可以包含256種顏色。如果你要合併調色板,或者在視頻隊列中同時在顯示其他視頻或圖像。你可以去使用一個小的顏色集合,這樣不同圖像或視頻的顏色就可以共存了。

使用WM_CAP_PAL_SAVE消息(capPaletteSave),可以保促一個新的調色板。通過WM_CAP_PAL_OPEN消息還可以得到當前的調色板。你可以在調色板處理前保存一個調色板,或者爲其他應用程序使用去保存一個調色板。


 

使用WM_CAP_PAL_PASTE可以把剪貼板中的調色板粘貼到捕獲窗口中。捕獲窗口通過這個調色板到捕獲驅動。其他程序可以拷貝調色板到剪貼板中。你也可以把調色板粘貼到剪貼板中。使用WM_CAP_ENDIT_COPY消息(capEditCopy)。它將拷貝視頻緩存區(包括調色板)到剪貼區。


在AVI文件中的嵌入信息塊

你可以在一個AVI文件中插入信息塊,比如文本或者自定義的數據。通過使用下面的消息:WM_CAP_FILE_SET_INFOCHUNK(capFileSetInfoChunk)。可以使用這個消息還可以清除掉一個AVI文件中的信息塊。


 

用戶數據消息

       通過使用WM_CAP_GET_USER_DATA和WM_CAP_SET_USER_DATA消息可以關聯數據到一個捕獲窗體。(capGetUserData 和 capSetUserData宏)。使用…Get…消息可以得到一個LONG數據值,可以通過_Set_消息去設置該值。


 


 

3.1.8 AVICap回調函數
       你的應用程序可以爲一個捕獲窗口註冊一些回調函數,它們可以告訴你的應用程序一些變化。比如捕獲狀態發生變化了,或者有錯誤發生了,音視頻緩存區可使用了。下面的消息設置回調函數。

消           息 
 說           明 
 
WM_CAP_SET_CALLBACK_CAPCONTROL

CapSetCallbackOnCapControl 宏 
 在應用程序中指定回調函數用於控制捕獲的開始和結束。 
 
WM_CAP_SET_CALLBACK_ERROR

CapSetCallbackOnError宏 
 在應用程序中指定回調函數,當出錯的時候就調用它。 
 
WM_CAP_SET_CALLBACK_FRAME

CapSetCallbackOnFrame宏 
 在應用程序中指定回調函數,當預覽圖像幀被捕獲了的時候就調用它。 
 
WM_CAP_SET_CALLBACK_STATUS

CapSetCallbackOnStatus宏 
 在應用程序中指定回調函數,當狀態(status)改變的時候就調用它。 
 
WM_CAP_SET_CALLBACK_VIDEOSTREAM

CapSetCallbackOnVideoStream宏 
 在應用程序中指定回調函數,在流捕獲期間,當一個新的視頻緩存區可用的時候就調用它。 
 
WM_CAP_SET_CALLBACK_WAVESTREAM

CapSetCallbackOnWaveStream宏 
 在應用程序中指定回調函數,在流捕獲期間,當一個新的音頻緩存區可用的時候就調用它。 
 
WM_CAP_SET_CALLBACK_YIELD

CapSetCallbackOnYield宏 
 在應用程序中指定回調函數,在流捕獲期間Yielding(產生?) 
 


 

精確捕獲控制

捕獲窗口可以提供捕獲回調函數,這個回調函數可以對流捕獲的開始和結束時刻進行精確的控制。在捕獲驅動程序(capture driver)完成所有緩存區分配和其他捕獲準備後,捕獲驅動程序就發送第一個消息給回調處理程序,把nState參數設置爲:

CONTROLCALLBACK_PREROLL

這個消息告訴應用程序將要開啓視頻源了。(這個回調函數指定nState爲它的第二個參數)回調函數將在開始時刻產生返回值。返回值爲TRUE那麼將繼續捕獲。爲FALSE就中斷捕獲。一旦捕獲開始,這個回調函數將頻繁的調用,把nState設置爲:

CONTROLCALLBACK_CAPTURING

將允許應用程序通過返回false去結束捕獲。


 

錯 誤

       捕獲窗口使用錯誤通知消息去告訴你的應用程序,發生了AVICap錯誤,比如磁盤空間已經用完了,嘗試對一個只讀文件進行寫操作,不能訪問硬件,掉幀太多。錯誤通知內容報價一個消息ID和一個格式化的文本字符(用來顯示)。你的應用程序可以通過使用這個消息ID去過濾錯誤通報,還可以讓該錯誤信息不顯示給用戶。消息ID爲0表示一個新操作正在開始並且這個回調函數會清除掉所有的顯示的錯誤信息。


 

幀(Frame)

       A capture window uses frame callback notification messages to notify your application when a new video frame is available. The capture window enables these callback notifications only if the preview rate is nonzero and streaming capture is not in progress.


 

狀態回調函數

當視頻捕獲向磁盤寫數據,或者在其他較長的操作期間,捕獲窗口可以發送消息給狀態回調函數通知你正在處理該操作的應用程序。狀態信息包括一個消息ID和和一個格式化的文本字符(用來顯示)。你的應用程序可以通過使用消息ID去過濾通報,還可以限制該信息是否顯示給用戶。在捕獲操作期間,發給回調函數的第一個消息總是ID_CAP_GEGIN,最後一個總是ID_CAP_END。消息ID爲0表示,一個新操作正在進行並且回調函數將清除當前狀態。


 

視頻流

       在流捕獲期間,應用程序可以使用視頻流回調函數去處理一個捕獲的視頻幀。視頻窗體只能在每次向磁盤寫數據幀前,調用視頻流回調函數。


 

音頻流

在流捕獲期間,應用程序可以使用音頻流回調函數去處理音頻緩存區。視頻窗體只能在每次向磁盤寫數據幀前,調用音頻流回調函數。


 

Yield 回調函數

應用程序在流捕獲期間可以使用Yield回調函數。(Yield回調函數一般是由一個消息循環組成,可以調用PeekMessage,TranslateMessage,DispatchMessage)。捕獲窗口在每次捕獲視頻幀時至少調用一次Yield回調函數。但是具體要調用多少次由幀率來決定。


 

關閉回調函數

你可以暫時或永久關閉所有的回調函數的功能,在發送消息設置回調函數的時候,用NULL替換調回調函數就可以了。


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/suntaoznz/archive/2005/08/06/447067.aspx

 

 

 

摘要 在VC++6.0中利用VFW技術實現視頻數據實時獲取的過程中,針對回調函數的處理中所碰到的問題、圖像採集中原始數據的獲取以及捕獲窗口的建立的問題進行了詳細的討論,並給出了具體的解決辦法。

  關鍵詞 VFW 圖像採集 回調函數

  引言

  以光學爲基礎,融光電子學、計算機技術、激光技術、圖像處理技術等現代科學技術爲一體的圖像測量技術在測量領域中形成了新的測量技術,基於數字圖像處理技術的圖像測量系統目前已廣泛應用於幾何量的測量、航空等遙感測量、精密複雜零件的微尺寸測量和外觀測量,以及光波干涉圖、應力應變場狀態分佈等和圖像有關的技術領域中。在基於數字圖像處理技術的圖像測量系統中,必須解決的問題就是圖像採集,即圖像數據的獲取,採集的圖像數據用於後期的圖像處理。 

  視頻圖像捕獲一般來講有兩種方法,一種是利用視頻捕獲卡所附帶的SDK開發工具,這種捕獲方法的實現是與設備有關的,依賴於視頻捕獲卡與攝像頭的類型,不利於靈活應用;另外一種捕獲方法是Microsoft的Visual C++自從4.0版就開始支持Video for Windows(簡稱VFW),這給視頻捕獲編程帶來了很大的方便,利用VFW技術的可以提高視頻捕獲的靈活性,減少了對視頻設備的依賴。在VC++6.0中,含有MCIAVI、DRAWDIB、AVIFILE和AVICAP等組件。通過它們之間的協調工作,可以完成播放、編輯、文件管理和視頻捕獲等功能,爲視頻圖像處理和分析帶來非常大的便利,本文就利用VFW進行視頻數據的實時採集中的碰到的幾個實際問題進行探討。

   VFW庫函數簡介

  視頻數據的實時採集主要是通過調用AVICap32.dll創建AVICap窗口類 ,由AVICap窗口類中的消息、宏函數、結構以及回調函數來完成。 AVICap在捕獲視頻方面具有明顯的優勢,它能直接訪問視頻緩衝區,不需要生成中間文件,實時性很高,它也可將數字視頻保存到事先建好的文件中。實際應用表明,通過這種方法,提高了視頻採集的效果和程序運行的效率,同時也減少了對硬件的依賴性,提高了程序的兼容性和移植性。

  VFW的視頻採集功能主要包括捕獲視頻流至AVI文件(capCaptureSequence)、捕獲視頻流至緩存(capCaptureSequenceNofile)、捕獲視頻流至AVI文件(capCaptureSingleFrame)、本地預覽(capPreview/capOverlay)和捕獲單幀預覽(capGrabFrame/capGrabFrameNoStop)等。VFW還提供了回調函數 ,允許應用程序精確控制視頻流的捕獲、檢測錯誤、監控狀態變化 ,以及在捕獲兩幀數據的空隙和每捕獲新幀時對實時數據進行處理。

  幾個實際問題的探討

  1、回調函數處理的問題 

  回調函數是至今爲止最有用的編程機制之一。在Windows中,回調函數更是窗口過程、鉤子過程、異步過程調用所必需的,在整個回調過程中自始至終地使用回調方法。人們可以註冊回調方法以獲得加載/卸載通知,未處理異常通知,數據庫/窗口狀態修改通知,文件系統修改通知,菜單項選擇,完成的異步操作通知,過濾一組條目等等。在VFW中有幾條這樣的宏函數,如用於設置在發生某事件後能作出反應的回調函數的宏函數,它和中斷服務機制很相似,條件一滿足,程序會自動進入相應的回調函數體中,該函數究竟要做些什麼,全由開發者藉助其參數自行編制程序來確定。利用VFW獲取實時視頻數據通常可以運用視頻處理的回調機制(call-backmechanism) 獲得實時數據緩衝區的首址和長度並對圖像數據進行處理,同時也可以進行視頻數據的直接傳輸,在這一方面很多文章都作了具體的介紹。但是按照大多數文章的介紹,在具體的應用過程中,對回調函數作如下定義時,程序總是無法通過編譯:

{ 
 LRESULT CALLBACK FrameCallbackProc(HWND ghWnd,LPVIDEOHDR lpVData)
 unsigned char *data;
 data=lpVData->lpData;//獲得視頻數據首地址,並將數據存入data數組中以便處理
}


  通過研究,發現根本原因是回調函數是基於C編程的Windows SDK的技術,不是針對C++的,可以將一個C函數直接作爲回調函數,但是如果試圖直接使用C++的成員函數作爲回調函數將發生錯誤,甚至編譯就不能通過。其錯誤是普通的C++成員函數都隱含了一個傳遞函數作爲參數,亦即“this”指針,C++通過傳遞一個指向自身的指針給其成員函數從而實現程序函數可以訪問C++的數據成員。這也可以理解爲什麼C++類的多個實例可以共享成員函數但是確有不同的數據成員。由於this指針的作用,使得將一個CALLBACK型的成員函數作爲回調函數安裝時就會因爲隱含的this指針使得函數參數個數不匹配,從而導致回調函數安裝失敗。要解決這一問題的關鍵就是不讓this指針起作用,通過採用以下兩種典型技術可以解決在C++中使用回調函數所遇到的問題。這種方法具有通用性,適合於任何C++。

  (1) 不使用成員函數,直接使用普通C函數,爲了實現在C函數中可以訪問類的成員變量,可以使用友元操作符(friend),在C++中將該C函數說明爲類的友元即可。這種處理機制與普通的C編程中使用回調函數一樣。 

  (2) 使用靜態成員函數,靜態成員函數不使用this指針作爲隱含參數,這樣就可以作爲回調函數了。靜態成員函數具有兩大特點:其一,可以在沒有類實例的情況下使用;其二,只能訪問靜態成員變量和靜態成員函數,不能訪問非靜態成員變量和非靜態成員函數。由於在C++中使用類成員函數作爲回調函數的目的就是爲了訪問所有的成員變量和成員函數,如果作不到這一點將不具有實際意義。解決的辦法也很簡單,就是使用一個靜態類指針作爲類成員,通過在類創建時初始化該靜態指針,如pThis=this,然後在回調函數中通過該靜態指針就可以訪問所有成員變量和成員函數了。這種處理辦法適用於只有一個類實例的情況,因爲多個類實例將共享靜態類成員和靜態成員函數,這就導致靜態指針指向最後創建的類實例。爲了避免這種情況,可以使用回調函數的一個參數來傳遞this指針,從而實現數據成員共享。這種方法稍稍麻煩,這裏就不再贅述。

  因此,可以對回調函數作如下定義:

static LRESULT CALLBACK FrameCallbackProc(HWND ghWnd,LPVIDEOHDR lpVData)
{
 unsigned char *data;
 data=lpVData->lpData;//獲得視頻數據首地址,並將數據存入data數組中以便處理
}

 

 

 

摘要 在VC++6.0中利用VFW技術實現視頻數據實時獲取的過程中,針對回調函數的處理中所碰到的問題、圖像採集中原始數據的獲取以及捕獲窗口的建立的問題進行了詳細的討論,並給出了具體的解決辦法。

  關鍵詞 VFW 圖像採集 回調函數

  引言

  以光學爲基礎,融光電子學、計算機技術、激光技術、圖像處理技術等現代科學技術爲一體的圖像測量技術在測量領域中形成了新的測量技術,基於數字圖像處理技術的圖像測量系統目前已廣泛應用於幾何量的測量、航空等遙感測量、精密複雜零件的微尺寸測量和外觀測量,以及光波干涉圖、應力應變場狀態分佈等和圖像有關的技術領域中。在基於數字圖像處理技術的圖像測量系統中,必須解決的問題就是圖像採集,即圖像數據的獲取,採集的圖像數據用於後期的圖像處理。 

  視頻圖像捕獲一般來講有兩種方法,一種是利用視頻捕獲卡所附帶的SDK開發工具,這種捕獲方法的實現是與設備有關的,依賴於視頻捕獲卡與攝像頭的類型,不利於靈活應用;另外一種捕獲方法是Microsoft的Visual C++自從4.0版就開始支持Video for Windows(簡稱VFW),這給視頻捕獲編程帶來了很大的方便,利用VFW技術的可以提高視頻捕獲的靈活性,減少了對視頻設備的依賴。在VC++6.0中,含有MCIAVI、DRAWDIB、AVIFILE和AVICAP等組件。通過它們之間的協調工作,可以完成播放、編輯、文件管理和視頻捕獲等功能,爲視頻圖像處理和分析帶來非常大的便利,本文就利用VFW進行視頻數據的實時採集中的碰到的幾個實際問題進行探討。

   VFW庫函數簡介

  視頻數據的實時採集主要是通過調用AVICap32.dll創建AVICap窗口類 ,由AVICap窗口類中的消息、宏函數、結構以及回調函數來完成。 AVICap在捕獲視頻方面具有明顯的優勢,它能直接訪問視頻緩衝區,不需要生成中間文件,實時性很高,它也可將數字視頻保存到事先建好的文件中。實際應用表明,通過這種方法,提高了視頻採集的效果和程序運行的效率,同時也減少了對硬件的依賴性,提高了程序的兼容性和移植性。

  VFW的視頻採集功能主要包括捕獲視頻流至AVI文件(capCaptureSequence)、捕獲視頻流至緩存(capCaptureSequenceNofile)、捕獲視頻流至AVI文件(capCaptureSingleFrame)、本地預覽(capPreview/capOverlay)和捕獲單幀預覽(capGrabFrame/capGrabFrameNoStop)等。VFW還提供了回調函數 ,允許應用程序精確控制視頻流的捕獲、檢測錯誤、監控狀態變化 ,以及在捕獲兩幀數據的空隙和每捕獲新幀時對實時數據進行處理。

  幾個實際問題的探討

  1、回調函數處理的問題 

  回調函數是至今爲止最有用的編程機制之一。在Windows中,回調函數更是窗口過程、鉤子過程、異步過程調用所必需的,在整個回調過程中自始至終地使用回調方法。人們可以註冊回調方法以獲得加載/卸載通知,未處理異常通知,數據庫/窗口狀態修改通知,文件系統修改通知,菜單項選擇,完成的異步操作通知,過濾一組條目等等。在VFW中有幾條這樣的宏函數,如用於設置在發生某事件後能作出反應的回調函數的宏函數,它和中斷服務機制很相似,條件一滿足,程序會自動進入相應的回調函數體中,該函數究竟要做些什麼,全由開發者藉助其參數自行編制程序來確定。利用VFW獲取實時視頻數據通常可以運用視頻處理的回調機制(call-backmechanism) 獲得實時數據緩衝區的首址和長度並對圖像數據進行處理,同時也可以進行視頻數據的直接傳輸,在這一方面很多文章都作了具體的介紹。但是按照大多數文章的介紹,在具體的應用過程中,對回調函數作如下定義時,程序總是無法通過編譯:

{ 
 LRESULT CALLBACK FrameCallbackProc(HWND ghWnd,LPVIDEOHDR lpVData)
 unsigned char *data;
 data=lpVData->lpData;//獲得視頻數據首地址,並將數據存入data數組中以便處理
}

  通過研究,發現根本原因是回調函數是基於C編程的Windows SDK的技術,不是針對C++的,可以將一個C函數直接作爲回調函數,但是如果試圖直接使用C++的成員函數作爲回調函數將發生錯誤,甚至編譯就不能通過。其錯誤是普通的C++成員函數都隱含了一個傳遞函數作爲參數,亦即“this”指針,C++通過傳遞一個指向自身的指針給其成員函數從而實現程序函數可以訪問C++的數據成員。這也可以理解爲什麼C++類的多個實例可以共享成員函數但是確有不同的數據成員。由於this指針的作用,使得將一個CALLBACK型的成員函數作爲回調函數安裝時就會因爲隱含的this指針使得函數參數個數不匹配,從而導致回調函數安裝失敗。要解決這一問題的關鍵就是不讓this指針起作用,通過採用以下兩種典型技術可以解決在C++中使用回調函數所遇到的問題。這種方法具有通用性,適合於任何C++。

  (1) 不使用成員函數,直接使用普通C函數,爲了實現在C函數中可以訪問類的成員變量,可以使用友元操作符(friend),在C++中將該C函數說明爲類的友元即可。這種處理機制與普通的C編程中使用回調函數一樣。 

  (2) 使用靜態成員函數,靜態成員函數不使用this指針作爲隱含參數,這樣就可以作爲回調函數了。靜態成員函數具有兩大特點:其一,可以在沒有類實例的情況下使用;其二,只能訪問靜態成員變量和靜態成員函數,不能訪問非靜態成員變量和非靜態成員函數。由於在C++中使用類成員函數作爲回調函數的目的就是爲了訪問所有的成員變量和成員函數,如果作不到這一點將不具有實際意義。解決的辦法也很簡單,就是使用一個靜態類指針作爲類成員,通過在類創建時初始化該靜態指針,如pThis=this,然後在回調函數中通過該靜態指針就可以訪問所有成員變量和成員函數了。這種處理辦法適用於只有一個類實例的情況,因爲多個類實例將共享靜態類成員和靜態成員函數,這就導致靜態指針指向最後創建的類實例。爲了避免這種情況,可以使用回調函數的一個參數來傳遞this指針,從而實現數據成員共享。這種方法稍稍麻煩,這裏就不再贅述。

  因此,可以對回調函數作如下定義:

static LRESULT CALLBACK FrameCallbackProc(HWND ghWnd,LPVIDEOHDR lpVData)
{
 unsigned char *data;
 data=lpVData->lpData;//獲得視頻數據首地址,並將數據存入data數組中以便處理
}

 

 

1 引用頭文件<vfw.h> ,導入 vfw32.lib 庫,庫文件可以在vc存在路徑中找到;
如:D:/Program Files/Microsoft Visual Studio/VC98/Lib/vfw32.lib

 

 


瀏覽視頻:
{
//create a window for captureWindow 
CWnd *mywnd=new CWnd;
mywnd->Create(_T("STATIC"), "", WS_CHILD | WS_VISIBLE,CRect(0, 0, 400, 400), this, 1234);
mywnd->ShowWindow(SW_SHOW);
CRect rect;
mywnd->GetWindowRect(rect);

//create capture window
ghCapWnd=capCreateCaptureWindow( "My Own Capture Window",WS_CHILD | WS_VISIBLE ,0, 0, (rect.right-rect.left), (rect.bottom-rect.top), mywnd->GetSafeHwnd(), 1235);
//connect device
capDriverConnect (ghCapWnd, 0);
//get params
CAPTUREPARMS CapParms;
capCaptureGetSetup(ghCapWnd,&CapParms,sizeof (CAPTUREPARMS))
//設置楨速
CapParms.dwRequestMicroSecPerFrame=40000; 
//有無時間限制 
CapParms.fLimitEnabled = FALSE; 
//是否捕捉音頻
CapParms.fCaptureAudio = FALSE; 
//MCI Device支持
CapParms.fMCIControl = FALSE;  
//設置窗口,如果爲false,捕捉畫面在桌面上              
CapParms.fYield = TRUE;
//停止捕捉鍵設置
CapParms.vKeyAbort = VK_ESCAPE;
CapParms.fAbortLeftMouse = FALSE;
CapParms.fAbortRightMouse = FALSE;
capCaptureSetSetup(ghCapWnd,&CapParms,sizeof (CAPTUREPARMS));
//設置預覽時的比例
capPreviewScale(ghCapWnd, 1);
//設置預覽時的幀頻率
capPreviewRate(ghCapWnd,66);
//是否支持比例變化
capPreviewScale(ghCapWnd,FALSE);
//打開預覽
capPreview(ghCapWnd, 1);
}

爲IDC_CAPTURE添加代碼開始捕獲視頻:
{
capCaptureSequence(ghCapWnd);
}
爲IDC_STOPCAPTURE添加代碼停止捕捉:
{
capCaptureAbort(ghCapWnd);
}
爲IDC_STOPVIDEO添加代碼斷開連接:
{
capDriverDisconnect(ghCapWnd);
}

 

VC-攝像頭控制SDK源碼

 

下面這段原碼,在vc下編程通過.可以作爲像我一樣的入門漢,體驗一下自己編程實現錄像的功能.不過,這段程序沒有對錄像進行壓縮,會很佔空間.所以只限學習.

#include <windows.h>
#include <stdio.h>
#include <vfw.h>

#pragma comment(lib,"vfw32.lib")

HWND ghWndCap ; //捕獲窗的句柄
CAPSTATUS gCapStatus ; //捕獲窗的狀態
CAPDRIVERCAPS gCapDriverCaps ; //視頻驅動器的能力 
char gachBuffer[20];
char szCaptureFile[] = "MYCAP.AVI";


LRESULT CALLBACK WinSunProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

///////////////////////////////////////////////////////////////////////
// StatusCallbackProc: 狀態回調函數,使用capSetCallbackOnStatus宏來註冊這個回調函數。
// hWnd:            捕獲窗體句柄 
// nID:              當前狀態的狀態碼 
// lpStatusText:       當前狀態的文本字符 
///////////////////////////////////////////////////////////////////////
LRESULT CALLBACK StatusCallbackProc(HWND hWnd,int nID,LPSTR lpStatusText)
{
if(!ghWndCap)return FALSE;//獲得捕獲窗的狀態
capGetStatus(ghWndCap,&gCapStatus,sizeof(CAPSTATUS));//更新捕獲窗的大小,得到消息WM_CAP_GET_STATUS
SetWindowPos(ghWndCap,NULL,0,0,gCapStatus.uiImageWidth,gCapStatus.uiImageHeight,SWP_NOZORDER|SWP_NOMOVE);
if(nID==0){//清除舊的狀態信息
SetWindowText(ghWndCap,(LPSTR)"hello");
return (LRESULT)TRUE;
}//顯示狀態ID和狀態文本
wsprintf(gachBuffer,"Status# %d: %s",nID,lpStatusText);
SetWindowText(ghWndCap,(LPSTR)gachBuffer);
return (LRESULT)TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// ErrorCallbackProc:    錯誤回調函數,過capSetCallbackOnError宏來註冊回調 
// hWnd:              捕獲窗口句柄 
// nErrID:              錯誤代碼 
// lpErrorText:          關於錯誤的文本信息 
/////////////////////////////////////////////////////////////////////////////// 
LRESULT CALLBACK ErrorCallbackProc(HWND hWnd,int nErrID,LPSTR lpErrorText)
{
if(!ghWndCap)return FALSE;
    if(nErrID==0)return TRUE;//清除舊的錯誤
wsprintf(gachBuffer,"Error# %d",nErrID);//顯示錯誤標識和文本
MessageBox(hWnd, lpErrorText, gachBuffer,MB_OK | MB_ICONEXCLAMATION); 
return (LRESULT) TRUE;
}

////////////////////////////////////////////////////////////////////////////// 
// FrameCallbackProc:   幀回調函數,通過capSetCallbackFrame宏來註冊回調函數 
// hWnd:              捕獲窗體句柄 
// lpVHdr:             指向一個包含幀信息的數據結構體
///////////////////////////////////////////////////////////////////////////////// 
LRESULT CALLBACK FrameCallbackProc(HWND hWnd,LPVIDEOHDR lpVHdr)
{
FILE *fp;
fp=fopen("caram.dat","w");
if(!ghWndCap)return FALSE;//假設fp爲一打開的.dat文件指針
fwrite(lpVHdr->lpData,1,lpVHdr->dwBufferLength,fp);
return (LRESULT)TRUE;
}


int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,          // command line
  int nCmdShow              // show state
)
{
 static TCHAR szAppName[]=TEXT("HelloWin");
 WNDCLASS wndcls;
 wndcls.cbClsExtra=0;
 wndcls.cbWndExtra=0;
 wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
 wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);
 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
 wndcls.hInstance=hInstance;
 wndcls.lpfnWndProc=WinSunProc;
 wndcls.lpszClassName="Weixin2003";
 wndcls.lpszMenuName=NULL;
 wndcls.style=CS_HREDRAW | CS_VREDRAW;
 //RegisterClass(&wndcls);
 if(!RegisterClass(&wndcls))
 {
  MessageBox(NULL,TEXT("This program requires WindowsNT!"),szAppName,MB_ICONERROR);
  return 0;
 }

 HWND hwnd;
 hwnd=CreateWindow("MYCAP","錄像程序",WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);

 ShowWindow(hwnd,nCmdShow);
 UpdateWindow(hwnd);

 MSG msg;
 while(GetMessage(&msg,NULL,0,0))
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 return 0;
}

LRESULT CALLBACK WinSunProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
 HDC hdc;
 PAINTSTRUCT ps;
 RECT rect;
 switch(uMsg)
 {
 case WM_CREATE:
  ghWndCap=capCreateCaptureWindow((LPSTR)"Capture  Window",WS_CHILD|WS_VISIBLE,0,0,300,240,(HWND)hwnd,(int)0); 
  capSetCallbackOnError(ghWndCap,(FARPROC)ErrorCallbackProc); 
  capSetCallbackOnStatus(ghWndCap,(FARPROC)StatusCallbackProc);
  capSetCallbackOnFrame(ghWndCap,(FARPROC)FrameCallbackProc);
  capDriverConnect(ghWndCap,0); // 將捕獲窗同驅動器連接  
  //獲得驅動器的能力,相關的信息放在結構變量gCapDriverCaps中
  capDriverGetCaps(ghWndCap,&gCapDriverCaps,sizeof(CAPDRIVERCAPS));
  capPreviewRate(ghWndCap, 66); // 設置Preview模式的顯示速率 
  capPreview(ghWndCap, TRUE); //啓動Preview模式
  if(gCapDriverCaps.fHasOverlay) //檢查驅動器是否有疊加能力 
  capOverlay(ghWndCap,TRUE); //啓動Overlay模式
  if(gCapDriverCaps.fHasDlgVideoSource)capDlgVideoSource(ghWndCap); //Video source 對話框 
  if(gCapDriverCaps.fHasDlgVideoFormat)capDlgVideoFormat(ghWndCap); // Video format 對話框 
  if(gCapDriverCaps.fHasDlgVideoDisplay)capDlgVideoDisplay(ghWndCap); // Video display 對話框
  capFileSetCaptureFile( ghWndCap, szCaptureFile); //指定捕獲文件名 
  capFileAlloc(ghWndCap, (1024L * 1024L * 5)); //爲捕獲文件分配存儲空間 
  capCaptureSequence(ghWndCap); //開始捕獲視頻序列
  capGrabFrame(ghWndCap); //捕獲單幀圖像
  break;
 case WM_PAINT:
  hdc=BeginPaint(hwnd,&ps);
  GetClientRect(hwnd,&rect);
  DrawText(hdc,TEXT("Hello,Windows98!"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
  EndPaint(hwnd,&ps);
  break;
 case WM_CLOSE:
  if(IDYES==MessageBox(hwnd,"是否真的結束?","weixin",MB_YESNO))
  {
   DestroyWindow(hwnd);
  }
  break;
 case WM_DESTROY:
  capSetCallbackOnStatus(ghWndCap,NULL);
  capSetCallbackOnError(ghWndCap,NULL); 
  capSetCallbackOnFrame(ghWndCap,NULL);
  capCaptureAbort(ghWndCap);//停止捕獲 
  capDriverDisconnect(ghWndCap); //將捕獲窗同驅動器斷開 
  PostQuitMessage(0);
  break;
 default:
  return DefWindowProc(hwnd,uMsg,wParam,lParam);
 }
 return 0;
}

 後面是孫濤先生的文章有對VFW在windows下編程控制攝像頭的詳細介紹

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/wang_cww/archive/2008/02/26/2122300.aspx


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章