DTS和PTS的分析(FFMPEG、HLS相關)

來在研究HLS(HTTP Live Streaming),以實現android上播放m3u8文件。由於TS段的切分不統一,每個視頻網站給出的m3u8 playlists總有差別,在時間戳顯示上有差異,所以對DTS和PTS進行了研究。

DTS和PTS是音視頻同步的關鍵技術,同時也是丟幀策略密切相關。


dts/pts定義 dts: decoding time stamp pts: present time stamp 

在ISO/IEC13818-1中制定90k Hz 的時鐘,如果編碼幀頻是30,那麼時間戳間隔就該是90000 / 30 = 3000。 在FFMPEG中有三種時間單位:秒、微秒和dts/pts。從dts/pts轉化爲微秒公式:



其中AV_TIME_BASE爲1,000,000,denominator爲90,000。 拿到m3u8播放列表後,首先進行解析。HTTP Live Streaming標準草案可以從這裏http://tools.ietf.org/html/draft-pantos-http-live-streaming-08查看。 解析代碼在ffmpeg/libavformat/hls.c中
  parse_playlist函數

解析播放列表的問題
   

當解析到#EXT-X-TARGETDURATION標籤時,後面緊跟着的是TS段的最大時長,當前沒有什麼用。#EXTINF標籤後緊跟的是當前TS段的時長,當EXT-X-VERSION標籤大於等於3時,TS段的時長可以爲小數,當前(2012-07-26)的FFMPEG代碼還不支持EXT-X-VERSION標籤的判斷,TS段的時長也爲整數。保存了當前段的時長,單位爲秒。
   

當前草案中還有EXT-X-DISCONTINUITY標籤,它表徵其後面的視頻段文件和之前的不連續,這意味着文件格式、時間戳順序、編碼參數等的變化。但是很遺憾,當前FFMPEG仍然不支持,這意味着該標籤出現後,後續的PES中攜帶的dts和pts將重新從零開始計數。


  seek_timestamp爲標誌位,它表徵當前視頻發生了SEEK事件,當發生SEEK事件後首先調用hls_read_seek()函數定位到應該讀取的TS段,更新HLS上下文中的段序號。當讀取到該段的packet,有兩種判斷。 在ffplay中,當外界發起seek請求後,將執行以下操作。

 

 

調用avformat_seek_file(),完成文件的seek定位
   

清空解碼前packet隊列(音頻、視頻、字幕)

 

調用avcodec_flush_buffers(),清空解碼buffer和相關狀態

 

在第一個步驟中,將在HLS層進行seek操作,seek流程圖如下圖所示:

http://image55.360doc.com/DownloadImg/2012/09/1315/26808238_1.png
http://image55.360doc.com/DownloadImg/2012/09/1315/26808238_1.png

首先讀取packet,判斷是否有seek操作,沒有則直接將該packet返回,送人後續的解碼操作。如果是seek情況,則讀取dts時間戳,如果dts沒有值,則直接清除seek標誌並返回packet(問題一)。如果dts時間戳有值,則將該值轉化爲微秒並與seek傳入的時間進行比較,看是否大於seek時間,如果大於則表明讀取的packet達到了seek要求(問題二),否則繼續讀packet。如果seek時間已經滿足,則看該packet的flags是否是關鍵幀,如果是則返回該packet(問題三),否則繼續讀packet。

該流程很簡單,但是帶來了三個問題。分別解釋

 

問題一,如果dts沒有值,返回回去後,解碼狀態全部進行了reset,則送入的第一幀信息應該爲關鍵幀,否則該幀需要參考其他幀,產生花屏。

 

問題二,如果dts時間戳有誤,將出現dts轉化爲微秒後永遠小於seek傳入時間問題,則永遠無法返回packet,導致seek僵死。

 

問題三,判斷packet是否爲關鍵幀,忽略了該packet是否爲視頻,如果該packet爲音頻並且flag AV_PKT_FLAG_KEY的結果爲真,則將返回該packet並清空seek標準。後續讀到的視頻也有非關鍵幀的可能,從而導致花屏。








發佈了28 篇原創文章 · 獲贊 5 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章