VFW简介——转载
原文地址:http://blog.ednchina.com/opencv2008/193859/message.aspx
VFW(Video For Windows)是微軟公司1992年推出的關于數字視頻的一個軟件包,它能使應用程序通過數字化設備從傳統的模擬視頻源得到數字化的視頻剪 輯。VFW的一個關鍵思想是播放時不需要專用硬件,為了解決數字視頻數據量大的問題,需要對數據進行壓縮。它引進了一種叫AVI的文件標準,該標準未規定 如何對視頻進行捕獲、壓縮及播放,僅規定視頻和音頻該如何存儲在硬盤上,以及在AVI文件中交替存儲視頻幀和與之相匹配的音頻數據。VFW給程序員提 供.VBX和AVICap窗口類的高級編程工具,使程序員能通過發送消息或設置屬性來捕獲、播放和編輯視頻剪輯。在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的輸出信號與其自身的輸出信號合并,形
成組合信號顯示在計算機的監視器上。只有部分視頻捕獲卡才具有視頻疊加能力。
Visual C++ 在支持VFW方面提供有vfw32.lib、 msacm32.lib 、winmm.lib等類似的庫。特別是它提供了功能強大、簡單易行、類似于 MCIWnd的窗口類AVICap。AVICap為應用程序提供了一個簡單的、基于消息的接口,使之能訪問視頻和波形音頻硬件,并能在將視頻流捕獲到硬盤 上的過程中進行控制。
開發步驟
●CapCreateCaptureWindow : 在進行視頻捕獲之前必需要先創建一個“捕獲窗”,并以它為基礎進行所有的捕獲及設置操作。
?? 捕獲窗類似于標準控件(如按鈕、列表框等),并具有下列功能:
??將視頻流和音頻流捕獲到一個AVI文件中;??
??動態地同視頻和音頻輸入器件連接或斷開;??
??以Overlay或Preview模式對輸入的視頻流進行實時顯示;??
??在捕獲時,可指定所用的文件名并能將捕獲文件的內容拷貝到另一個文件;??
??設置捕獲速率;??
??顯示控制視頻源、視頻格式、視頻壓縮的對話框;??
??創建、保存或載入調色板;??
??將圖像和相關的調色板拷貝到剪貼板;??
??將捕獲的單幀圖像保存為DIB格式的文件。
●CapDriverConnect : 使一個捕獲窗與一個設備驅動程序相關聯。單獨定義的一個捕獲窗是不能工作的,它必需與一個設備相關聯,這樣才能取得視頻信號。
●CapCaptureSetSetup,CapPreviewScale,CapPreviewRate : 設置視頻設備的屬性。 通過設置TcaptureParms結構變量的各個成員變量,可以控制設備的采樣頻率、中斷采樣按鍵、狀態行為等等。設置好 TCaptureParms結構變量后,可以用函數CapCaptureSetSetup使設置生效。之后還可以用CapPreviewScale、 CapPreviewRate來設置預覽的比例與速度,也可以直接使用設備的默認值。
●CapOverlay,CapPreview :打開預覽。 利用函數CapOverlay選擇是否采用疊加模式預覽,這樣占用系統資源小,并且視頻顯示速度快。然后用CapPreview啟動預覽功能,這時就可以在屏幕上看到來自攝像機的圖像了。
編程實例
為了能夠捕獲視頻幀,要啟動一個捕獲幀回調函數VideoStreamCallBack。
捕獲一個視頻流或當前設備狀態時分別使用以下函數:
//捕獲一個視頻流
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);
自定義的函數2 //定義捕獲幀回調函數:
function FrameCallBack(hWnd:HWND; lpVHdr:LongInt) :LongInt; stdcall;
var??
DataPoint:^byte;??
DibLen,RectWidth,RectHeight:integer;
begin??
//轉換從回調函數中得到的指針
VideoStr:=LPVIDEOHDR(lpVHdr);
//得到返回的數據大小??
DibLen:=VideoStr^.dwBufferLength;??
GetMem(DataPoint,64000);
//將幀數據COPY到一個內存中,注意DATAPOINT要先分配空間
CopyMemory(DataPoint,VideoStr^.lpData,Diblen);??
//一些其他處理
……
end;
靈活地使用AVICap窗口類的回調函數可以滿足各種不同的需求,但要注意從視頻卡中捕獲的視頻數據的格式和圖像的長寬要參考視頻卡的參數。而且有些視頻卡通過設置可支持多種的格式和圖像長寬,所以在還原圖像時要注意參考所用的視頻卡的參數。
與視頻捕獲相關的編程。
1、定義全局變量:
HWND ghWndCap ; //捕獲窗的句柄
CAPDRIVERCAPS gCapDriverCaps ; //視頻驅動器的能力
CAPSTATUS gCapStatus ; //捕獲窗的狀態
2、處理WM_CREATE消息:
//創建捕獲窗,其中hWnd為主窗口句柄
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)) ;
3、處理WM_CLOSE消息:
//取消所登記的三個回調函數
capSetCallbackOnStatus(ghWndCap, NULL);
capSetCallbackOnError(ghWndCap, NULL);
capSetCallbackOnFrame(ghWndCap, NULL);
capCaptureAbort(ghWndCap);//停止捕獲
capDriverDisconnect(ghWndCap); //將捕獲窗同驅動器斷開
4、處理菜單項Preview:
capPreviewRate(ghWndCap, 66); // 設置Preview模式的顯示速率
capPreview(ghWndCap, TRUE); //啟動Preview模式
5、處理菜單項Overlay:
if(gCapDriverCaps.fHasOverlay) //檢查驅動器是否有疊加能力
capOverlay(ghWndCap,TRUE); //啟動Overlay模式
6、處理菜單項Exit:
SendMessage(hWnd,WM_CLOSE,wParam,lParam);
7、分別處理Setting下的三個菜單項,它們可分別控制視頻源、視頻格式及顯示:
if (gCapDriverCaps.fHasDlgVideoSource)
capDlgVideoSource(ghWndCap); //Video source 對話框
if (gapDriverCaps.fHasDlgVideoFormat)
capDlgVideoFormat(ghWndCap); // Video format 對話框
if (CapDriverCaps.fHasDlgVideoDisplay)
capDlgVideoDisplay(ghWndCap); // Video display 對話框
8、處理Video Stream菜單項,它捕獲視頻流到一個.AVI文件:
char szCaptureFile[] = "MYCAP.AVI";
capFileSetCaptureFile( ghWndCap, szCaptureFile); //指定捕獲文件名
capFileAlloc( ghWndCap, (1024L * 1024L * 5)); //為捕獲文件分配存儲空間
capCaptureSequence(ghWndCap); //開始捕獲視頻序列
9、處理Single Frame菜單項:
capGrabFrame(ghWndCap); //捕獲單幀圖像
10、定義三個回調函數:
LRESULT CALLBACK StatusCallbackProc(HWND hWnd, int nID, LPSTR lpStatusText)
{
if (!ghWndCap) return FALSE;
//獲得捕獲窗的狀態
capGetStatus(ghWndCap, &gCapStatus, sizeof (CAPSTATUS));
//更新捕獲窗的大小
SetWindowPos(ghWndCap, NULL, 0, 0, gCapStatus.uiImageWidth,
gCapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE);
if (nID == 0) { // 清除舊的狀態信息
SetWindowText(ghWndCap, (LPSTR) gachAppName);
return (LRESULT) TRUE;
}
// 顯示狀態 ID 和狀態文本
wsprintf(gachBuffer, "Status# %d: %s", nID, lpStatusText);
SetWindowText(ghWndCap, (LPSTR)gachBuffer);
return (LRESULT) TRUE;
}
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;
}
LRESULT CALLBACK FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)
{
if (!ghWndCap)
return FALSE;
//假設fp為一打開的.dat文件指針
fwrite(fp,lpVHdr->lpData,lpVHdr->dwBufferLength,1);
return (LRESULT) TRUE ;
}
值得注意的是:應在.cpp文件中加入#include 一句,在Link設置中加入vfw32.lib。
上述的回調函數FrameCallbackProc是將視頻數據直接從緩沖寫入文件,也可利用memcpy函數將視頻數據直接拷貝到另一緩存。同理,可 定義VideoStreamCallbackProc。capSetCallbackOnVideoStream的使用比 capSetCallbackOnFrame稍微復雜一些。在捕獲過程中,當一個新的視頻緩沖可得時,系統就調用它所登記的回調函數。在缺省情況下,捕獲 窗在捕獲過程中不允許其它應用程序繼續運行。為了取消這個限制,可以設置CAPTUREPARMS的成員fYield為TRUE或建立一個Yield回調 函數。為了解決潛在的重入(reentry)問題,可在YieldCallbackProc中用PeekMessage過濾掉一些消息,例如鼠標消息。
轉載于:https://www.cnblogs.com/oskycar/archive/2009/08/10/1543046.html
總結
- 上一篇: 何谓程序员?何谓中国的程序员?
- 下一篇: ASP.NET防止页面刷新的方法