1. 程式人生 > >【轉】談談使用VFW在windows下程式設計控制攝像頭(一)。 【孫濤】

【轉】談談使用VFW在windows下程式設計控制攝像頭(一)。 【孫濤】

原文:http://blog.csdn.net/suntaoznz/default.aspx?PageNumber=2

3.2使用視訊捕獲

3.2.1建立捕獲窗體

下面的例子通過使用capCreateCaptureWindow函式來建立一個捕獲窗體

hWndC = capCreateCaptureWindow (

    (LPSTR) "My Capture Window",       // 如果是Pop-up視窗的視窗名稱 

    WS_CHILD | WS_VISIBLE,          // 視窗型別 

    0, 0, 160, 120,                      // 視窗位置和尺寸

    (HWND) hwndParent, 

    (int) nID /* child ID */); 

3.2.2連線到一個捕獲驅動器

下面舉例,如何通過捕獲視窗的控制代碼hWndC連線到MS VIDEO驅動程式上,同時還演示瞭如何斷開連線。使用capDriverDisconnect:

fOK = SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0, 0L); 

// 或者使用巨集連線: 

// fOK = capDriverConnect(hWndC, 0); 

// 關閉連線

capDriverDisconnect (hWndC); 

3.2.3列舉安裝的捕獲驅動程式

使用capGetDriverDescription 函式來獲得系統已經安裝的所有捕獲驅動程式的名稱和版本。

char szDeviceName[80];

char szDeviceVersion[80];

for (wIndex = 0; wIndex < 10; wIndex++) 

{

    if (capGetDriverDescription (wIndex, szDeviceName, 

        sizeof (szDeviceName), szDeviceVersion, 

        sizeof (szDeviceVersion)) 

    {

        // 加入名字到一個已經安裝的裝置列表中

        // 讓使用者選擇一個使用。

    }

3.2.4獲得捕獲驅動器的效能引數

       WM_CAP_DRIVER_GET_CAPS訊息可以返回捕獲驅動程式以及其硬體的效能引數。這些資訊存放在一個CAPDRIVERCAPS的資料結構中。當你的應用程式的捕獲視窗連線到一個新的捕獲驅動器後,都會重新整理這個CAPDRIVERCAPS資料結構。下面將使用capDriverGetCaps巨集來獲得捕獲裝置的效能引數。

CAPDRIVERCAPS CapDrvCaps; 

SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS, 

    sizeof (CAPDRIVERCAPS), (LONG) (LPVOID) &CapDrvCaps); 

// 或者,使用巨集來獲得驅動器的新能引數 

// capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS)); 

3.2.5獲得捕獲視窗狀態(Status)

下面例子使用SetWindowPos函式區設定捕獲視窗的尺寸,這個尺寸的大小是基於輸入的視訊流大小的。輸入視訊流的尺寸大小由capGetStatus巨集來獲得,獲得資訊放在一個CAPSTATUS的資料結構體中。

CAPSTATUS CapStatus;

capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS)); 

SetWindowPos(hWndC, NULL, 0, 0, CapStatus.uiImageWidth, 

             CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE); 

3.2.6顯示對話方塊區設定視訊屬性

       每個捕獲驅動器都可以提高3個以上的不同對話方塊來控制數字視訊的特性和捕獲處理。下面的例子示範如何顯示這些對話方塊。在顯示每個對話方塊前,該例會呼叫capDriverGetCaps巨集並且檢查返回的CAPDRIVERCAPS物件來檢視是否可以能夠顯示特定的對話方塊。

CAPDRIVERCAPS CapDrvCaps; 

capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS));  

// 視訊源對話方塊 

if (CapDriverCaps.fHasDlgVideoSource)

    capDlgVideoSource(hWndC);  

// 視訊格式對話方塊 

if (CapDriverCaps.fHasDlgVideoFormat) 

{

    capDlgVideoFormat(hWndC); 

    // 是否由新的影象尺寸?Are there new image dimensions?

    capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));

    // 如果有,傳送通知給父視窗,告訴它尺寸改變了

}  

// 視訊顯示對話方塊 

if (CapDriverCaps.fHasDlgVideoDisplay)

    capDlgVideoDisplay(hWndC); 

3.2.7獲得和設定視訊格式

