程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 用DirectShow抓取影片幀

用DirectShow抓取影片幀

編輯:關於VC++

很多視頻播放軟件或視頻編輯軟件都提供了抓幀的功能,利用這類軟件,視頻工作者可以 很輕松地將一個電影某一時刻的幀抓取出來並保存為圖片文件,那麼,我們如何自己編程實 現這樣的功能呢?如果你熟悉MPEG或者AVI等常見視頻格式,你可以直接對影片文件進行操作 ,如果你不知道這些視頻格式,而希望使用更簡單的方法來抓取影片的幀,微軟的 DirectShow將會給你極大的驚喜。

DirectShow屬於DirectX家族(DirectX還包括 Direct3D、DirectInput、DirectDraw、DirectSound等組件),在使用DirectShow開發抓取 幀的程序前,你必須要安裝DirectX SDK,這個開發包可以在微軟的網站上下載得到,目前最 新版本是9.0b;另外,由於DirectX SDK是用COM的方式發布的,所以對於開發人員而言,他 還必須要了解COM的基本原理。如果大家沒有使用過COM,可以先從網上找一些COM方面的入門 教程看看

一、編程工具的設置:

先說說我使用的VC 6.0的設置,一般而言, 安裝完DirectX 9.0b SDK後,會自動設置好VC,用戶無需手動干預,如果編譯過程中出現錯 誤,請檢查VC是否包含了DirectX SDK的頭文件和庫文件,方法是選擇菜單“Tools- >Options…”,在彈出的Options對話框中選擇Directories選項卡,看看 Include files和Library files中是否包含有DirectX SDK的Include路徑和Lib路徑,如果沒 有,將這兩個路徑添加上去即可。

二、主要的實現步驟:

在實現抓取影片幀 的過程中,DirectShow的IMediaDet接口將是主角,這個接口包含了一些方法能夠從媒體源文 件中提取一些重要信息,比如媒體類型、幀速率甚至是視頻流的單個幀。

·注 意

要正確使用IMediaDet接口,工程中需要包含下列文件:

頭文件:dshow.h, qedit.h

庫文件:strmiids.lib

因為使用CComPtr模板來聲明接口實例,所以 還要在工程中包含atlbase.h頭文件。

下面我們將一步步利用IMediaDet接口實現抓取 影片幀的功能。

第一步:新建一個基於對話框的應用程序,為應用程序添加兩個編輯 控件和三個按鈕控件,程序界面如圖所示:

第二步:為對話 框類添加一個HRESULT類型的成員函數GrabFramFromMovie,它將實現抓幀功能。在函數體內 創建IMediaDet接口實例,創建實例需要調用CoCreateInstance函數,並給函數的第一個參數 傳入CLSID_MediaDet類標識符。

第三步:調用IMediaDet::put_Filename方法為接口 指定一個媒體文件,該方法只有一個參數,這個參數描述了媒體文件的路徑,注意參數類型 為BSTR。

第四步:調用IMediaDet::get_OutputStreams方法以得到影片輸出流的數目 ,一個影片的輸出由多個流組成,但是get_OutputStreams方法只關心影片輸出的視頻流和音 頻流而自動忽略其它流,所以,如果一個影片輸出包含有視頻流、音頻流和數據流, get_OutputStreams只返回視頻流和音頻流的數目。

第五步:調用 IMediaDet::put_CurrentStream方法指定一個用於編輯和操作的流,因為我們的目的是要將 影片的單個幀保存為圖片,這就需要對視頻流進行操作,所以要利用put_CurrentStream定位 影片文件輸出的視頻流。

第六步:調用IMediaDet::get_StreamMediaType方法得到一 個VIDEOINFORHEADER結構,這個結構與當前指定的視頻流關聯。VIDEOINFORHEADER結構中包 含有一個BITMAPINFORHEADER結構類型的成員,它描述了視頻影像對應位圖的尺寸、顏色等有 用的信息。

第七步:調用IMediaDet::WriteBitmapBits方法將影片的幀保存為位圖, 若想指定保存哪一幀,只需要給第一個參數傳遞一個合適的時間即可。這裡,我傳遞給第一 個參數的時間為0,因此程序將保存影片第一幀的位圖。

下面是GrabFramFromMovie函 數的完整代碼,其中,變量m_editOpenDir和m_editSaveDir分別指定了影片路徑及保存的位 圖路徑,請對照上面的步驟閱讀:

HRESULT CFrameGrabberDlg::GrabFrameFromMovie()
{
  HRESULT hr;
  // 定 義IMediaDet接口實例
  CComPtr< IMediaDet > pDet;
  hr = CoCreateInstance( CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
     IID_IMediaDet, (void**) &pDet );
  if (FAILED(hr))
    return hr;

  // 將影片文件名轉換成BSTR類型
  CComBSTR openBSTR (m_editOpenDir);
  // 設置IMediaDet接口的文件關聯
  hr = pDet- >put_Filename(openBSTR);
  if (FAILED(hr))
    return hr;

  // 從影片中檢索視頻流和音頻流
  long lStreams;
  hr = pDet->get_OutputStreams(&lStreams);
  if (FAILED(hr))
     return hr;

  // 取出影片的視頻流,因為幀的信息是保存在視頻流中的
  bool bFound = false;
  for (int i=0; i<lStreams; i++)
   {
    GUID major_type;
    hr = pDet->put_CurrentStream (i);
    if (SUCCEEDED(hr))
      hr = pDet- >get_StreamType(&major_type);
    if (FAILED(hr))
       break;
    if (major_type == MEDIATYPE_Video)
    {
       bFound = true;
      break;
    }
  }
   if (!bFound)
    return VFW_E_INVALIDMEDIATYPE;

  long width = 0, height = 0; // 存儲位圖的寬和高(單位:象素)
  AM_MEDIA_TYPE mt;
  hr = pDet->get_StreamMediaType(&mt);
  if (SUCCEEDED (hr))
  {
    if ((mt.formattype == FORMAT_VideoInfo) &&
      (mt.cbFormat >= sizeof(VIDEOINFOHEADER)))
     {
      // 得到VIDEOINFOHEADER結構指針,VIDEOINFOHEADER結構包含 一些與視頻
      // 有關的信息,其中含有BITMAPINFORHEADER結構
       VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat);
       width = pVih->bmiHeader.biWidth;
      height = pVih- >bmiHeader.biHeight;
    }
    else
      hr = VFW_E_INVALIDMEDIATYPE;
    MyFreeMediaType(mt); // 釋放AM_MEDIA_TYPE結 構
  }
  if (FAILED(hr))
    return hr;

   CComBSTR saveBSTR(m_editSaveDir);
  // 將第一幀保存為指定路徑的位圖文件
  hr = pDet->WriteBitmapBits(0, width, height, saveBSTR);
  if (FAILED(hr))
    return hr;
  return S_OK;
}

三、程 序運行:

程序運行後,選擇一個影片,然後指定保存路徑,點擊“抓取” 按鈕,就可以將影片第一幀保存到指定路徑下,我們也可以修改IMediaDet接口的 WriteBitmapBits方法中的第一個參數來保存我們指定的幀。源代碼的DEBUG文件夾下包含了 一個測試影片,供測試使用。該程序在Windows XP、Visual C++ 6和DirectX 9.0b環境下編 譯並運行通過。

下載本文示例源代碼:http://www.vckbase.com/code/downcode.asp?id=2221

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved