使用OpenSL_ES播放聲音

之前的播放聲音是轉碼得到數(shù)據(jù)后主動放進AudioTrack進行播放,OpenSL就屬于被動了,播放器開始播放先從緩沖區(qū)取數(shù)據(jù),播放完了調用回調方法再去獲取數(shù)據(jù)。
OpenSL_ES 跟JNI里的env 很類似,通過結構體實現(xiàn)對象的概念。
OpenSL ES的開發(fā)流程主要有如下6個步驟:
? ? ? ? 1、創(chuàng)建引擎對象
? ? ? ? 2、創(chuàng)建播放器(錄音器)
? ? ? ? 3、設置緩沖隊列和回調函數(shù)
? ? ? ? 4、設置播放狀態(tài)
? ? ? ? 5、啟動回調函數(shù)
? ? ? ? 其中創(chuàng)建播放器有需要設置混音器
? ? ? ? 其中3和4是播放PCM等數(shù)據(jù)格式的音頻是需要用到的。
創(chuàng)建OpenSL_ES 對象有個生命周期的概念。
創(chuàng)建成功后,都進入 SL_OBJECT_STATE_UNREALIZED 狀態(tài),這種狀態(tài)下,系統(tǒng)不會為它分配任何資源,直到調用 Realize 函數(shù)為止。
Realize 后的對象,就會進入 SL_OBJECT_STATE_REALIZED 狀態(tài),這是一種“可用”的狀態(tài),只有在這種狀態(tài)下,對象的各個功能和資源才能正常地訪問。
當調用對象的 Destroy 函數(shù)后,則會釋放資源,并回到 SL_OBJECT_STATE_UNREALIZED 狀態(tài)。

播放pcm:
第一步:創(chuàng)建播放引擎

第二步:創(chuàng)建播放器
創(chuàng)建播放器參數(shù)

channel可以設置為2。
創(chuàng)建播放器需要設置混音器

其他兩個參數(shù)

真的要創(chuàng)建播放器了

第三步:設置緩沖隊列和回調函數(shù)


第四步:設置播放狀態(tài)

可以初始化音量控制對象,調節(jié)聲音大小。
第五步:啟動回調函數(shù)

播放URI

跟上面的差不多,就是設置SLDataSource這個參數(shù)的時候不一樣,還不用調用回調方法。
音視頻同步:
av_samples_get_buffer_size()可以得到一幀視頻的大小size,采樣率為什么44100,1秒的數(shù)據(jù)大小為44100*2*2(雙通道16位),一幀的音頻播放時間為size除以44100*2*2。
音視頻的同步不是絕對的同步,以音頻播放時間為基準(因為人對視頻的感知比音頻弱),視頻或快或慢來同步,用音頻幀播放時間減去視頻幀播放時間大于某個值,就任務產生延遲了,視頻播放通過USleep()來調整視頻幀的播放速度達到同步效果。
在視音頻流中的包中都含有DTS和PTS。DTS,Decoding Time Stamp,解碼時間戳,告訴解碼器packet的解碼順序;PTS,Presentation Time Stamp,顯示時間戳,指示從packet中解碼出來的數(shù)據(jù)的顯示順序。
視頻的編碼要比音頻復雜一些,特別的是預測編碼是視頻編碼的基本工具,這就會造成視頻的DTS和PTS的不同。這樣視頻編碼后會有三種不同類型的幀:
?????????I幀 關鍵幀,包含了一幀的完整數(shù)據(jù),解碼時只需要本幀的數(shù)據(jù),不需要 ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 參考其他幀。
????????P幀 P是向前搜索,該幀的數(shù)據(jù)不完全的,解碼時需要參考其前一幀的數(shù) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 據(jù)。
????????B幀 B是雙向搜索,解碼這種類型的幀是最復雜,不但需要參考其一幀的 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 數(shù)據(jù),還需要其后一幀的數(shù)據(jù)。
I幀的解碼是最簡單的,只需要本幀的數(shù)據(jù);P幀也不是很復雜,值需要緩存上一幀的數(shù)據(jù)即可,總體來說都是線性,其解碼順序和顯示順序是一致的。B幀就比較復雜了,需要前后兩幀的順序,并且不是線性的,也是造成了DTS和PTS的不同的“元兇”,也是在解碼后有可能得不到完整Frame的原因
假如一個視頻序列,要這樣顯示I B B P,但是需要在B幀之前得到P幀的信息,因此幀可能以這樣的順序來存儲I P B B,這樣其解碼順序和顯示的順序就不同了,這也是DTS和PTS同時存在的原因。DTS指示解碼順序,PTS指示顯示順序。
在計算某一幀的顯示時間之前,現(xiàn)來弄清楚FFmpeg中的時間單位:時間基(TIME BASE)。在FFmpeg中存在這多個不同的時間基,對應著視頻處理的不同的階段(分布于不同的結構體中)。在本文中使用的是AVStream的時間基,來指示Frame顯示時的時間戳(timestamp)。
1、解碼視頻

2、計算當前幀播放的延遲時間延遲并不斷糾正

3、拿到視頻顯示時間和音頻的播放時間進行比較,然后控制視頻的延遲時間

4、得到正確的視頻幀延遲時間,最后繪制

對于actual_delay的理解:
