?? directshowimediadet.txt
字號:
很多視頻播放軟件或視頻編輯軟件都提供了抓幀的功能,利用這類軟件,視頻工作者可以很輕松地將一個電影某一時刻的幀抓取出來并保存為圖片文件,那么,我們?nèi)绾巫约壕幊虒崿F(xiàn)這樣的功能呢?如果你熟悉MPEG或者AVI等常見視頻格式,你可以直接對影片文件進行操作,如果你不知道這些視頻格式,而希望使用更簡單的方法來抓取影片的幀,微軟的DirectShow將會給你極大的驚喜。
DirectShow屬于DirectX家族(DirectX還包括Direct3D、DirectInput、DirectDraw、DirectSound等組件),在使用DirectShow開發(fā)抓取幀的程序前,你必須要安裝DirectX SDK,這個開發(fā)包可以在微軟的網(wǎng)站上下載得到,目前最新版本是9.0b;另外,由于DirectX SDK是用COM的方式發(fā)布的,所以對于開發(fā)人員而言,他還必須要了解COM的基本原理。如果大家沒有使用過COM,可以先從網(wǎng)上找一些COM方面的入門教程看看,VC知識庫上就有很多好文章,推薦VC知識庫第九期趙湘寧的《COM編程入門》系列。
一、編程工具的設(shè)置:
先說說我使用的VC 6.0的設(shè)置,一般而言,安裝完DirectX 9.0b SDK后,會自動設(shè)置好VC,用戶無需手動干預(yù),如果編譯過程中出現(xiàn)錯誤,請檢查VC是否包含了DirectX SDK的頭文件和庫文件,方法是選擇菜單“Tools->Options…”,在彈出的Options對話框中選擇Directories選項卡,看看Include files和Library files中是否包含有DirectX SDK的Include路徑和Lib路徑,如果沒有,將這兩個路徑添加上去即可。
二、主要的實現(xiàn)步驟:
在實現(xiàn)抓取影片幀的過程中,DirectShow的IMediaDet接口將是主角,這個接口包含了一些方法能夠從媒體源文件中提取一些重要信息,比如媒體類型、幀速率甚至是視頻流的單個幀。
·注意
要正確使用IMediaDet接口,工程中需要包含下列文件:
頭文件:dshow.h, qedit.h
庫文件:strmiids.lib
因為使用CComPtr模板來聲明接口實例,所以還要在工程中包含atlbase.h頭文件。
下面我們將一步步利用IMediaDet接口實現(xiàn)抓取影片幀的功能。
第一步:新建一個基于對話框的應(yīng)用程序,為應(yīng)用程序添加兩個編輯控件和三個按鈕控件,程序界面如圖所示:
第二步:為對話框類添加一個HRESULT類型的成員函數(shù)GrabFramFromMovie,它將實現(xiàn)抓幀功能。在函數(shù)體內(nèi)創(chuàng)建IMediaDet接口實例,創(chuàng)建實例需要調(diào)用CoCreateInstance函數(shù),并給函數(shù)的第一個參數(shù)傳入CLSID_MediaDet類標識符。
第三步:調(diào)用IMediaDet::put_Filename方法為接口指定一個媒體文件,該方法只有一個參數(shù),這個參數(shù)描述了媒體文件的路徑,注意參數(shù)類型為BSTR。
第四步:調(diào)用IMediaDet::get_OutputStreams方法以得到影片輸出流的數(shù)目,一個影片的輸出由多個流組成,但是get_OutputStreams方法只關(guān)心影片輸出的視頻流和音頻流而自動忽略其它流,所以,如果一個影片輸出包含有視頻流、音頻流和數(shù)據(jù)流,get_OutputStreams只返回視頻流和音頻流的數(shù)目。
第五步:調(diào)用IMediaDet::put_CurrentStream方法指定一個用于編輯和操作的流,因為我們的目的是要將影片的單個幀保存為圖片,這就需要對視頻流進行操作,所以要利用put_CurrentStream定位影片文件輸出的視頻流。
第六步:調(diào)用IMediaDet::get_StreamMediaType方法得到一個VIDEOINFORHEADER結(jié)構(gòu),這個結(jié)構(gòu)與當前指定的視頻流關(guān)聯(lián)。VIDEOINFORHEADER結(jié)構(gòu)中包含有一個BITMAPINFORHEADER結(jié)構(gòu)類型的成員,它描述了視頻影像對應(yīng)位圖的尺寸、顏色等有用的信息。
第七步:調(diào)用IMediaDet::WriteBitmapBits方法將影片的幀保存為位圖,若想指定保存哪一幀,只需要給第一個參數(shù)傳遞一個合適的時間即可。這里,我傳遞給第一個參數(shù)的時間為0,因此程序?qū)⒈4嬗捌谝粠奈粓D。
下面是GrabFramFromMovie函數(shù)的完整代碼,其中,變量m_editOpenDir和m_editSaveDir分別指定了影片路徑及保存的位圖路徑,請對照上面的步驟閱讀:
貼子相關(guān)圖片:
作者: kony2008 2006-6-21 16:57 回復(fù)此發(fā)言
--------------------------------------------------------------------------------
2 用DirectShow的IMediaDet接口抓取影片幀
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;
// 將影片文件名轉(zhuǎn)換成BSTR類型
CComBSTR openBSTR(m_editOpenDir);
// 設(shè)置IMediaDet接口的文件關(guān)聯(lián)
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; iput_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結(jié)構(gòu)指針,VIDEOINFOHEADER結(jié)構(gòu)包含一些與視頻
// 有關(guān)的信息,其中含有BITMAPINFORHEADER結(jié)構(gòu)
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat);
width = pVih->bmiHeader.biWidth;
height = pVih->bmiHeader.biHeight;
}
else
hr = VFW_E_INVALIDMEDIATYPE;
MyFreeMediaType(mt); // 釋放AM_MEDIA_TYPE結(jié)構(gòu)
}
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方法中的第一個參數(shù)來保存我們指定的幀。源代碼的DEBUG文件夾下包含了一個測試影片,供測試使用。該程序在Windows XP、Visual C++ 6和DirectX 9.0b環(huán)境下編譯并運行通過。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -