JNI——FFmpeg音視頻同步(二)

使用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的理解:

demo代碼

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,980評論 0 3
  • 本文轉自:[FFmpeg 入門(5):視頻同步 | www.samirchen.com][2] 視頻如何同步 在之...
    SamirChen閱讀 3,015評論 0 5
  • ### YUV顏色空間 視頻是由一幀一幀的數(shù)據(jù)連接而成,而一幀視頻數(shù)據(jù)其實就是一張圖片。 yuv是一種圖片儲存格式...
    天使君閱讀 3,656評論 0 4
  • ffmpeg是一個非常有用的命令行程序,它可以用來轉碼媒體文件。它是領先的多媒體框架FFmpeg的一部分,其有很多...
    城市之光閱讀 7,045評論 3 6
  • 克倫威爾(Oliver Cromwell)的一段話,“一個人,只有不知道自己的路將伸向何方的時候,他才能達到頂峰”...
    9ml葉酸閱讀 353評論 0 0

友情鏈接更多精彩內容