閱讀761 返回首頁    go 技術社區[雲棲]


VS2010 C++學習(5):基於DirectShow的視頻預覽錄像程序

VS2010 C++學習(5):基於DirectShow的視頻

預覽錄像程序

 

學習VC++編製的基於DirectShow視頻捕獲程序,主要練習基於DirectShow程序的應用。

 

一、           主要內容:

 

1.        基於DirectShow視頻預覽;

2.        基於DirectShow視頻錄像;

 

二、           設計實現:

(一)、安裝DirectShow

首先我們安裝DirectShow SDK,由於現在directShow沒有和direcxtx一起發布,而是和windows sdk 打包發布了,可以到官網下載最新的windows sdk 開發包。一個可用的下載地址為https://dl-sh-ctc-2.pchome.net/07/hh/DXSDK_Feb10.rar

然後安裝好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.libstrmbasd.libSTRMBASE.libstrmiids.lib。中間兩個lib需要用戶自己編譯生成,而其他兩個微軟已經提供。下表列出了使用DirectShow SDK開發程序所有要使用的庫。

庫名

功能說明

Strmiids.lib

定義了DirectShow標準的輸出類標識(CLSID)和接口標識(IID

Strmbasd.lib

流媒體開發用到的庫,DebugDebug_Unicode版本

Strmbase.lib

流媒體開發用到的庫,ReleaseRelease_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)      添加鏈接庫支持

C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Debug;

C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib;

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推出了DirectShowDirectShowMicrosoft推出的基於Windows平台的流媒體處理開發包,它與DirectX一起發布。DirectShow對流媒體的捕捉、回放提供了強大的支持。

1)      DirectShow係統結構分析

DirectShow主要由過濾器(Filter Graph)圖表構成。過濾圖表中包含了各種Filter,這些Filter能夠按一定順序連接在一起,構成一條流水線。

從功能的角度劃分,Filter 大體可以分為3類,

Source Filters;主要負責獲取數據,可以是一個文件、一個采集卡、聲卡或數碼相機等。

Transform Filters;負責數據的轉換、傳輸。例如各種碼器、解碼器等。

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();

而下麵的代碼則用於判斷係統中是否安裝了指定的視頻壓縮器。

ICreateDevEnum *pDevEnum = NULL;

CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,

IID_ICreateDevEnum, (void **)&pDevEnum);

IEnumMoniker *pClassEnum = NULL;

//列舉視頻壓縮設備;=CLSID_VideoCompressorCategory

pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pClassEnum, 0);

while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)    

{

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);

pMoniker->Release();

break;

}

VariantClear(&varName);

}

pClassEnum->Release();

 

4)      查找Filter Pin過濾器引腳

每一個過濾器(Filter)至少應有一個引腳(Pin),或者是輸入引腳或者是輸出引腳。有些過濾器還擁有多個引腳,即又輸入引腳又有輸出引腳。但是過濾器的輸入、輸出引腳並不是對應的,有些過濾器可以有多個輸入引腳,而隻有一個輸出引腳或者沒有輸出引腳。在程序中為了連接過濾器間的引腳,通常需要獲得過濾器的各個引腳。

用戶可以使用IEnumPins接口來枚舉某一個過濾器的輸入、輸出引腳。過濾器 IBaseFilter提供了一個EnumPins方法用於生成一個IEnumPins接口實例,這樣,通過調用IEnumPinsNext方法便可以訪問各個引腳了。

下麵的代碼定義了一個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 * pComOut,*pComIn ;

pComIn  = FindPin(pCompress,PINDIR_INPUT);

pComOut = FindPin(pCompress,PINDIR_OUTPUT);

IPin* pOutpin = FindPin(pSrc,PINDIR_OUTPUT); //pSrc的輸出引腳

HRESULT result ;

result = pGraph->ConnectDirect(pOutpin,pComIn,NULL);

 

 

 

 

最後更新:2017-04-03 12:54:38

  上一篇:go Java中的cookie(3)——cookie中存取中文
  下一篇:go Java中的cookie(2)——cookie共享