ffmpeg之ffplay音視頻同步原理

首先看一些碎知識點

pts和dts:

    pts是錄製時產生的時間戳,即顯示時間戳,表示這幀數據啥時候播放

    dts解碼時間戳,音視頻同步時一般來說不用關注

音視頻同步三種方法:

1、以音頻爲基準

     視頻慢了加快或者丟幀

     快了則放慢播放

     音頻丟幀時ffplay會丟視頻幀

2、以視頻爲基準

     音頻慢了加快或者丟幀

     快了則放慢播放

     視頻丟幀時音頻應該加快播放比丟幀效果更好一點

3、以外部時鐘爲基準

     根據外部始終改變播放速度

ffmpeg時間定義:

標準時間 :秒、微秒

自定義時間單位 :a/b秒

aac:pts以1/採樣率爲單位,1024個採樣點爲一幀,每個採樣點時間是1/44100

第一幀0

第二幀1024*一個採樣點時間

第三幀2048*一個採樣點

pts1=0

pts2=1024*1/44100=0.232...

pts3=2048*1/44100=0.464399秒

ffmpeg時間單位:

#define AV_TIME_BASE 1000000

#define AV_TIME_BASE_Q 1/1000000

時間基轉換公式:

timestamp(ffmpeg內部時間戳)=AV_TIME_BASE*time(秒)

time(秒)=timestamp(ffmpeg內部時間戳)*AV_TIME_BASE_Q

計算時間戳 :

下面是ffplay裏面的關於時間單位的一個重要結構體

typedef struct AVRational

{

    int num; //分子,如果是aac的話就是1

    int den;  //分母如果是aac的話就是44100

}AVRational;//這個是基礎時間

av_q2d(AVRational a)

{

    這裏其實可以表示一個時間單位是多少

    return (double)a.num/(double)a.den

}

這裏算出來的是時間戳:timestamp(秒)=pts*av_q2d(st->time_base)

第二幀pts=2048 所以第二幀時間戳是2048/44100

這裏算出來的是一幀的時間長度:st->duration*av_q2d(st->time_base)

st->duration如果是aac的一幀,也即1024,那麼aac一幀的間隔是1024個單位,

每個單位的時間是1/44100秒,所以一幀的時常爲1024/44100秒,總之1/44100是一個單位(basetime),duration表示的是多少個單位。

ffplay以音頻爲基準同步視頻的原理

同步的機制有分爲簡單同步和精確同步,在很多自個寫的程序中咱們可能簡單同步一下就ok,但是在ffplay裏面的音視頻同步可以說很精確。

爲什麼通常以音頻作爲基準:

因爲視頻隨着音頻去校準,視頻判斷時間不對可能掉1-2幀或者加快減慢速度對於人眼來說是分辨不出來的,沒有音頻掉1-2幀或者變換速度影響來的大,音頻可能會明顯聽出來卡頓,因此我們讓音頻自然放,視頻根據音頻來校準。

簡單同步:

爲簡化分析,這邊說的同步都是以音頻爲基準做同步,首先我們讓音頻正常播放,上面說到了音視頻幀的pts,也即解碼時間戳,音頻播放每一幀都會獲取這個時間戳,因此我們將這個時間戳保存起來,比如說音頻

第一幀0ms

第二幀30ms

第三幀60ms

每次播放之前都將這個變量存儲起來,之後視頻即將播放的時候獲取到存儲的時間是30呢還是60呢,再根據自己的時間戳來對比,因爲錄製視頻的時候時間戳都是對着的,自己的時間戳如果和獲取到的音頻正在播放的時間戳差的很多的話就應該要作出相應的調整了。

簡單同步的話就有一個問題,如果音頻的每一幀時間過於長的話,比如採樣率很低是8k的時候

第一幀0ms

第二幀128ms

第三幀256ms

當我的視頻獲取時間戳的時候剛好音頻播放到255ms,但其實第三幀還沒播放,返回的數據還是128ms,但實際只有1ms就進入第三幀了,因此這會再根據128來做對比判斷就不會那麼精確啦。

ffplay同步:

ffplay的同步機制引進了一個系統時鐘,其實他把你解碼流失的時間也記錄下來了,能夠精確定位到你這會已經播放到多少ms了(包括播放到一幀的中間時間段),而不是大概的剛開始播放幀的時間戳。

音頻走到第一幀時,記錄一下當前pts比如等於30ms,同時還會記錄一個系統時間比如00::00,意思就是,我在系統時間是00:00的時候記錄了需要播放音頻的第一幀是30ms,那麼好我視頻來了,視頻這會讀取到音頻的pts此時還記錄在20ms,但是視頻讀取音頻時間的時候系統時間已經是00:10了,所以這時的音頻播放其實不是30ms了,而是40ms了就是用:

00:10 減去 00:00 加上 30ms 等於 30ms,這會視頻應該和40ms對比而不是30(使用簡單同步的方法就是對比30ms的),其實視頻已經開始10ms了。那大致的意思就是這樣啦~詳細同步原理請看ffplay源碼~網上資料一大把哈~

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章