摘要:本篇文件中主要講述了graph圖表中資料流是如何傳遞的,如果你是做directshow的應用開發也許對於這些細節並不需要了解,如果你要開發自己的filter,就很有必要了解這些細節。
directshow資料流動概述
filter之間的資料是通過sample來傳送的。sample是乙個com元件,擁有自己的一段資料緩衝buffer,這個com元件暴露了imediasample介面。這個sample一般都有乙個叫做記憶體分配器(alloctor)的com物件來建立管理,這個物件具有imemallocator介面。如下圖所示:
圖1
兩個filter之間的連線都要指定乙個allocator,有時也有幾個filter連線同用乙個allocator。每乙個allocator都要建立乙個media sample池,並且給每乙個sample分配乙個記憶體buffer。每當乙個filter需要乙個buffer來填充資料,它就通過allocator的函式imemallocator::getbuffer.來獲得乙個sample。如果分配器allocator正好有空閒的sample,getbuffer立即返回乙個指向該sample的指標。如果沒有空閒的sample,該方法就阻塞,直到有乙個sample可用為止。當該函式返回乙個sample時,filter就將資料填充到buffer裡,設定好標識,然後就將sample傳遞給下乙個filter。
圖2
下面描述了在流中只有乙個allocator的情景,實際上,在每條資料流中總是有好幾個allocator,當乙個sample被釋放的時候,也許此時有好幾個allocator都在等著該sample,這就有新的問題了,也許有的alloctor永遠都不能被分配sample,陷入互鎖狀態。下面的圖就演示了這種情形,decoder有資料需要壓縮,因此它在等待renderer釋放sample,但是,parser也在請求sample,它在等待decoder釋放sample。
圖3
傳輸(transports)
為了在過濾器圖表中傳送**資料,directshow過濾器需要支援一些協議,稱之為傳輸協議(transport)。相連的過濾器必須支援同樣的傳輸協議,否則不能交換**資料。
大多數的directshow過濾器把**資料儲存在主儲存器中,並通過引腳把資料提交給其它的過濾器,這種傳輸稱為區域性儲存器傳輸(local memory transport)。雖然區域性儲存器傳輸在directshow中最常用,但並不是所有的過濾器都使用它。例如,有些過濾器通過硬體傳送**資料,引腳只是用來提交控制資訊,如ioverlay介面。
directshow為區域性儲存器傳輸定義了兩種機制:推模式(push model)和拉模式(pull model)。在推模式中,源過濾器生成資料並提交給下一級過濾器。下一級過濾器被動的接收資料,完成處理後再傳送給再下一級過濾器。在拉模式中,源過濾器與乙個render過濾器相連。render過濾器向源過濾器請求資料後,源過濾器才傳送資料以響應請求。推模式使用的是imeminputpin介面,拉模式使用iasyncreader介面,推模式比拉模式要更常用。
samples和allocators
當乙個pin向另乙個pin傳遞資料的時候,它並不是直接將記憶體塊的指標傳遞下乙個pin,實際上,它將傳遞乙個管理記憶體的com物件的指標給下乙個pin。這個com物件稱為media sample。暴露了imediasample介面。接收pin通過呼叫imediasample的方法來對記憶體進行操作,比如方法imediasample::getsize, imediasample::getactualdatalength以及imediasample::getpointer。
sample一般都是從源filter開始,通過輸出pin傳遞到下乙個filter的輸入pin,一路傳遞下去一直到render filter。在拉模式中,輸出pin通過呼叫輸入pin上的imeminputpin::receive方法傳遞sample,輸入pin或者在receive函式同步處理資料,或者另外採用乙個工作執行緒非同步出來的方式。如果在recive方法中需要等待資源的話,也可以阻塞。
另外乙個com物件,叫做allocator,用來建立和管理sample的。暴露了imemallocator介面。當乙個filter需要乙個空的buffer的時候,就可以呼叫imemallocator::getbuffer,該方法返回乙個指向sample的指標。每乙個pin連線都共享乙個allocator,當兩個pin連線的時候,他們會決定由哪個filter來提供allocator,通過pin還可以設定allocator的屬性,例如,buffer的數量和大小。
下面的圖表顯示了allocator,sample和filter之間的關係。
圖4
media sample引用計數
allocator建立了乙個sample池。因此 ,當某個filter呼叫getbuffer函式時,一些sample被使用,其他空閒的sample可以響應。allocator通過引用計數來跟蹤samples。filter呼叫getbuffer返回的sample的引用計數是1。當sample的引用計數為0時,sample就返回記憶體池,成為空閒的sample,可以再次響應getbuffer的呼叫。如果所有的sample都處於繁忙狀態,getbuffer就會阻塞,直到有乙個sample空閒。
例如,假設乙個輸入pin接到乙個sample,如果它在receive方法裡同步的處理這個sample,沒有增加該sample的引用計數,等到receive返回後,輸出pin就釋放這個sample,引用計數為0,sample就返回到記憶體池中。如果輸入pin的執行緒還要處理該sample,引用計數增加1,成為2,輸出pin返回,釋放,計數成1。
當乙個輸入pin接收乙個sample時,它可以將資料複製到另乙個sample中,也可以將這個sample傳遞到下乙個filter。乙個sample可以流遍整個filter graph。不過引用計數要保持大於0。 當乙個輸出pin呼叫了release以後,就不應該再次使用該sample,因為也許下游還有filter正在使用該sample。輸出pin必須呼叫getbuffer獲取新的sample。
這種機制減少 了記憶體分配的,因為buffer可以重用。也防止了資料沒有被處理的sample被重新寫入。
當乙個filter建立乙個allocator的時候,allocator還沒有保留任何的記憶體,如果這個時候有人getbuffer,就會失敗。只有當資料流開始的時候,輸出pin呼叫imemallocator::commit,提交allocator,現在才能分配記憶體。
當資料流停止的時候,pin就呼叫imemallocator::decommit,來銷毀allocator。在allocator再次committ之前,所有呼叫getbuffer方法都會失敗。當然,如果有乙個getbuffer阻塞呼叫在等待sample的時候,遇到decommit方法,會立即返回乙個錯誤碼。
filter的狀態
filter有三種狀態,停止,暫停,執行。
過濾器圖表管理器 控制著filter的所有狀態的轉換。當應用程式呼叫imediacontrol::run, imediacontrol::pause, or imediacontrol::stop時, 過濾器圖表管理器就呼叫filter相應的imediafilter方法。停止,執行狀態的切換總是要經過暫停,因此,當乙個應用程式對乙個停止的graph 呼叫run命令時,過濾器圖表管理器 在run之前首先要暫停。
對於大多數的filter來說,running和paused狀態是一樣的。看下面的graph source > transform > renderer
當乙個filter停止時,它拒絕傳送給它的任何samples,源filter關閉他們的stream執行緒,其他filter也關閉他們建立的其他執行緒,pin decommit他們的記憶體分配器。
過濾器圖表管理器按照逆流的方向來切換filter的狀態,從renderer filter到源filter,這種方式可以防止死鎖。最關鍵的狀態切換是暫停和停止之間。
從停止到暫停,當filter暫停時,它就做好了接收sample的準備,源filter是最後乙個切換到暫停的。它開始建立streaming執行緒,傳送sample,因為下游的filter的狀態都已經切換到暫停了,所以,所有的filter都可以接收sample。只有當所有的flter都接收到sample,過濾器圖表管理器才算完成了狀態的切換
從暫停到停止。當乙個filter停止時,它要釋放它擁有的所有的samples。當圖表管理器試圖停掉上游的乙個filter時,這個filter不會阻塞在getbuffer和receive方法裡,它會立即響應stop命令。上游的filter也許在執行stop命令前還會講少量的sample傳遞下去,但是下游的filter會拒絕的,因為他們已經停止了。
DirectShow開發快速入門之二資料流的流動
directshow資料流動概述 filter之間的資料是通過sample來傳送的。sample是乙個com元件,擁有自己的一段資料緩衝buffer,這個com元件暴露了imediasample介面。這個sample一般都有乙個叫做記憶體分配器 alloctor 的com物件來建立管理,這個物件具有...
DirectShow開發快速入門之事件通知機制
摘要 這篇文件描述directshow中事件產生的機制,以及應用程式是如何處理事件的。概述 事件是graph圖和應用程式之間互相通訊的機制,類似於訊息機制。當某個事件發生時,比如資料流結束,產生乙個錯誤等,filter就要給filter圖表管理器 graph manager 傳送乙個事件通知。fil...
DirectShow開發快速入門之慨述(三)
4 samples和allocators filters通過pin的連線來傳遞資料,資料流是從乙個filter的輸出pin流向相連的filter的輸入pin。輸出pin常用的傳遞資料的方式是呼叫輸入pin上的imeminputpin receive方法。對於filter來說,可以有好幾種方式來分配 ...