首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Visual C++ 視頻捕獲開發實戰:基於 AVICap 窗口類的完整解析

     編輯:關於VC++

前言:從 VFW 到 AVICap 的演進

在 Video for Windows (VFW) 推出前,數位視訊捕獲是極其複雜的系統級工程。VFW 1.1 隨 Windows 95 內建,提供統一的 AVI 檔案格式、壓縮管理器 (ICM)、音訊壓縮管理器 (ACM) 及設備驅動介面。Visual C++ 4.0 起內建支援 VFW,並提供 AVICap 窗口類——一個輕量級、訊息驅動的高階封裝,讓開發者無需處理複雜的驅動程式協定,即可實現視訊串流捕獲、預覽、壓縮存檔與單幀抓取。本文深入解析 AVICap 程式設計模型、核心結構、回呼機制與完整實戰範例。

VFW 架構回顧

VFW 六大核心模組:

  1. AVICAP.DLL:捕獲核心,提供高階 API 介面給 AVI I/O 與驅動程式。
  2. MSVIDEO.DLL:DrawDib 系列函數,處理螢幕視訊繪製。
  3. MCIAVI.DRV:MCI 指令解譯器,支援 avivideo、overlay 指令集。
  4. AVIFILE.DLL:建立於 mmio 之上,提供 AVI 檔案高階存取。
  5. ICM (Image Compression Manager):管理視訊編解碼器 (CODEC)。
  6. ACM (Audio Compression Manager):管理波形音訊編解碼器。

VC++ 專案需連結 vfw32.lib、msacm32.lib、winmm.lib。

AVICap 程式設計核心模型

捕獲窗口

透過 capCreateCaptureWindow 建立(風格 WS_CHILD | WS_VISIBLE),概念上類似標準控制項。九大核心功能:

  1. 視訊/音訊串流捕獲至 AVI 檔案
  2. 動態連接/斷開視訊與音訊輸入裝置
  3. Overlay(硬體疊加)或 Preview(GDI 軟體繪製)模式即時顯示
  4. 指定捕獲檔名、檔案內容複製
  5. 設定捕獲幀率
  6. 顯示視訊來源、格式、顯示屬性對話框
  7. 建立/儲存/載入調色盤
  8. 影像與調色盤複製到剪貼簿
  9. 單幀影像另存為 DIB 檔案

兩種顯示模式差異

模式原理硬體需求CPU 佔用
Preview幀資料經系統記憶體 → GDI 繪製於捕獲窗 → VGA 輸出通用顯示卡即可較高(需 CPU 搬移像素)
Overlay捕獲卡硬體將視訊訊號直接與 VGA 輸出合成需支援硬體疊加的捕獲卡極低(零拷貝顯示)

回呼函數機制

AVICap 允許登記四類回呼,滿足即時串流處理、視訊會議等進階需求:

  • capSetCallbackOnError:錯誤通知
  • capSetCallbackOnStatus:狀態變更(如幀率、解析度)
  • capSetCallbackOnFrame:單幀資料就緒(VIDEOHDR*)
  • capSetCallbackOnYield:捕獲過程中讓出 CPU 給其他應用

搭配 capCaptureSequenceNoFile + capSetCallbackOnVideoStream 可直接在回呼中獲取壓縮後串流資料,適用於即時傳輸場景。

核心結構體詳解

結構體用途關鍵欄位
CAPSTATUS捕獲窗口當前狀態uiImageWidth, uiImageHeight, fLiveWindow, fOverlayWindow
CAPDRIVERCAPS驅動程式能力指標fHasOverlay, fHasDlgVideoSource, fHasDlgVideoFormat, fHasDlgVideoDisplay, wDeviceIndex
CAPTUREPARMS捕獲參數控制dwRequestMicroSecPerFrame (幀率), fYield, wTimeLimit, vKeyAbort
VIDEOHDR視訊資料區塊標頭lpData (資料指標), dwBufferLength, dwBytesRecorded, dwFlags

前三者皆有對應 Get/Set 宏/函數操作。

訊息與宏的對應關係

所有操作均透過 SendMessage(hWndCap, WM_CAP_..., ...) 完成,VC++ 提供同名宏簡化呼叫:

SendMessage(hWndCap, WM_CAP_DRIVER_CONNECT, 0, 0L)  ≡  capDriverConnect(hWndCap, 0)
SendMessage(hWndCap, WM_CAP_SET_PREVIEW, TRUE, 0L)   ≡  capPreview(hWndCap, TRUE)

常用宏分類:

  • 驅動連接:capDriverConnect/Disconnect, capDriverGetCaps
  • 預覽/疊加:capPreview/PreviewRate, capOverlay
  • 檔案操作:capFileSetCaptureFile, capFileAlloc, capCaptureSequence, capCaptureSingleFrameOpen/Close, capGrabFrame, capGrabFrameNoStop
  • 對話框:capDlgVideoSource/Format/Display
  • 回呼登記:capSetCallbackOnError/Status/Frame/VideoStream/Yield
  • 調色盤:capPaletteOpen/Save/Paste

完整實戰範例:即時預覽、設定、捕獲存檔

全域變數宣告

