【轉】談談使用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