1. 程式人生 > >基於vfw的攝像頭視訊瀏覽和捕獲的程式

基於vfw的攝像頭視訊瀏覽和捕獲的程式

使用基於VFW的方式進行攝像頭視訊瀏覽和捕獲,優點是編碼簡單,缺點是功能受限

方法: 新建一個基於對話方塊的工程,引用標頭檔案<vfw.h> , 匯入 vfw32.lib 庫,庫檔案可以在vc 存在路徑中找到; 如:D:/Program Files/Microsoft Visual Studio/VC98/Lib/vfw32.lib

在窗體上新增四個個按鈕,修改IDIDC_VIDEO , IDC_CAPTURE , IDC_STOPVIDEO , IDC_STOPCAPTURE;

為按鈕IDC_VIDEO 新增程式碼開始瀏覽視訊 :

{
// 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);
}

補充:

一、捕獲的幀頻率

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

下例使用capCaptureGetSetup和capCaptureSetSetup巨集來改變捕獲速度,從預設值(15幀/秒)到10幀/秒。

CAPTUREPARMS CaptureParms;
float  FramesPerSec  = 10.0 ;
capCaptureGetSetup(hWndC, 
& CaptureParms,  sizeof (CAPTUREPARMS));
CaptureParms.dwRequestMicroSecPerFrame 
=  (DWORD) ( 1.0e6 /  FramesPerSec);
capCaptureSetSetup(hWndC, 
& CaptureParms,  sizeof  (CAPTUREPARMS)); 

二、捕獲窗體狀態

通過傳送WM_CAP_GET_STATUS訊息(capGetStatus巨集),可以獲得當前捕獲視窗的狀態。這個訊息得到一個CAPSTATUS結構體的拷貝,狀態資訊就在這個結構體的成員中。CAPSTATUS 結構體包含了圖形尺寸大小、滾動位置(scroll position)、是否覆蓋(overlay)或者預覽(preview)等資訊。因為在CAPSTATUS 中的資訊是動態的,你的應用程式應該隨時去重新整理這個結構體中的內容。 改變捕獲視窗的尺寸對實際的視訊流的尺寸沒有影響。視訊捕獲可以做這幾個方面的工作:訪問 視訊源、顯示選項、格式和壓縮選項。音訊捕獲包括指定音訊格式和選擇壓縮方式。

CAPSTATUS CapStatus;
capGetStatus(hWndC, 
& CapStatus,  sizeof  (CAPSTATUS)); 
SetWindowPos(hWndC, NULL, 
0 0 , CapStatus.uiImageWidth, 
             CapStatus.uiImageHeight, SWP_NOZORDER 
|  SWP_NOMOVE); 

三、捕獲驅動效能

通過傳送WM_CAP_DRIVER_GET_CAPS訊息(capDriverGetCaps巨集),可以獲得當前連線的捕獲裝置的效能。傳送該訊息後,會返回一個CAPDRIVERCAPS 結構的物件。裝置的效能資訊,就在這個物件中。

CAPDRIVERCAPS CapDrvCaps; 
SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS, 
    
sizeof  (CAPDRIVERCAPS), (LONG) (LPVOID)  & CapDrvCaps); 
//  或者,使用巨集來獲得驅動器的新能引數 
//  capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS)); 

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

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

預覽模式從捕獲裝置硬體傳輸資料幀到系統的記憶體中,並且在捕獲視窗中使用GDI函式來顯示這些資料幀。當捕獲視窗的父窗體失去焦點的時候,在應用程式的視訊預覽的資料將變慢,如果父窗體獲的焦點後,將對預覽顯示進行加速。因為預覽處理的這種處理方式將大大提高整個系統的效率。

這裡用3個訊息用於控制預覽操作。

l     WM_CAP_SET_PREVIEW訊息(capPreview 巨集)可以開啟或者關閉預覽模式。

l     WM_CAP_SET_PREVIEWRATE 訊息(capPreviewRate 巨集)可以設定預覽模式下影象的幀速度。

l     WM_CAP_SET_SCALE 訊息 (capPreviewScale 巨集) 開啟或者關閉預覽視訊的縮放比例。

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

capPreviewRate(hWndC,  66 );       //  速度,微秒
capPreview(hWndC, TRUE);        //  開始預覽 
capPreview(hWnd, FALSE);         //  遮蔽預覽 

覆蓋模式,將不佔用CPU的處理資源,直接在顯示器上顯示視訊內容。所用的處理是有捕獲裝置硬體來完成。傳送WM_CAP_SET_OVERLAY訊息(或capOverlay 巨集)給捕獲視窗,可以開啟覆蓋模式。開啟覆蓋模式後,將自動關閉預覽格式。