BITMAPINFO資料結構體可以實現長度可調節地去適應標準壓縮的資料格式。因為它的長度可以變,所以在每次獲得當前視訊格式前,都必須去查詢這個結構的長度以及分配的記憶體大小。該例子使用了capGetVideoFormatSize巨集去獲得快取區大小,使用capGetVideoFormat巨集區獲得當前視訊格式。 

LPBITMAPINFO lpbi;

DWORD dwSize;

dwSize = capGetVideoFormatSize(hWndC);

lpbi = GlobalAllocPtr (GHND, dwSize);

capGetVideoFormat(hWndC, lpbi, dwSize); 

// 訪問視訊格式,並且釋放分配的記憶體。

應用程式使用capSetVideoFormat巨集(WM_CAP_SET_VIDEOFORMAT),把一個BITMAPINFO結構傳送給捕獲視窗,顯示修改。因為視訊格式由裝置指定的,你的應用程式可以去檢查獲得的返回值,來知道這個視訊格式是不是公開的。

3.2.8預覽視訊

       下面使用capPreviewRate巨集來設定預覽模式的幀頻率為66毫秒/幀,使用capPreview巨集在捕獲視窗預覽影象。

capPreviewRate(hWndC, 66);      // 速度,微秒

capPreview(hWndC, TRUE);       // 開始預覽 

capPreview(hWnd, FALSE);        // 遮蔽預覽 

3.2.9允許視訊覆蓋(Overlay)

下面使用capDriverGetCaps巨集去檢測這個捕獲驅動是否支援覆蓋(Overlay)模式,如果支援,就允許視訊覆蓋模式;

CAPDRIVERCAPS CapDrvCaps; 

capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS)); 

if (CapDrvCaps.fHasOverlay) 

    capOverlay(hWndC, TRUE);

3.2.10捕獲檔案命名

    下例使用capFileSetCaptureFile巨集來指定一個要命名的檔名(mycap.avi),使用capFileAlloc巨集去預分配5MB的檔案。

char szCaptureFile[] = "MYCAP.AVI";

capFileSetCaptureFile( hWndC, szCaptureFile); 

capFileAlloc( hWndC, (1024L * 1024L * 5)); 

3.2.11格式化音訊捕獲

下例使用capSetAudioFormat來設定音訊格式為11-KHz PCM 8-bit,立體聲。

WAVEFORMATEX wfex;

wfex.wFormatTag = WAVE_FORMAT_PCM;

wfex.nChannels = 2;                     // 使用立體聲

wfex.nSamplesPerSec = 11025;

wfex.nAvgBytesPerSec = 22050;

wfex.nBlockAlign = 2;

wfex.wBitsPerSample = 8;

wfex.cbSize = 0;

capSetAudioFormat(hWndC, &wfex, sizeof(WAVEFORMATEX)); 

3.2.12改變視訊捕獲設定

       下例使用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)); 

3.2.13捕獲資料

       下例使用capCaptureSequence巨集開始視訊捕獲,使用capFileSaveAs巨集從捕獲檔案拷貝資料到其他檔案NEWFILE.AVI中。

char szNewName[] = "NEWFILE.AVI";

// Set up the capture operation.

capCaptureSequence(hWndC); 

// Capture.

capFileSaveAs(hWndC, szNewName); 

3.2.14加入資訊塊

如果你想新增其他資訊(除了音視訊),你可以建一個資訊塊並把它們插入到一個捕獲檔案中去。資訊塊可以包含這個方面的內容。比如版權資訊,視訊源的ID,外部顯示的時間資訊。下面的例子儲存外部時間資訊SMPTE()到一個資訊塊中,並加入使用capFileSetInfoChunk巨集加入到捕獲檔案中。

//  This example assumes the application controls 

//  the video source for preroll and postroll. 

CAPINFOCHUNK cic;

// . 

// . 

// . 

cic.fccInfoID = infotypeSMPTE_TIME;

cic.lpData = "00:20:30:12"; 

cic.cbData = strlen (cic.lpData) + 1;

capFileSetInfoChunk (hwndC, &cic); 

3.2.15在程式中加入回撥函式

應用程式可以註冊捕獲視窗的回撥函式,這樣就可以把下面的情況通知給應用程式:

l         狀態變化了 

l         錯誤發生了 

l         視訊和音訊的緩衝區的資料可以使用了 

l         在捕獲期間,應用程式將yield 

