學習vc++編制的基于directshow視訊捕獲程式,主要練習基于directshow程式的應用。
一、 主要内容:
1. 基于directshow視訊預覽;
2. 基于directshow視訊錄像;
二、 設計實作:
(一)、安裝directshow
首先我們安裝directshow sdk,由于現在directshow沒有和direcxtx一起釋出,而是和windows
sdk 打包釋出了,可以到官網下載下傳最新的windows sdk
然後安裝好windows sdk。安裝完directshow sdk的目錄為c:\program files\microsoft sdks\windows\v7.1\samples\multimedia\directshow。
(二)、開發環境配置
開發環境的配置主要有兩個工作要做:
一是在使用directshow sdk開發自己的程式時需要的directshow的有關靜态庫的配置,
二是visual c++開發環境的配置。
1) 生成directshow sdk開發庫
使用directshow sdk開發使用者自己的程式需要幾個靜态連結庫:quartz.lib、strmbasd.lib、strmbase.lib和strmiids.lib。中間兩個lib需要使用者自己編譯生成,而其他兩個微軟已經提供。下表列出了使用directshow
sdk開發程式所有要使用的庫。
庫名
功能說明
strmiids.lib
定義了directshow标準的輸出類辨別(clsid)和接口辨別(iid)
strmbasd.lib
流媒體開發用到的庫,debug、debug_unicode版本
strmbase.lib
流媒體開發用到的庫,release、release_unicode版本
quartz.lib
定義了導出函數amgeterrortext
winmm.lib
使用windows多媒體程式設計用到的庫
2) 更改添加的include内容:
c:\program files\microsoft sdks\windows\v7.1\samples\multimedia\directshow\baseclasses;
c:\program files\microsoft sdks\windows\v7.1\include;
添加過程如下。選擇“ex005屬性”→“選項” →“vc++目錄” →“包含目錄”,将上面的2個include内容添加進去。
3) 更改添加lib路徑
要添加的lib内容:
c:\program files\microsoft sdks\windows\v7.1\samples\multimedia\directshow\baseclasses\debug;
c:\program files\microsoft sdks\windows\v7.1\lib;
添加過程和include内容相似,選擇“ex005屬性”→“選項” →“vc++目錄” →“庫檔案”選項。
4) 添加連結庫支援
5)
小貼士
directshow中的例子,在編譯的過程中經常會出現這樣的錯誤:
error 1 error c2061: syntax error : identifier 'camschedule' c:/program files/microsoft sdks/windows/v6.0/samples/multimedia/directshow/baseclasses/refclock.h 80
這主要是因為在不同sdk的目錄裡包含了多個 schedule.h file 和 refclock.h
是以需要在“ex005屬性”→“選項” →“vc++目錄” →“包含目錄”中調整 include 的順序,将samples/multimedia/directshow/baseclasses 放到其他的sdk之前即可
(三)、directshow視訊采集方案
流媒體處理技術以其複雜性和技術性一直受到人們的關注。随着網絡技術的不斷發展,流媒體在網絡上得到了廣泛地應用。如何能夠簡單、有效地進行流媒體處理,已成為一個焦點問題。為此,microsoft推出了directshow,directshow是microsoft推出的基于windows平台的流媒體處理開發包,它與directx一起釋出。directshow對流媒體的捕捉、回放提供了強大的支援。
1) directshow系統結構分析
directshow主要由過濾器(filter graph)圖表構成。過濾圖表中包含了各種filter,這些filter能夠按一定順序連接配接在一起,構成一條流水線。
從功能的角度劃分,filter
大體可以分為3類,
l source filters;主要負責擷取資料,可以是一個檔案、一個采集卡、聲霸卡或數位相機等。
l transform filters;負責資料的轉換、傳輸。例如各種碼器、解碼器等。
l rendering filters。負責資料的最終去向,例如将資料傳送到聲霸卡、顯示卡或存儲為檔案。
在開發directshow應用程式時,通常需要設計一個過濾圖表(filter
graph),向過濾圖表中添加相應的過濾器,最後連接配接過濾器的引腳就完成了功能的設計。
例如,實作一個簡單的視訊預覽功能,需要向過濾圖表中添加一個視訊捕捉源過濾器和一個video renderer過濾器,将視訊捕捉源過濾器的輸出引腳與video renderer過濾器的輸入引腳相連就可以了。
而在程式中隻需要按照設計過濾圖表的捕捉添加過濾器并連接配接過濾器引腳就可以了。在連接配接過濾器引腳時需要注意:隻能是輸出過濾器引腳與輸入過濾器引腳相連,兩個輸出過濾器或兩個輸入過濾器引腳是不能相連的。
2) filter圖表設計
為了友善使用者設計過濾圖表,directx提供了一個graph edit工具。
位于 c:\program files\microsoft sdks\windows\v7.1\bin\graphedt.exe。
點選運作。示範如何使用graph edit工具設計過濾圖表,過濾圖表的功能是實作視訊的預覽功能。具體步驟如下:
(1)單擊“graph/insert filters”菜單項打開“添加過濾器”視窗,
選擇一個視訊捕捉源過濾器。選擇“video renderer”最終去向過濾器,連接配接,如圖1。
圖2 寬屏haali視訊分離器
單擊工具欄中的“>”按鈕運作過濾圖表,将顯示一個視訊預覽視窗。
3) 枚舉系統裝置
使用graph edit工具,使用者可以非常友善地獲得與某一系統裝置相關的過濾器。但是,在程式中該如何獲得這些過濾器呢?
使用者可以采用枚舉的方式列舉系統中安裝的裝置。
以列舉系統中的視訊捕捉裝置為例,
(1) 首先定義一個裝置列舉接口 icreatedevenum的一個指針;
(2) 調用cocreateinstance方法建立icreatedevenum執行個體。
(3) 然後定義一個列舉螢幕 ienummoniker的一個指針;
(4) 調用icreatedevenum執行個體的createclassenumerator方法建立
ienummoniker執行個體。
(5) 最後以循環的方式調用ienummoniker執行個體的next方法周遊系統裝置;
(6) 調用ienummoniker執行個體的 bindtoobject方法将系統裝置綁定到過濾器上。
在上面的描述中,icreatedevenum執行個體的createclassenumerator方法的第一個參數确定枚舉的系統裝置。例如,第一個參數為clsid_videoinputdevicecategory,表示将要枚舉系統中的視訊捕捉卡,為
clsid_videocompressorcategory,表示枚舉系統中的視訊壓縮器。
下面的代碼示範了如何枚舉系統中的視訊捕捉卡。
//枚舉視訊裝置;值= clsid_videoinputdevicecategory
//
音頻裝置的值= clsid_ audioinputdevicecategory;
icreatedevenum *pdevenum = null;
cocreateinstance(clsid_systemdeviceenum, null, clsctx_inproc,
iid_icreatedevenum, (void **)&pdevenum);
ienummoniker *pclassenum = null;
pdevenum->createclassenumerator(clsid_videoinputdevicecategory, &pclassenum, 0);
ulong cfetched;
while (pclassenum->next(1, &pmoniker, &cfetched) == s_ok)
{
pmoniker->bindtoobject(0, 0, iid_ibasefilter, (void**)&psrc);
pmoniker->release();
break;
}
pclassenum->release();
而下面的代碼則用于判斷系統中是否安裝了指定的視訊壓縮器。
//列舉視訊壓縮裝置;值=clsid_videocompressorcategory
pdevenum->createclassenumerator(clsid_videocompressorcategory, &pclassenum, 0);
ipropertybag* pprop= null;
pmoniker->bindtostorage(0, 0, iid_ipropertybag, (void**)&pprop);
variant varname;
varname.vt = vt_bstr;
pprop->read(l"friendlyname", &varname,0);
cstring str = varname.bstrval;
if (str.find("microsoft video 1",0)!= -1)
pmoniker->bindtoobject(0, 0, iid_ibasefilter, (void**)&pcompress);
variantclear(&varname);
4) 查找filter pin過濾器引腳
每一個過濾器(filter)至少應有一個引腳(pin),或者是輸入引腳或者是輸出引腳。有些過濾器還擁有多個引腳,即又輸入引腳又有輸出引腳。但是過濾器的輸入、輸出引腳并不是對應的,有些過濾器可以有多個輸入引腳,而隻有一個輸出引腳或者沒有輸出引腳。在程式中為了連接配接過濾器間的引腳,通常需要獲得過濾器的各個引腳。
使用者可以使用ienumpins接口來枚舉某一個過濾器的輸入、輸出引腳。過濾器 ibasefilter提供了一個enumpins方法用于生成一個ienumpins接口執行個體,這樣,通過調用ienumpins的next方法便可以通路各個引腳了。
下面的代碼定義了一個findpin函數,用于獲得某個過濾器的輸入或輸出引腳。
//查找引腳
ipin* ckinescopedlg::findpin(ibasefilter *pfilter, pin_direction dir)
ienumpins* penumpins;
ipin* poutpin;
pin_direction pdir;
pfilter->enumpins(&penumpins);
while (penumpins->next(1,&poutpin,null)==s_ok)
poutpin->querydirection(&pdir);
if (pdir==dir) {return poutpin;}
return 0;
使用者可以按下面的方式獲得某個過濾器的輸入、輸出引腳。
ipin * pcomout,*pcomin ;
pcomin = findpin(pcompress,pindir_input);
pcomout = findpin(pcompress,pindir_output);
5) 連接配接filter pin過濾器引腳
使用graph edit工具,使用者可以利用滑鼠非常友善地連接配接兩個過濾器間的引腳。但是在程式中卻沒這麼簡單了。首先需要按照上面介紹的方法獲得兩個過濾器的輸入、輸出引腳,然後将第一個過濾器的輸出引腳連接配接到第二個過濾器的輸入引腳,其中,連接配接兩個引腳需要調用igraphbuilder接口的
connectdirect方法。
下面的代碼示範了如何連接配接兩個過濾器的引腳。
ipin* poutpin = findpin(psrc,pindir_output); //psrc的輸出引腳
hresult result ;
result = pgraph->connectdirect(poutpin,pcomin,null);