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

Visual C++ 實作攝影機影像擷取:基於 DirectShow 的 CCaptureVideo 類完整教學

     編輯:關於VC++

DirectShow 是微軟提供的串流媒體處理架構,支援從 WDM 驅動裝置 (如 USB 攝影機、擷取卡) 擷取影音資料並進行預覽、儲存、靜態擷圖。本文封裝一個 CCaptureVideo MFC 類別,將複雜的 Filter Graph 建立、裝置列舉、預覽視窗設定、Sample Grabber 靜態擷圖等功能整合,僅需三個公開方法即可完成影像擷取應用。

架構概覽

  • Capture Graph Builder (ICaptureGraphBuilder2):快速建立/控制擷取圖表。
  • Filter Graph (IGraphBuilder):管理 Filter 連接與資料流。
  • Video Capture Filter:代表實體攝影機裝置。
  • Sample Grabber Filter:攔截影像幀以擷取靜態圖片 (BMP)。
  • Video Renderer / Video Window:於指定視窗顯示預覽畫面。

核心類別設計:CCaptureVideo

公開介面

關鍵私有成員

IGraphBuilder *m_pGB;
ICaptureGraphBuilder2 *m_pCapture;
IBaseFilter *m_pBF;           // Capture Filter
IMediaControl *m_pMC;         // 媒體控制 (Run/Stop)
IVideoWindow *m_pVW;          // 視窗顯示控制
CComPtr<ISampleGrabber> m_pGrabber; // Sample Grabber
CSampleGrabberCB mCB;         // 回呼類別,處理 BufferCB

關鍵實作細節

1. 裝置列舉 (EnumDevices)

int CCaptureVideo::EnumDevices(HWND hList) {
  ICreateDevEnum *pCreateDevEnum;
  CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
                   IID_ICreateDevEnum, (void**)&pCreateDevEnum);
  CComPtr<IEnumMoniker> pEm;
  pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
  pEm->Reset();
  IMoniker *pM; ULONG cFetched;
  int id = 0;
  while (pEm->Next(1, &pM, &cFetched) == S_OK) {
    IPropertyBag *pBag;
    pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);
    VARIANT var; var.vt = VT_BSTR;
    pBag->Read(L"FriendlyName", &var, NULL);
    TCHAR str[2048];
    WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, str, 2048, NULL, NULL);
    ::SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)str);
    SysFreeString(var.bstrVal);
    pBag->Release(); pM->Release(); id++;
  }
  return id;
}

2. 建立擷取圖表

  • InitCaptureGraphBuilder():建立 IGraphBuilder、ICaptureGraphBuilder2、IMediaControl、IVideoWindow。
  • BindFilter():依索引綁定裝置 Moniker 至 IBaseFilter。
  • 加入 Capture Filter 至 Graph。
  • 建立 Sample Grabber,設定媒體類型為 MEDIASUBTYPE_RGB24,加入 Graph。
  • RenderStream(PIN_CATEGORY_PREVIEW, MEDIATYPE_Video, pCap, pGrabBase, NULL) 連接預覽腳位 → Grabber → Renderer。
  • 取得連接後的媒體格式 (VIDEOINFOHEADER) 記錄寬高,供 BMP 儲存用。
  • 設定 Grabber 回呼模式:SetCallback(&mCB, 1) (使用 BufferCB)。
  • SetupVideoWindow():設定 Video Window 為子視窗、填滿客戶區、顯示。
  • m_pMC->Run() 開始預覽。

3. 靜態擷圖回呼 (CSampleGrabberCB::BufferCB)

STDMETHODIMP BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize) {
  if (!bOneShot) return 0; // 全域旗標,由 GrabOneFrame(TRUE) 設定
  if (!pBuffer) return E_POINTER;
  SaveBitmap(pBuffer, lBufferSize); // 寫入 BMP 檔案
  bOneShot = FALSE;
  return 0;
}

SaveBitmap 手動建構 BITMAPFILEHEADER + BITMAPINFOHEADER (24-bit RGB) + 像素資料。

使用範例:MFC 對話方塊應用程式

  1. 建立 MFC 對話方塊專案,放置 CComboBox (IDC_COMBO1)、兩個按鈕 (IDC_HAVEALOOK 啟動、IDC_PHOTO 擷圖)、一個 Picture Control (IDC_STATIC_SCREEN, Type=Rectangle, Color=Gray)。
  2. 加入成員變數:CComboBox m_ListCtrl、CStatic m_staticScreen、CCaptureVideo m_cap。
  3. OnInitDialog:m_cap.EnumDevices(m_ListCtrl); m_ListCtrl.SetCurSel(0);
  4. 啟動按鈕:m_cap.Init(m_ListCtrl.GetCurSel(), m_staticScreen.GetSafeHwnd());
  5. 擷圖按鈕:m_cap.GrabOneFrame(TRUE);

編譯與部署注意事項

  • 環境:Windows 2000 + DirectX 9 SDK + VC6 (亦適用 VS2005+ 配合 Windows SDK)。
  • 連結庫:Strmiids.lib、Quartz.lib (DirectX SDK 提供)。
  • 標頭檔:<dshow.h>、<atlbase.h> (需 ATL 支援)。
  • 若 qedit.dll 未註冊,Sample Grabber 建立會失敗,請執行 regsvr32 qedit.dll。

總結

CCaptureVideo 將 DirectShow 複雜的 Filter Graph 建立、裝置管理、預覽視窗綁定、靜態擷圖等功能封裝為簡潔的三介面類別,大幅降低開發門檻。開發者可依需求擴充:支援多種輸出格式 (JPG/PNG)、影片錄製 (ASF/MP4)、影像處理 (OpenCV 整合) 等。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法用途
int EnumDevices(HWND hList)列舉系統視訊擷取裝置,填入下拉清單 (ComboBox)
HRESULT Init(int iDeviceID, HWND hWnd)初始化指定裝置,於 hWnd 顯示預覽畫面
void GrabOneFrame(BOOL bGrab)觸發單幀擷取,儲存為 BMP (預設 c:\\donaldo.bmp)