狂野欧美性色xo影院_高清国产美女毛片在线_娇小性色xxxxx中文_色综合久久久久久888

行業新聞

致力于廣播設備的創新與產品服務

淺析DirectShow音視頻同步解決完整方案

2013年01月06日未知瀏覽量:0

多媒體處理,不可避免地要解決音視頻的同步問題。DirectShow是怎么來實現的呢?我們一起來學習一下。

  大家知道,DirectShow結構最核心的部分是Filter Graph Manager:向下控制Graph中的所有Filter,向上對τ貿絳蛺峁┍喑探涌凇F渲校現ilter Graph Manager實現的很重要一個功能,就是同步音視頻的處理。簡單地說,就是選一個公共的參考時鐘,并且要求給每個Sample都打上時間戳,Video Renderer或Audio Renderer根據Sample的時間戳來控制播放。如果到達Renderer的Sample晚了,則加快Sample的播放;如果早了,則Renderer等待,一直到Sample時間戳的開始時間再開始播放。這個控制過程還引入一個叫Quality Control的反饋機制。

  下面,我們來看一下參考時鐘(Reference Clock)。所有Filter都參照于同一個時鐘,才能統一步調。DirectShow引入了兩種時鐘時間:Reference time和Stream time。前者是從參考時鐘返回的絕對時間(IReferenceClock::GetTime),數值本身的意義取決于參考時鐘的內部實現,利用價值不大;后者是兩次從參考時鐘讀取的數值的差值,實際應用于Filter Graph內部的同步。Stream time在Filter Graph不同狀態的取值為:

  1. Filter Graph運行時,取值為當前參考時鐘時間減去Filter Graph啟動時的時間(啟動時間是通過調用Filter上的IMediaFilter::Run來設置的);

  2. Filter Graph暫停時,保持為暫停那一刻的Stream time;

  3. 執行完一次Seek操作后,復位至零;

  4. Filter Graph停止時,取值不確定。

  那么,參考時鐘究竟是什么東西呢?其實,它只是一個實現了IReferenceClock接口的對象。也就是說,任何一個實現了IReferenceClock接口的對象都可以成為參考時鐘。在Filter Graph中,這個對象一般就是一個Filter。(在GraphEdit中,實現了參考時鐘的Filter上會顯示一個時鐘的圖標;如果同一個Graph中有多個Fiter實現了參考時鐘,當前被Filter Graph Manager使用的那個會高亮度顯示。)而且大多數情況下,參考時鐘是由Audio Renderer這個Filter提供的,因為聲卡上本身帶有了硬件定時器資源。接下來的問題是,如果Filter Graph中有多個對象實現了IReferenceClock接口,Filter Graph Manager是如何做出選擇的呢?默認的算法如下:

  1. 如果應用程序設置了一個參考時鐘,則直接使用這個參考時鐘。(應用程序通過IMediaFilter:: SetSyncSource設置參考時鐘,參數即為參考時鐘;如果參數值為NULL,表示Filter Graph不使用參考時鐘,以最快的速度處理Sample;可以調用IFilterGraph:: SetDefaultSyncSource來恢復Filter Graph Manager默認的參考時鐘。值得注意的是,這時候的IMediaFilter接口應該從Filter Graph Manager上獲得,而不是枚舉Graph中所有的Filter并分別調用Filter上的這個接口方法。)

  2. 如果Graph中有支持IReferenceClock接口的Live Source,則選擇這個Live Source。

  3. 如果Graph中沒有Live Source,則從Renderer依次往上選擇一個實現IReferenceClock接口的Filter。如果連接著的Filter都不能提供參考時鐘,則再從沒有連接的Filter中選擇。這一步算法中還有一個優先情況,就是如果Filter Graph中含有一個Audio Render的鏈路,則直接選擇Audio Renderer這個Filter(原因上面已經提及)。

  4. 如果以上方法都找不到一個適合的Filter,則選取系統參考時鐘。(System Reference Clock,通過CoCreateInstance創建,CLSID為CLSID_SystemClock。)

  我們再來看一下Sample的時間戳(Time Stamp)。需要注意的是,每個Sample上可以設置兩種時間戳:IMediaSample::SetTime和IMediaSample::SetMediaTime。我們通常講到時間戳,一般是指前者,它又叫Presentation time,Renderer正是根據這個時間戳來控制播放;而后者對于Filter來說不是必須的,Media time有沒有用取決于你的實現,比如你給每個發出去的Sample依次打上遞增的序號,在后面的Filter接收時就可以判斷傳輸的過程中是否有Sample丟失。我們再看一下IMediaSample::SetTime的參數,兩個參數類型都是REFERENCE_TIME,千萬不要誤解這里的時間是Reference time,其實它們用的是Stream time。還有一點,就是并不是所有的Sample都要求打上時間戳。對于一些壓縮數據,時間戳是很難打的,而且意義也不是很大(不過壓縮數據經過Decoder出來之后到達Renderer之前,一般都會打好時間戳了)。時間戳包括兩個時間,開始時間和結束時間。當Renderer接收到一個Sample時,一般會將Sample的開始時間和當前的Stream time作比較,如果Sample來晚了或者沒有時間戳,則馬上播放這個Sample;如果Sample來得早了,則通過調用參考時鐘的IReferenceClock::AdviseTime等待Sample的開始時間到達后再將這個Sample播放。Sample上的時間戳一般由Source Filter或Parser Filter來設置,設置的方法有如下幾種情況:

  1. 文件回放(File playback):第一個Sample的時間戳從0開始打起,后面Sample的時間戳根據Sample有效數據的長度和回放速率來定。

  2. 音視頻捕捉(Video and audio capture):原則上,采集到的每一個Sample的開始時間都打上采集時刻的Stream time。對于視頻幀,Preview pin出來的Sample是個例外,因為如果按上述方法打時間戳的話,每個Sample通過Filter鏈路傳輸,最后到達Video Renderer的時候都將是遲到的;Video Renderer通過Quality Control反饋給Source Filter,會導致Source Filter丟幀。所以,Preview pin出來的Sample都不打時間戳。對于音頻采集,需要注意的是,Audio Capture Filter與聲卡驅動程序兩者各自使用了不同的緩存,采集的數據是定時從驅動程序緩存拷貝到Filter的緩存的,這里面有一定時間的消耗。

  3. 合成(Mux Filters):取決于Mux后輸出的數據類型,可以打時間戳,也可以不打時間戳。

  大家可以看到,Sample的時間戳對于保證音視頻同步是很重要的。Video Renderer和Audio Renderer作為音視頻同步的最終執行者,需要做很多工作。我們或許要開發其它各種類型的Filter,但一般這兩個Filter是不用再開發的。一是因為Renderer Filter本身的復雜性,二是因為微軟會對這兩個Filter不斷升級,集成DirectX中其它模塊的最新技術(如DirectSound、DirectDraw、Direct3D等)。

  最后,我們再來仔細看一下Live Source的情況。Live Source又叫Push source,包括Video /Audio Capture Filter、網絡廣播接收器等。Filter Graph Manager是如何知道一個Filter是Live Source的呢?通過如下任何一個條件判斷:

  1. 調用Filter上的IAMFilterMiscFlags::GetMiscFlags返回有AM_FILTER_MISC_FLAGS_IS_SOURCE標記,并且至少有一個Output pin實現了IAMPushSource接口。

  2. Filter實現了IKsPropertySet接口,并且有一個Capture output pin(Pin的類型為PIN_CATEGORY_CAPTURE)。

  Live Source對于音視頻同步的影響主要是以下兩個方面:Latency和Rate Matching。Latency是指Filter處理一個Sample花費的時間,對于Live Source來說,主要取決于使用緩存的大小,比如采集30fps的視頻一般采集完一幀后才將數據以一個Sample發送出去,則這個Filter的Latency為33ms,而Audio一般緩存500ms后才發送一個Sample,則它的Latency就為500ms。這樣的話,Audio與Video到達Renderer就會偏差470ms,造成音視頻的不同步。默認情況下,Filter Graph Manager是不會對這種情況進行調整的。當然,應用程序可以通過IAMPushSource接口來進行Latency的補償,方法是調用IAMGraphStreams::SyncUsingStreamOffset函數。Filter Graph Manager的實現如下:對所有實現IAMPushSource接口的Filter調用IAMLatency::GetLatency得到各個Source的Latency值,記下所有Latency值中的最大值,然后調用IAMPushSource::SetStreamOffset對各個Source設置偏移值。

  這樣,在Source Filter產生Sample時,打的時間戳就會加上這個偏移量。Rate Matching問題的引入,主要是由于Renderer Filter和Source Filter使用的是不同的參考時鐘。這種情況下,Renderer對數據的播放要么太快,要么太慢。另外,一般Live Source不能控制輸出數據的速率,所以必須在Renderer上進行播放速率的匹配。因為人的聽覺敏感度要大于視覺敏感度,所以微軟目前只在Audio Renderer上實現了Rate Matching。實現Rate Matching的算法是比較復雜的,這里就不再贅述。

  看到這里,大家應該對DirectShow是如何解決音視頻同步問題的方案有一點眉目了吧。深層次的研究,還需要更多的測試、Base class源碼閱讀,以及DirectShow相關控制機制的理解,比如Quality Control Management等。

海峽廣播電視設備工程有限公司地址:福建省福州市鼓樓區軟件大道89號福州軟件園A區28號樓五層

Copyright ? 1999-2024All Rights Reserved閩ICP備12023208號