DirectShow系統概述

 

1. 關於DirectShow

1.1
DirectX是微軟公司開發的一套基於Windows平臺的編程接口(API);它能出色地完成高速的實時動畫渲染、交互式音樂和環境音效、高效多媒體數據處理等一般API很難完成的任務。
DirectShow是DirectX大家族中的一位成員。DirectX的家族成員很多,而且各有各的本領,就如DirectDraw和Direct3D負責二維圖形圖像/三維動畫加速、DirectMusic和DirectSound負責交互式音樂/環境音效處理一樣,DirectShow爲Windows平臺上處理各種格式的媒體文件播放、音視頻採集等高性能要求的多媒體應用,提供了完整的解決方案。

DirectShow是一個開放性的應用框架,也是一套基於COM的編程接口。DirectShow的系統功能參見圖1.1。可以看到,圖中最大的一塊即是DirectShow系統,它的基本工作原理就是“流水線”:將單元組件——Filter——串聯在一起,交由Filter Graph Manager統一控制。系統的輸入可以是本地文件系統、硬件插卡、因特網等,系統的輸出可以是聲卡(聲音再現)、顯卡(視頻內容顯示)、本地文件系統,當然也可以最終將數據向網絡發送。

事實上,計算機應用領域中的很多模塊都可以和DirectShow系統交互。也就是說,DirectShow的應用範疇很廣。單純從本地系統來說,DirectShow可以實現不同格式的媒體文件的解碼播放、或格式之間的相互轉換,可以從本地機器中的採集設備採集音視頻數據並保存爲文件,可以接收、觀看模擬電視等。而從網絡應用的角度來說,DirectShow更可用於視頻點播、視頻會議、視頻監控等領域。其實,廣義上來說,DirectShow系統適合於一切流式數據的處理,這些數據可以是音頻、視頻這樣的多媒體數據,但又不侷限於多媒體數據。

隨着信息技術的發展,多媒體技術迎來新的挑戰:
(1)多媒體流包含了大量的數據,這些數據要求被迅速處理以達到實時性。
(2)視頻流和音頻流的同步。
(3) 流的來源非常複雜,包括本地文件、Internet 網絡、攝像頭、視頻卡和電視廣播網等。
(4)流的格式也多種多樣,包括Audio2Video Interleaved(AVI) ,Advanced Streaming Format (ASF) , Motion Picture Experts Group (MPEG) ,and Digital Video (DV)等。
(5)開發人員事先並不知道終端用戶的硬件設備。

Microsoft的DirectShow正是爲了適應以上的挑戰而設計的多媒體開發工具, Microsoft 設計它的意圖就是簡化多媒體應用程序的開發,使開發者不必考慮複雜的流數據格式和不同的終端設備,以及數據同步的問題。
Microsoft 通過DirectShow給多媒體程序開發員提供了標準的、統一的、高效的API接口。DirectShow技術是建立在DirectX的DirectDraw和DirectSound 的基礎之上的,它通過 DirectDraw 對顯卡進行控制以顯示視頻,通過DirectSound 對聲卡進行控制以播放聲音。DirectX爲了最大限度提高效率而允許用戶直接訪問硬件,如允許用戶直接讀寫顯存,因此,DirectShow也同樣具有快速的優勢。

爲了實現對多種對象(不同流格式和不同的終端設備)的處理,DirectShow使用了組件(COM)封裝的實現方法,在DirectShow中組件稱爲濾波器(Filter) 。
圖1爲用戶程序與DirectShow及外部對象的關係框


圖1  DirectShow系統框圖
從圖1 中可以看到,DirectShow的濾波器支持多種外部設備,包括本地文件系統、視頻採集卡、有線電視接口、視頻播放卡(通過 DirectDraw 或 Graphic Device Interface) 、音頻播放卡(通過DirectSound) 。雖然DirectShow是基於 COM (Component Object Model)技術上的,但是如果只是用DirectShow開發自己的應用程序而不涉及開發自己的DirectShow組件,就不需要了解太多的COM的知識。

儘管Microsoft 提供的標準DirectShow開發包已經支持了很多格式,但畢竟不是囊括一切,如它就不支持的解碼。但是 由於 是一個開放系統,它允許用戶根據自己的需要按照一定規範編寫自己的濾波器(也就是COM) ,擴充DirectShow的功能。

1.2 VC開發環境的配置

(假設DirectX SDK8.1安裝在C:/DXSDK目錄下。)
1. 編譯基類源代碼,至少生成兩個靜態庫文件
打開C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses/baseclasses.dsw,Debug版本生成strmbasd.lib,Release版本生成strmbase.lib。

2. 配置VC的編譯環境:Include目錄和Lib目錄。執行VC的菜單命令Tools | Options…,在隨後彈出的對話框中進入Directories一頁,在Show directories for一項選擇Include files,然後配置如下:(注意,務必將DirectX SDK的目錄放在標準的VC目錄之前。)
C:/DXSDK/Include
C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses
C:/ DXSDK/samples/Multimedia/Common/include
C:/Program Files/Microsoft Visual Studio/VC98/INCLUDE
C:/Program Files/Microsoft Visual Studio/VC98/MFC/INCLUDE
C:/Program Files/Microsoft Visual Studio/VC98/ATL/INCLUDE
再在Show directories for一項選擇Library files,配置如下:
C:/DXSDK/Lib
C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses /DEBUG
C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses /RELEASE
C:/PROGRAM FILES/MICROSOFT SDK/LIB
C:/Program Files/Microsoft Visual Studio/VC98/LIB
C:/Program Files/Microsoft Visual Studio/VC98/MFC/LIB

3. 配置DirectShow應用程序開發項目需要連接的庫文件。
執行VC的菜單命令Project | Settings…,在隨後彈出的對話框中進入Link一頁,在Object/library modules一項,Debug版輸入Strmbasd.lib Msvcrtd.lib Winmm.lib,Release版本輸入Strmbase.lib Msvcrt.lib Winmm.lib。Ignore default libraries. (In Microsoft® Visual C++® 6.0, choose Settings from the Project menu. Click the Link tab and check Ignore all default libraries.)

4. 如果安裝的DirectX SDK的版本是9.0以前的,請確認在編譯應用程序的Debug版本之前已經定義了DEBUG宏。執行VC的菜單命令Project | Settings…,在隨後彈出的對話框中進入C/C++一頁,在Category一項選擇Preprocessor,然後確認Preprocessor definitions中有DEBUG(如果沒有就自己加上)。
另外,應用程序在調用任何COM庫函數之前,務必調用CoInitialize或CoInitializeEx進行COM庫的初始化(一般只需在程序啓動的時候調用一次);在結束所有COM操作之後,調用CoUninitialize進行反初始化(一般在程序退出之前調用一次)。而當程序中有多個線程都要使用COM庫函數時,則每個線程都要進行初始化和反初始化。總之,要保證CoUninitialize和CoInitialize(或CoInitializeEx)調用的一一配對。

2  DirectShow 的組成構架

DirectShow 是一個基於COM(組件對象模型)的系統,由許多模塊化的軟件組件組成。在這個系統中,最基本的構造模塊是稱爲過濾器(Filter)的軟件組件。Filter將多媒體數據的處理過程分爲若干步驟,每一步由一個過濾器來完成,對多媒體數據流執行一個簡單的操作。過濾器有輸入和輸出,它接受輸入併產生輸出。例如,對於一個解碼過濾器,它的輸入是按某種格式經過編碼的多媒體數據流,它輸出的是經過過濾器解碼的數據流。
在應用程序中,爲了完成對多媒體數據的處理,需要將若干過濾器連接起來,一個的輸出作爲另一個的輸入,這樣連接在一起的一組過濾器稱爲過濾器流水線(Filter Graph)。過濾器流水線也掌握着每一步該使用哪一個過濾器及這些過濾器之間是如何連接的。這樣,多媒體數據流就在過濾器流水線上,從源過濾器經由中間過濾器移動到播放過濾器,從而得到播放。在這個過程中完成了數據的讀取、解碼、將數據輸出到相應的設備、播放等操作。

過濾器之間數據傳輸的細節由插頭(Pid)來處理。插頭實際上是一個COM對象,分爲輸入插頭和輸出插頭,一個過濾器包含一個輸入插頭和一個輸出插頭,或者包含其中的一個。插頭相當於過濾器之間的連結點,位於上游的過濾器的輸出插頭和位於下游的過濾器的輸入插頭連結在一起。

過濾器及過濾器流水線的管理,是由一個更高一級組件來完成的,即過濾器流水線管理器(Filter Graph Manager),它提供對經過流水線的數據流的高級控制。通常,它會自動地爲你處理數據流。應用程序一般不用直接操作過濾器,只需要執行一些較高級的調用,如運行(Run)、停止(Stop)等。
(VC下利用DirectShow播放多媒體文件.PDF)

2.1  濾波器(Filter)
濾波器是 DirectShow的最基本的組成元件。DirectShow對數據流的處理大致可以分成幾個獨立的過程,每個過程完成不同的工作。而濾波器正是完成這些過程的基本單元。事實上,用戶的一個應用程序就是幾個不同功能的濾波器合在一起的濾波器圖(Filter Graph) 。
DirectShow Filter 可以分爲以下幾個種類:
(1)源濾波器(Source Filter)
源濾波器是整個濾波器圖(Filter Graph)中處理輸入數據的濾波器。它從外部設備獲取原始數據並作簡單處理,再將數據往下一級濾波器送。外部設備可以是文件系統、Internet 數據流、視頻採集卡等。
(2)變換濾波器(Transform Filter)
變換濾波器是整個濾波器圖(Filter Graph) 的核心,它從上一級濾波器獲取數據並對它進行處理:把原始數據流轉換成其它形式的多媒體數據流;壓縮編碼或解碼;把一個數據流分解成多個數據流(Parse) ,如把一個音頻視頻混合流分解成單獨的音頻流和單獨的視頻流;把多個數據流組合成一個數據流等。
(3)提交濾波器(Render Filter)
提交濾波器在濾波器圖裏處於最後一級,它的作用就是把經過處理的數據流提交給外部設備。這裏說的外部設備包括文件系統、顯示卡、聲卡、網卡等。

2.2  濾波器圖(Filter Graph)
任何用DirectShow開發的應用程序,都必須創建多個濾波器並進行恰當的連接,於是數據流就可以從源濾波器經傳送到 Render Filter 輸出,被用戶所使用。這些濾波器的集合就叫做濾波器圖(Filter Graph) 。圖2 就是一個 Filter Graph的例子。


圖2  一個典型的濾波器圖

2.3  Pin
Pin就是兩個濾波器相連的接口。每一個 Pin 都是從Ipin這個 COM對象派生出來的。每個 Pin 都是濾波器私有對象,濾波器可以動態地創建 Pin,銷燬 Pin,自由地控制 Pin的生存時間。Pin 可以分爲兩類:輸入 Pin 和輸出 Pin。兩個相連的 Pin必須是不同種類的,就是輸入Pin只能同輸出 Pin 相連。數據就從相連的 Pin 中流動,從上一級濾波器到下一級濾波器。兩個濾波器的Pin 相連的時候,有一個協商的過程,兩者必須統一數據流的類型、緩存的大小、數據傳送的機制等。如果協商沒有統一,這兩個濾波器就無法連接。

2.4  多媒體數據樣本和多媒體數據類型
兩個濾波器相連時,它們必須使用相同的數據類型。這樣能保證下一級濾波器可以處理從上一級濾波器得到的數據。濾波器之間傳輸的數據也是經過了COM封裝,稱爲多媒體數據樣本(Media Type) ,使用了MediaSample 或 IMediaSample2 接口。在實際數據中,還包含了時間戳以求得同步。

2.5  時鐘(Clock)
DirectShow的濾波器圖管理器爲整個濾波器圖保持了統一的參考時鐘,它對數據流的播放和同步有非常重要的作用。在每個MediaSample 中也使用了時間戳。

3  應用DirectShow 開發應用程序

3.1  COMLibrary的調用
由於DirectShow Filter 都是以COM的形式存在的,因此用戶使用DirectShow Filter 開發自己的應用程序的時候必須在開始時初始化 COMLibrary,調用 CoInitialize 函數嵌入所有的動態鏈接庫和資源。而且在程序結束的時候調用 CoUninitialize 函數釋放所有的動態鏈接庫和資源。

3.2  Filter Graph Manager接口
IGraphBuilder: 負責 Filter Graph的創建
應用程序通過此接口建立過濾器流水線。主要方法爲:RenderFile,自動識別多媒體文件的類型、格式,建立適用於該格式的過濾器流水線。
IMediaControl: 操作Filter Graph 中的多媒體數據流
控制過濾器流水線的運行。主要方法爲:Run開始運行;Pause,暫停運行;Stop,停止運行。
IMediaEvent(Ex): 處理 Filter Graph (Event)的事件
應用程序通過此接口獲得播放過程中發生的事件,如 EC_COMPLETE(播放完畢)等。主要方法爲:SetNotifyWindow,指定處理事件通知的窗口;GetEvent,獲得事件。
IVideoWindow: 用於設置多媒體播放窗口的屬性
控制視頻窗口的屬性。主要方法爲:put_Owner,指定視頻窗口的父窗口;put_FullScreenMode,指定全屏播放模式;SetWindowPosition,指定視頻窗口的位置;put_MessagerDrain,指定一個窗口,用於接收視頻窗口發出的鼠標等消息。
IMediaSeeking:提供了一些簡單的搜索功能
提供了對多媒體數據流的播放位置等屬性的精確控制。主要方法爲:SetPositons,設置播放的起始和終止位置;GetCurrentPosition,獲得當前播放位置。
IFilterMapper2:對註冊表中的濾波器進行枚舉
IBasicAudio:
控制音頻數據流的基本屬性:音量和均衡。主要方法:put_Volume、get_Volume,設置或獲得音量;put_Balance、get_Balance,設置或獲得均衡。

在實現多媒體文件的播放時需要用到上述的接口,這些接口的每個方法只執行一個簡單的操作。因此,有必要對這些接口進行封裝,見(VC下利用DirectShow播放多媒體文件.PDF)

3.3  創建 Filter Graph Manager接口
以下是創建 Filter Graph Manager接口的例子:
//首先申明並且初始化必需的接口。由於接口的索引值是自動加1 ,所以不要調用
// Iunknow::Addref
IGraphBuilder pGraph = NULL;
IMediaControl pMediaControl = NULL;
IMediaEvent pEvent = NULL;
IVideoWindow pVW = NULL;
IMediaSeeking pMS = NULL;
IFilterMapper2 pMapper = NULL;
// 實例化一個 Filter Graph Manager ,並且查詢各接口
CoCreateInstance(CLSID_FilterGraph, NULL , CLSCTX_ INPROC_SERVER,
IID_ IGraphBuilder , (void **) &pGraph) ;
pGraph -> QueryInterface ( IID_IMediaControl , ( void **)&pMediaControl2 ) ;
pGraph ->QueryInterface(IID_IMediaEvent , (void** ) &pEvent) ;
pGraph ->QueryInterface(IID_IVideoWindow, (void**) &pVW) ;
pGraph2>QueryInterface IID_IMediaSeeking, void(**)&pMS ;
CoCreateInstance(CLSID_FilterMapper2 , NULL , CLSCTX _INPROC,
IID_IFilterMapper2 ,(void **) &pMapper) ;

3.4  創建 Filter Graph
所有的DirectShow Filter 都必須在 Windows 註冊表中註冊,它對應了一個 GUID(Globally unique identifier)和一些其它濾波器的屬性,如支持的多媒體類型,濾波器的種類等等。Filter Graph Manager 就是通過搜索 Windows註冊表來得到濾波器的信息,並採用合乎需要的濾波器來構建 Filter Graph。
應用DirectShow創建 Filter Graph可以完全不用用戶操心繫統使用了哪一類濾波器,濾波器是怎樣連接的。只要調用IGraphBuilder::RenderFile函數,一個完整的Filter Graph就將誕生。下面分析一下 IGraphBuilder::RenderFile 的內部動作。
首先,IGraphBuilder 調用AddSourceFilter 去檢測文件的類型,以確定應該使用哪一類的源濾波器。確定源濾波器後,再用 IFilterMapper2::EnumMatchingFilters 來搜索註冊表中的濾波器,根據源濾波器的輸出類型來確定傳送濾波器(Transform Filter) ,接着,用 IFilterGraph::AddFil2
ter添加搜索到的濾波器。IFilterGraph 可以由 IGraphBuilder::AddSourceFilter後得到的一個 GUID,再用 CoCreateInstance 來得到。接下去就可以使用IGraph Builder::Connect 去連接兩個濾波器。還可以用同樣的方法添加其它濾波器,整個 Filter Graph就這樣建立起來了。

3.5  使用 DirectShow的事件響應機制
DirectShow的事件響應機制是Filter Graph Manager與用戶進行交互的接口,DirectShow可以處理的可以是一些事先可以預期的事件,比如數據流的結束;也可以是一些無法預期的錯誤。有的事件可以由 Filter Graph Manager自己處理,但如果 Filter Graph Manager 自己無法處理這些事件,它就把事件的通知放在事件隊列裏。用戶程序就可以通過 IMediaEvent 接口得到事件,並對它作出響應。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章