前言
在開發多媒體播放器或直播系統時,音視頻的同步是非常關鍵且復雜的點。要想把音視頻同步搞明白,我們必須要了解一些基本的知識。只有了解了這些基本知識,才能為你打下理解音視頻同步的基礎。 本文將從下面幾個主題介紹這些知識點:
I/B/P幀
對于 I幀,B幀,P幀,我想很多人對它們已經了解的很多了。
但在實時互動直播系統中,很少使用B幀。主要的原因是壓縮和解碼B幀時,由于要雙向參考,所以它需要緩沖更多的數據,且使用的CPU也會更高。由于實時性的要求,所以一般不使用它。不過對于播放器來說,遇到帶有B幀的H264數據是常有的事兒。
對于 H264 編碼原理相關的知識請看我的免費視頻課《移動端音視頻入門》
PTS/DTS
有了上面 I/B/P幀的概念,我們再來理解 PTS/DTS 就非常容易了。PTS( )是渲染用的時間戳,也就是說,我們的視頻幀是按照 PTS 的時間戳來展示的。DTS( )解碼時間戳,是用于視頻解碼的。
那為什么有了 PTS 還要有 DTS呢?這就與我們上面所講的 I/B/P幀有關了。如果我們的視頻中沒有B幀,那顯示的幀的順序與存放的幀的順序是一樣的,此時PTS與DTS 的值就是一樣的,也就沒有存在兩個時間戳的必要了。
但有了B幀之后,就不是這個樣子了。我們舉個簡單的例子:
第一行,實際應展示的順序:I B B P
第二行,實際在存放的順序:I P B B
第三行,按實際順序號展示:1 4 2 3
第四行,按實際順序號展示:1 2 3 4
復制
對于上面這個例子我們作下說明:
我們實際應該展示的幀的順序是 I, B, B, P 幀解碼后的視頻幀。但實際上,這些幀到達之后,在緩沖區里就按照第二行的樣子存放的。為什么會這樣呢?這是由于我上面所講的,P幀參考的是 I幀,B幀是雙向參考幀。也就是說,如果 I幀和P幀沒有解碼的話,B幀是無法進行解碼的。基于此,為了解決這個問題就出現了 PTS和DTS兩個時間戳。第三行是視頻幀真正的解碼順序,先解 I幀,然后是P幀,然后是第一個B幀,最后是第二個B幀。最終的展示順序是 I幀解碼后的視頻幀,第一個B幀解碼后的視頻幀,第二個B幀解碼后的視頻幀,最后是P幀解碼后的視頻帖。時間基
有了時間戳之后,最終進行展示時還要需要將 PTS時間戳轉成以秒為單位的時間。那這里需要向大家介紹一下 的時間基。
我們在執行 /命令時ffmpeg中時間戳同步,可以通過控制臺看到幾個參數,分別是 tbr, tbn, tbc。這幾個值是什么含義呢?其實就是不同的時間基。
在中,不同的時間戳對應不同的時間基。對于視頻的渲染我們使用的是視頻流的時間基,也就是 tbn。那我們如何理解時間基呢?其實非常簡單,就是時間刻度。我們以幀率為例,如果每秒鐘的幀率是 25幀,那么它的時間基(時間刻度)就是 1/25。也就是說每隔1/25 秒后,顯示一幀。
所以如我們當前的時間是 100, 時間基是 1/25,那么轉成秒的時間是多少呢? 100*(1/時間基)ffmpeg中時間戳同步,也就是100 * 1/25 = 4秒。是不是非常的簡單?
內部時間基
除了我上面所講的幾個時間基之外,內部還有一個時間基。即我們通過所見到的 。它在內部定義如下:
#define AV_TIME_BASE 1000000
復制
它還有一種分數所表式法:
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
復制
在 中進行換算,將不同時間基的值轉成按秒為單位的值計算如下:
timestamp(秒) = pts * av_q2d(time_base)
復制
這里引入了 這個函數,它的定義非常簡單:
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;
}
復制
從這里我們可以看到,它與我上面所講的公式是一樣的。
不同時間基的換算
在上面我向大家介紹了 有好幾種不同的時間基,有時候我們需要在不同的時間基之間做換算。為我們提供了非常方便的函數。即
av_rescale_q()
復制
(a,b,c)的作用是,把時間戳從一個時基調整到另外一個時基時候用的函數。其中,a 表式要換算的值;b 表式原來的時間基;c表式要轉換的時間基。其計算公式為 a * b / c。
既然公式這么簡單,我們自己寫就OK了,為什么還要單獨提供一個函數呢?其實這個看似簡單的方法,還要考慮數值溢出的問題。所以把這塊的邏輯加上之后,就沒我們看到的這么簡單了。不過沒關系,我們只要清楚 是做什么的,怎么用就可以了。
下面我再給出兩個算計公式:
小結
以上我通過幾個主題向大家介紹了中的時間戳與時間基,以及音視頻同步的基本知識。通過本文大家會了解到,其實中的時間戳與時間基并不復雜。但就是這些不復雜的知識點的交互最終完成了音視頻的同步。