Android PVPlayer播放引擎在渲染(Render)多媒體數(shù)據(jù)時(shí)需要保持一個(gè)暫時(shí)的同步,也就是通常所說的 A/V 同步。為了達(dá)到A/V同步,需要如下信息:媒體回放的時(shí)鐘、媒體數(shù)據(jù)的時(shí)間戳、從 Sink 中獲取的時(shí)間信息(比如從音頻設(shè)備設(shè)定的特定的采樣率來獲取的播放速率)等。
1.媒體時(shí)鐘
PVMFMediaClock,媒體時(shí)鐘主要負(fù)責(zé)維持一個(gè)時(shí)間的引用,從而保持媒體回放的節(jié)奏,獲取和實(shí)現(xiàn)媒體播放的同步。
1)時(shí)間源
媒體時(shí)鐘可以作為一個(gè)時(shí)間源提供給多媒體,它本身可能來自于系統(tǒng)時(shí)鐘或其他時(shí)間源(如音頻設(shè)備時(shí)鐘)。它可以給多媒體提供一個(gè)時(shí)間基準(zhǔn),同時(shí)來維護(hù)該時(shí)間基準(zhǔn)。
2)時(shí)鐘觀察者
媒體時(shí)鐘可以把自己作為一個(gè)觀察者,來通知對(duì)象時(shí)鐘狀態(tài)的改變。以下接口實(shí)現(xiàn)了其作為觀察者的角色。
PVMFMediaClockObserver:用來通知時(shí)鐘基值,時(shí)鐘計(jì)數(shù)的更新,時(shí)鐘的調(diào)整。
PVMFMediaClockStateObserver:用來通知時(shí)鐘狀態(tài)的改變。
PVMFMediaClockNotificationsObs:用來獲取回調(diào)通知。
3)NPT 映射
媒體時(shí)鐘是一個(gè)單調(diào)遞增的時(shí)鐘,而媒體在播放時(shí)卻可能需要定位(Seek)到任意位置。為了控制媒體的播放,使其正確渲染 ,媒體時(shí)鐘需要在媒體時(shí)鐘時(shí)間和 NPT 之間維護(hù)一個(gè) NPT ( Normal Play Time )映射,任意對(duì)媒體播放位置的改變將會(huì)通知進(jìn)行一次映射。
媒體時(shí)鐘和NPT 之間的映射公式為:NPT=(media_time-5550+380) 。
4)時(shí)鐘的回調(diào)
在媒體時(shí)鐘上設(shè)置回調(diào)是組件采取動(dòng)作的基礎(chǔ),這些回調(diào)可以減少在時(shí)鐘發(fā)生改變時(shí),組件自己需要設(shè)置它們的時(shí)鐘的時(shí)間。媒體時(shí)鐘采用輸入特定時(shí)間窗口來取代絕對(duì)時(shí)間,這樣可以使處于競(jìng)爭(zhēng)狀態(tài)的任務(wù)或線程盡可能早的得到響應(yīng)。
5)延遲處理
當(dāng)集成了多個(gè)不同媒體流的數(shù)據(jù)槽同時(shí)輸出時(shí),每個(gè)槽都可能會(huì)有不同程度的延遲,為了彌補(bǔ)不同媒體流之間的延遲從而同步播放,就需要進(jìn)行延遲處理。每個(gè) Sink 都向媒體時(shí)鐘注冊(cè)自己的延遲,后由媒體時(shí)鐘來調(diào)整終調(diào)度的延遲。
6)NPT 時(shí)鐘轉(zhuǎn)換
當(dāng)一個(gè)新的 NPT 開始時(shí),用戶可以給媒體時(shí)間設(shè)置一個(gè)絕對(duì)時(shí)間。用戶還可以任意調(diào)整 NPT的方向(如向前、向后)。
2.時(shí)間戳
為了及時(shí),準(zhǔn)確地輸出媒體數(shù)據(jù),就不得不考慮媒體數(shù)據(jù)中包含的時(shí)間戳信息,以及媒體回放時(shí)鐘。如果時(shí)間戳值等于當(dāng)前回放時(shí)間,則媒體數(shù)據(jù)是同步的,需要進(jìn)行渲染 ;如果時(shí)間戳小于當(dāng)前回放時(shí)間,則說明媒體數(shù)據(jù)到達(dá)時(shí)間晚了;反之,如果時(shí)間戳大于當(dāng)前回放時(shí)間,則說明媒體數(shù)據(jù)到達(dá)時(shí)間早了。如何處理這些來早的或來晚的媒體數(shù)據(jù)則取決于 PVPlayer 引擎的配置。在通常情況下,來早的數(shù)據(jù)需要等待,直到播放時(shí)間到達(dá);來晚的數(shù)據(jù)則會(huì)被丟棄而不被渲染,但有時(shí)候來晚的數(shù)據(jù)也會(huì)被渲染 。
3.同步音頻
音頻數(shù)據(jù)的渲染通常不需要外部時(shí)鐘來進(jìn)行同步,因?yàn)橐纛l設(shè)備通常會(huì)被配置一定的采樣率來消化音頻數(shù)據(jù)。因此,音頻設(shè)備被配置的這個(gè)采樣率通常也作為媒體回放時(shí)鐘的速率。
1)渲染開始時(shí)的同步
一旦媒體時(shí)鐘開始后,就必須要求媒體數(shù)據(jù)盡可能快地被渲染,然而硬件在渲染時(shí)很可能需要額外的時(shí)間,或者硬件需要等到更多的媒體數(shù)據(jù)被緩存。因此會(huì)導(dǎo)致媒體時(shí)鐘的開始時(shí)間與媒體數(shù)據(jù)真正被輸出的時(shí)間不一致,從而導(dǎo)致播放引擎報(bào)告給應(yīng)用程序的播放進(jìn)度與真實(shí)播放進(jìn)度產(chǎn)生誤差。為了解決這一問題,在硬件沒有開始輸出媒體數(shù)據(jù)時(shí),將媒體時(shí)鐘設(shè)置暫停狀態(tài),當(dāng)硬件開始輸出媒體數(shù)據(jù)時(shí),給媒體時(shí)鐘發(fā)一個(gè)消息來通知媒體時(shí)鐘也開始運(yùn)行。這樣就可以保證在媒體時(shí)鐘開始的時(shí)候,媒體數(shù)據(jù)也開始進(jìn)行輸出。
作為一個(gè)主動(dòng)態(tài)的 MIO 組件,無論時(shí)鐘狀態(tài)為暫停還是運(yùn)行,播放引擎都向 MIO 組件傳送數(shù)據(jù),而 MIO 組件也應(yīng)該繼續(xù)接受和緩存數(shù)據(jù),并決定何時(shí)把數(shù)據(jù)發(fā)送到硬件。
而作為一個(gè)被動(dòng)態(tài)的 MIO 組件,只有當(dāng)時(shí)鐘狀態(tài)為運(yùn)行時(shí),播放引擎才向 MIO 組件發(fā)送數(shù)據(jù),而接收到數(shù)據(jù)的 MIO 組件也需要將收到的數(shù)據(jù)立即發(fā)送給硬件。
2)重新定位后的同步
當(dāng)應(yīng)用程序請(qǐng)求重新定位媒體播放位置時(shí),MIO組件和硬件緩存的數(shù)據(jù)需要被立即釋放,并且在新的位置開始播放。
3)播放中的同步
盡管硬件消費(fèi)數(shù)據(jù)的速率應(yīng)該與媒體時(shí)鐘的速率是一致的,但他們畢竟是單獨(dú)運(yùn)行的,因此不可避免會(huì)有一些不同。在通常情況下,這中間的差距會(huì)很小,然而隨著播放的進(jìn)行,差距將會(huì)被積累,終導(dǎo)致不同步。
因此,為了控制短時(shí)間內(nèi)播放時(shí)鐘與音頻輸出進(jìn)程差距在很小的范圍內(nèi),需要不時(shí)地調(diào)整兩者之間的差,使之小于一個(gè)特定的閾值。
4.同步視頻
與音頻輸出相比,視頻的輸出需要參考一個(gè)時(shí)鐘來決定何時(shí)輸出一個(gè)特定的視頻幀,視頻幀的輸出要盡可能與該幀的時(shí)間戳保持一致。 播放引擎維護(hù)了一個(gè)與音頻播放同步的播放時(shí)鐘,因此一旦視頻輸出與播放時(shí)鐘同步,那么也就意味著視頻輸出與音頻輸出同步。
5.音視頻同步
音視頻同步是音頻同步和視頻同步的終極目標(biāo)。在播放引擎架構(gòu)中,媒體時(shí)鐘需要調(diào)整以便與音頻輸出過程相一致,而對(duì)于視頻輸出來說,在輸出一個(gè)視頻幀時(shí),應(yīng)使該幀的時(shí)間戳與媒體時(shí)鐘同步。因此音頻輸出設(shè)備、視頻幀的時(shí)間戳與媒體時(shí)鐘的結(jié)合便構(gòu)成了A/V同步。