下面的例子將建立一個捕獲視窗並在應用的訊息迴圈中,注狀態、錯誤、視訊流、幀的回撥函式。

case WM_CREATE: 

    char    achDeviceName[80] ; 

    char    achDeviceVersion[100] ; 

    char    achBuffer[100] ; 

    WORD    wDriverCount = 0 ; 

    WORD    wIndex ; 

    WORD    wError ; 

    HMENU   hMenu ; 

    // 使用capCreateCaptureWindow巨集建立一個捕獲窗體.

    ghWndCap = capCreateCaptureWindow((LPSTR)"Capture Window", 

        WS_CHILD | WS_VISIBLE, 0, 0, 160, 120, (HWND) hWnd, (int) 0); 

    // 使用capSetCallbackOnError巨集註冊錯誤回撥函式 

     capSetCallbackOnError(ghWndCap, fpErrorCallback); 

    // 使用capSetCallbackOnStatus巨集註冊狀態回撥函式 

    capSetCallbackOnStatus(ghWndCap, fpStatusCallback); 

    //使用capSetCallbackOnVideoStream巨集註冊視訊流回調函式

    capSetCallbackOnVideoStream(ghWndCap, fpVideoCallback); 

    //使用capSetCallbackOnFrame巨集註冊幀回撥函式

    capSetCallbackOnFrame(ghWndCap, fpFrameCallback); 

    // 連線到一個捕獲驅動器上 

    break; 

case WM_CLOSE: 

//使用capSetCallbackOnFrame巨集關閉幀回撥函式 

// 類似可呼叫其他存在的回撥函式。

    capSetCallbackOnFrame(hWndC, NULL); 

  break; 

3.2.16建立一個狀態回撥函式

下面的例子是一個簡單的狀態回撥函式,使用capSetCallbackOnStatus巨集來註冊這個回撥函式。

// StatusCallbackProc: 狀態回撥函式 

// hWnd:            捕獲窗體控制代碼 

// nID:              當前狀態的狀態碼 

// lpStatusText:       當前狀態的文字字元 

// 

LRESULT PASCAL StatusCallbackProc(HWND hWnd, int nID, 

    LPSTR lpStatusText) 

    if (!ghWndMain) 

        return FALSE; 

    if (nID == 0) {           // 清除舊的狀態資訊 

        SetWindowText(ghWndMain, (LPSTR) gachAppName); 

        return (LRESULT) TRUE; 

    } 

    // 顯示狀態ID和狀態文字.. 

    wsprintf(gachBuffer, "Status# %d: %s", nID, lpStatusText); 

    SetWindowText(ghWndMain, (LPSTR)gachBuffer); 

    return (LRESULT) TRUE; 

3.2.17建立一個錯誤的回撥函式

下面例子是一個簡單的錯誤回撥函式。通過capSetCallbackOnError巨集來註冊回撥。

// ErrorCallbackProc:    錯誤回撥函式 

// hWnd:              捕獲視窗控制代碼 

// nErrID:              錯誤程式碼 

// lpErrorText:          關於錯誤的文字資訊 

// 

LRESULT PASCAL ErrorCallbackProc(HWND hWnd, int nErrID,

    LPSTR lpErrorText) 

    if (!ghWndMain) 

        return FALSE; 

    if (nErrID == 0)            // Starting a new major function. 

        return TRUE;          // 清除舊的錯誤 

    // 顯示錯誤ID和錯誤文字資訊 

    wsprintf(gachBuffer, "Error# %d", nErrID); 

    MessageBox(hWnd, lpErrorText, gachBuffer, 

               MB_OK | MB_ICONEXCLAMATION); 

    return (LRESULT) TRUE; 

3.2.18建立一個幀回撥函式

下面是一個簡單的幀回撥函式。通過capSetCallbackFrame巨集來註冊回撥函式。 

// FrameCallbackProc:   幀回撥函式 

// hWnd:              捕獲窗體控制代碼 

// lpVHdr:             指向一個包含幀資訊的資料結構體 

// 

LRESULT PASCAL FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) 

    if (!ghWndMain) 

        return FALSE; 

    wsprintf(gachBuffer, "Preview frame# %ld ", gdwFrameNum++); 

    SetWindowText(ghWndMain, (LPSTR)gachBuffer); 

    return (LRESULT) TRUE ; 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/suntaoznz/archive/2005/08/08/448303.aspx