PTS/DTS(時間戳)
要想解決時間同步問題就必須要了解ffmpeg中的PTS和DTS到底是什么
-
PTS:
PTS(Presentation TimeStamp)是渲染用的時間戳,播放器會根據這個時間戳進行渲染播放
-
DTS:
DTS(Decoding TimeStamp)解碼時間戳,在視頻packet進行解碼成frame的時候會使用到
-
有了PTS為什么還需要DTS
就拿編碼H264來說,H264編碼分為I幀,B幀,P幀,I幀是關鍵幀,也就是一個GOP的最開始幀,B幀是前后參考幀,它屬於幀間壓縮技術,B幀會通過記錄前后兩幀進行壓縮,P幀是向前參考幀,比B幀的壓縮率要低
因為B幀要參考前后幀,那么在編碼之后的幀的時間順序就會發生變化,所以在沒有B幀的時候PTS和DTS應該是一樣的,有了B幀之后PTS和DTS也就會發生變化
時間基
有了時間戳之后,還需要將PTS的時間戳轉成以秒為單位的時間。這里就需要用到ffmpeg的時間基來進行計算了
先了解一下tbr,tbn,tbc
- tbr: 是通常說的幀率
- tbn: 視頻流的時間基
- tbc: 時間解碼的時間基
在ffmpeg中,不同的時間戳對應不同的時間基。一般在視頻進行渲染的時候渲染的時候用到的就是視頻流的時間基tbn,視頻流的時間基和幀率有關,每秒30幀,代表一幀需要1/30秒
-
ffmpeg內部有自己的時間基,分別定義了
// ffmpeg中內部的時間基 #define AV_TIME_BASE 1000000 // ffmpeg中分數所表示法 #define AV_TIME_BASE_Q (AVRatonal){1, AV_TIME_BASE}
-
av_q2d,計算真實秒數
// ffmpeg 中進行轉換,將時間轉成秒,av_q2d可以將時間基轉換成double類型小數 typedef struct AVRational{ int num; //numerator int den; //denominator } AVRational; static inline double av_q2d(AVRational a){ /** * Convert rational to double. * @param a rational to convert **/ return a.num / (double) a.den; } // 通過pts*時間基的小數可以算出當前的流的秒數 AVRational time_base = {1, 30}; double time_sec = pts * av_q2d(time_base)
-
av_rescale_q(),不同的時間基直接的轉換
/** * Rescale a 64-bit integer by 2 rational numbers. * * The operation is mathematically equivalent to `a * bq / cq`. * * This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF. * * @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd() */ int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; /* @param a : 需要進行轉換的時間戳 @bq : 對應轉換的時間戳的原來的時間基 @cq : 轉換之后的時間基 */
總結
通過ffmpeg的時間戳和時間基的使用,可以有效的解決音視頻的同步的問題