CAPDRIVERCAPS CapDrvCaps; 
capDriverGetCaps(hWndC, 
& CapDrvCaps,  sizeof  (CAPDRIVERCAPS)); 
if  (CapDrvCaps.fHasOverlay) 
    capOverlay(hWndC, TRUE);

無論是預覽模式還是覆蓋模式,都可以通過傳送WM_CAP_SETSCROLL訊息(capSetScroollPos 巨集),可以設定影象的在整個視訊幀的滾動位置(scroll position)。

五、捕獲變化

除了對基於持續時間間隔的流捕獲外,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 、/capCaptureSingleFramecapCaptureSigleFrameClose )。

 典型應用是,這些訊息用於向捕獲檔案新增單獨的幀來建立一個動畫, 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 訊息 (

或 巨集) 在一個幀快取區中捕獲一個影象。你可以通過使用下面的訊息來抓獲當前顯示的圖形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 巨集),可以不向磁碟檔案寫入資料。該訊息僅在配合回撥函式時有用,它允許你的應用程式直接使用音視訊資料。例如,在視訊會議中,應用程式使用該訊息區獲得視訊流。回撥函式將傳輸捕獲的影象傳送給遠端的計算機。

capCaptureSequenceNoFile(m_hWndCapture);  //  預設開始視訊

獲取記憶體中影象位置指標的方法:

LRESULT CALLBACK FrameCallbackProc(HWND ghWnd,LPVIDEOHDR lpVData)

     unsigned 
char *  data;
    data
= lpVData -> lpData; // 獲得視訊資料首址並將資料存入data陣列中以便處理 return  (LRESULT) TRUE;
}

// 在捉圖的時候呼叫
capSetCallbackOnVideoStream(hCapWnd,capVideoStreamCallback);
capCaptureSequenceNoFile(hwndCap); 
// 呼叫完成後關閉
capSetCallbackOnVideoStream(hwndCap,NULL); 

從MCI 裝置進行流捕獲

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

控制MCI裝置的規格資訊儲存在CAPTRUEPARMS 資料結構體的資料成員中。MCI相容的視訊源包括錄影機(VCR)和光碟。如果fMCIControl 資料成員為TRUE,捕獲視窗採用MCI操作。捕獲視窗使用dwMCIStartTimedwMCIStopTime 來獲得開始和結束位置(毫秒)。 如果fMCIControl 資料成員的值為FALSE, dwMCIStartTimedwMCIStopTime 的值將被忽略不見。

你可以使用Media Player 去快速檢查MCI裝置是否正確地連線到了你的系統上,如果在視訊顯示顯示了影象,就表示這個視訊源正確連線到了捕獲硬體上。

步進幀(step-frame)捕獲控制的規格資訊儲存在CAPTRUEPARMS 資料結構體的資料成員中。步進幀(step-frame)捕獲除了使用視訊捕獲要用的資料成員外,還使用其他的資料成員:fStepMCIDevice , fStepCaptureAt2x , 和 wStepCaptureAverageFrames 。如果資料成員fStepMCIDevice 的值為TRUE,捕獲視窗採用步進幀(step-frame)捕獲。捕獲視窗將使用這兩個引數來指定捕獲的開始和結束位置(dwMCIStartTimedwMCIStopTime 毫秒)。捕獲視窗使用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上的資訊。

六、高階捕獲選項

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

l     測量視訊質量

l     使用者初始化捕獲

l     和調色盤一起工作

l     在AVI檔案中的嵌入資訊塊

l     使用者資料訊息(Messages)

測量視訊質量

測量視訊質量的一個方法是去限定在一個捕獲操作期間丟掉的捕獲影象幀的數字。當流捕獲完成後,質量 = 丟掉的幀 / 所有的幀。如果這個數(百分數)大於wPercentDropForError 的值,AVICap將發一個錯誤資訊給錯誤回撥函式。WPercentDropForErrorCAPTUREPARMS 資料結構體的一個數據成員。

通過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訊息(capPalettePastecapPaletteOpen )可以獲得一個現存的調色盤去替換預設的調色盤。你還可以建立一個自定義的調色盤去替換預設的調色盤,你要使用WM_CAP_PAL_AUTOCREATE 或者 WM_CAP_PAL_MANUALCREATE訊息 ( capPaletteAutocapPaletteManual )。當你替換了調色盤後,捕獲窗體和驅動程式將使用替換後的調色盤,直到你建立或開啟其他的調色盤為止。

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訊息可以關聯資料到一個捕獲窗體。(capGetUserDatacapSetUserData 巨集)。使用…Get…訊息可以得到一個LONG資料值,可以通過_Set_訊息去設定該值。

七、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(產生?)

轉自blog.csdn.net/suntaoznz