HWND g_hWndCap;                 // 捕獲窗口句柄
CAPDRIVERCAPS g_Caps;           // 驅動能力
CAPSTATUS g_Status;             // 窗口狀態

WM_CREATE:建立與初始化

g_hWndCap = capCreateCaptureWindow("CaptureWindow", WS_CHILD|WS_VISIBLE,
    0, 0, 320, 240, hWnd, 0);

// 登記回呼
capSetCallbackOnError(g_hWndCap, (FARPROC)ErrorCallback);
capSetCallbackOnStatus(g_hWndCap, (FARPROC)StatusCallback);
capSetCallbackOnFrame(g_hWndCap, (FARPROC)FrameCallback);

// 連接驅動程式(索引 0 為第一張卡)
capDriverConnect(g_hWndCap, 0);
capDriverGetCaps(g_hWndCap, &g_Caps, sizeof(CAPDRIVERCAPS));

WM_CLOSE:資源釋放

capSetCallbackOnStatus(g_hWndCap, NULL);
capSetCallbackOnError(g_hWndCap, NULL);
capSetCallbackOnFrame(g_hWndCap, NULL);
capCaptureAbort(g_hWndCap);
capDriverDisconnect(g_hWndCap);

選單命令處理


// 預覽模式
case IDM_PREVIEW:
    capPreviewRate(g_hWndCap, 66);  // ~15 fps
    capPreview(g_hWndCap, TRUE);
    break;

// 疊加模式(需硬體支援)
case IDM_OVERLAY:
    if (g_Caps.fHasOverlay) capOverlay(g_hWndCap, TRUE);
    break;

// 視訊來源/格式/顯示對話框
case IDM_VIDEOSOURCE:
    if (g_Caps.fHasDlgVideoSource) capDlgVideoSource(g_hWndCap);
    break;
case IDM_VIDEOFORMAT:
    if (g_Caps.fHasDlgVideoFormat) capDlgVideoFormat(g_hWndCap);
    break;
case IDM_VIDEODISPLAY:
    if (g_Caps.fHasDlgVideoDisplay) capDlgVideoDisplay(g_hWndCap);
    break;

// 捕獲視訊串流至 AVI
case IDM_CAPTURE_VIDEO:
    capFileSetCaptureFile(g_hWndCap, "capture.avi");
    capFileAlloc(g_hWndCap, 5*1024*1024);  // 預分配 5MB
    capCaptureSequence(g_hWndCap);
    break;

// 單幀捕獲
case IDM_CAPTURE_FRAME:
    capGrabFrame(g_hWndCap);  // 觸發 FrameCallback
    break;

三大回呼函數實作

LRESULT CALLBACK StatusCallback(HWND hWnd, int nID, LPSTR lpText) {
    if (!g_hWndCap) return FALSE;
    capGetStatus(g_hWndCap, &g_Status, sizeof(CAPSTATUS));
    // 自動調整捕獲窗大小匹配視訊解析度
    SetWindowPos(g_hWndCap, NULL, 0, 0, g_Status.uiImageWidth, g_Status.uiImageHeight,
                 SWP_NOZORDER|SWP_NOMOVE);
    if (nID == 0) { SetWindowText(g_hWndCap, g_szAppName); return TRUE; }
    char buf[256]; wsprintf(buf, "Status #%d: %s", nID, lpText);
    SetWindowText(g_hWndCap, buf);
    return TRUE;
}

LRESULT CALLBACK ErrorCallback(HWND hWnd, int nErrID, LPSTR lpText) {
    if (!g_hWndCap) return FALSE;
    if (nErrID == 0) return TRUE;
    char buf[64]; wsprintf(buf, "Error #%d", nErrID);
    MessageBox(hWnd, lpText, buf, MB_OK|MB_ICONEXCLAMATION);
    return TRUE;
}

LRESULT CALLBACK FrameCallback(HWND hWnd, LPVIDEOHDR lpVHdr) {
    if (!g_hWndCap) return FALSE;
    // 範例:直接寫入檔案(實際應用可傳送網路、編碼、分析)
    fwrite(fp, lpVHdr->lpData, lpVHdr->dwBufferLength, 1);
    return TRUE;
}

編譯關鍵設定

  • 原始檔包含 #include <vfw.h>
  • 專案設定 → Link → Object/Library modules 加入 vfw32.lib

進階主題:Yield 機制與重入保護

預設捕獲期間獨佔 CPU。設定 CAPTUREPARMS.fYield = TRUE 或登記 YieldCallback 可讓出 CPU。回呼中使用 PeekMessage 過濾滑鼠等高頻訊息,防止重入導致堆疊溢位。

結語

AVICap 以簡潔的訊息介面封裝了 VFW 複雜的驅動協定、緩衝管理與壓縮管線,是 Windows 平台視訊捕獲開發的利器。靈活運用回呼機制,可構建視訊會議、遠端監控、工業檢測等即時視訊應用。筆者團隊即以此技術實現電話網可視電話系統,同樣適用於 ISDN、區域網多媒體會議平台。掌握 AVICap,即掌握了 Windows 視訊捕獲的核心鑰匙。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved