DirectShow所采用的是一種子產品化的結構,其基本單元是一類成為filter的COM對象。DirectShow提供了多種預定義的标準filter元件,同時開發者也可以根據需要開發自己的個性化filter。常用的filter一般可分為以下不同類别:
(1)Source Filter——為整個Filter Graph提供資料來源,這些資料可能來自硬碟檔案、網絡流媒體或者音視訊采集裝置等。不同的資料來源由不同的Source Filter負責處理。
(2)Transform Filter——負責資料的變換處理,擷取輸入資料并對其進行相應處理後,生成輸出資料并傳遞到下一個filter。典型的如編碼、解碼Filter等。
(3)Render-er Filter——位于Filter Graph的末尾,用于處理資料的渲染等操作。如視訊渲染器、音頻渲染器和寫入檔案filter等。
(4)Splitter Filter——用于分離資料流。如AVI視訊流複用了音頻和視訊信号,AVI Splitter filter的作用就是将一路AVI資料流分離成視訊流和音頻流。
(5)Mux Filter——用于複用資料流,作用與Splitter Filter相反。
每一個Filter都至少實作了IBaseFilter接口用于實作Filter Graph中的統一操作。每一個實作Filter的檔案都是動态連結庫,可能是dll但更多的是ax檔案。在代碼中,一個Filter也與其他COM對象一樣,通過API: CoCreateInstance()建立。
作為一個COM元件,注冊和解除安裝均通過regsvr32.exe程式實作。一般的filter工程會定義一下四個導出函數:DllGetClassObject,用于建立對象時調用,根據CLSID傳回對應的類廠對象;DllCanUnloadNow,用于判斷是否可以從記憶體中解除安裝;DllRegisterServer和DllUnRegisterServer用于元件的自注冊,可以在程式中通過LoadLibrary加載DLL庫後導出執行之實作自注冊。所謂“注冊”,就是将Filter的基本COM資訊寫入系統資料庫的操作。
媒體類型用于規定Filter所處理的資料的格式。其定義實際上是一個AM_MEDIA_TYPE結構體:
該結構體中描述媒體類型的成員主要有majortype, subtype和formattype三部分,分别用于描述媒體類型、具體格式和格式的細節等。
任何兩個filter之間的互相聯系通過一個COM對象Pin實作,Pin的連接配接實際上是輸出Pin和輸入Pin之間關于媒體類型的“協商”過程。每一個Pin都實作了IPin接口,Pin對象也是通過這個接口實作連接配接的。連接配接過程大緻為:
Step 1:Filter Graph Manager在輸出Pin(上級Pin)上調用IPin::Connect()方法,用輸入Pin指針和指定的連接配接用的媒體類型作為參數;
Step 2:若輸出Pin接受連接配接,則調用輸入Pin的IPin::ReceiveConnection()方法;如果輸入Pin接受連接配接,則本次連接配接成功;
在IPin::Connect()的實作函數CBasePin::Connect中,首先檢查參數和狀态(如Pin是否已經被連結、Filter是否是停止狀态),随後檢查媒體類型,找到雙方都支援的媒體類型。檢查媒體類型調用了AgreeMediaType()函數,如果該函數指定的媒體類型非空,則針對該類型做一次嘗試,如果成功則調用AttemptConnection嘗試連接配接;如果媒體類型指針為空或對象不完整,則調用TryMedaiTypes()周遊輸入和輸出Pin上支援的媒體類型,對每一中支援的類型調用AttemptConnection()嘗試連接配接。
在AttemptConnection()中,首先會調用輸出Pin(上級Pin)的CheckConnect進行連接配接檢查(如輸入Pin是否支援特殊接口等),若失敗則BreakConnect()。成功後調用CheckMediaType()。若check成功,則講輸入Pin和媒體類型資訊儲存在輸出Pin中,随後調用ReceiveConnection()和CompleteConnection()完成連接配接。
在DirectShow中定義了Sample類,是一個封裝了一定大小資料記憶體的COM元件。互相連結的filter之間通過sample進行資料傳輸。
在傳輸過程中,兩個連結的Pin擁有同一個sample配置設定器allocator,用于建立和管理sample。傳輸時上級filter通過輸出pin的allocator得到空閑的sample及其記憶體位址,并将資料存放其中,随後将這個sample傳遞給下級filter的輸入pin。
資料傳輸的兩種主要方式:推模式和拉模式。
①推模式:常用于實時源,自身可以産生資料并通過專用資料線程将資料向下傳遞,具體方法是調用下級filter輸入Pin的IMemInputPin::Receive函數實作;
②拉模式:常用于檔案源,源filter輸出pin需實作IAsyncReader接口,由下級filter的輸入pin調用該接口的方法擷取資料。
* DirectShow需要專門的線程來傳送資料,是以至少需要兩個線程(應用程式主線程和資料線程)。
任何Filter可能分為三種狀态,即“Run”、“Stop”和“Pause”。通常情況下整個Filter Graph中的filter都處于同一狀态,那麼這個狀态也成為整個Filter Graph的狀态。
在具體實作中,每個Filter實作了IBaseFilter接口,該接口繼承自IMediaFilter接口,該接口的方法實作了Filter的狀态轉換功能。Filter Graph Manager在控制Filter Graph的運作時,通常調用其IMediaControl的Run/Pause/Stop等方法控制。在這些函數的内部,正是調用了Filter Graph内所有的filter的IMediaFilter::Run()、IMediaFilter::Pause()、IMediaFilter::Stop()實作。