音視頻同步問題
音視頻流裡都包含了播放速率的資訊,音頻使用採樣率來表示,而視頻則採用f/s來表示,但是我們卻不能簡單地用這兩個資料來對音視頻進行同步,我們需要使用DTS(解碼時間戳記)和PTS(播放時間戳記)這兩個資料;我們知道影視資料在儲存時,會存在多種幀形式,例如MPEG中就採用了I,B和P,由於B幀的存在使得PTS和DTS存在不同(原因見附錄),如圖1所示為一個簡單的例子;當然真正影響我們音視頻同步的是PTS。
我們可以從影視檔案中獲得包的PTS,但是我們無法直接獲得幀(我們真正關心的)的PTS,解決辦法是用一幀的第一個包的PTS作為這一幀的PTS,這是可行的,因為當一個包開始一幀時,avcodec_decode_video()會調用為幀申請儲存空間的函數,我們可以重寫這個函數,在其中加入擷取包DTS的方法(這是很容易的),因為ffmpeg會重新給包進行排序,因此被avcodec_decode_video()處理過的包的DTS和返回的幀的PTS是相同的,這樣就可以得到幀的PTS了。當然有時我們可能沒法得到這個PTS,那樣我們使用內部video_clock(記錄視頻已經過去的時間);
這樣我們就可以使用PTS來重新隊列化我們的幀(queue_picture);
然後,我們可以去獲得音訊播放時間PTS。
get_audio_clock():
把audio_clock作為音訊pts,但是在audio_decode_frame()計算的audio_clock的是假定緩衝滿的情況,而實際上可能緩衝是不滿的,我們需要減去閒置部分的時間:pts -= (double)hw_buf_size / bytes_per_sec;
audio_decode_frame():音頻解碼
讀取包時,擷取其pts,放入audio_clock中;
播放時根據緩衝大小和播放速率計算播放時間;
獲得這兩個pts後,我們有三個選擇:視頻同步音頻(計算音視頻PTS只差,來決定視頻是否有延遲)、音頻同步視頻(根據音視頻PTS差值調整音頻取的樣值,即改變音頻緩衝區的大小)和音頻視頻同步外部時鐘(同前一個)。
附錄:
I frame :幀內編碼幀 又稱intra picture,I 幀通常是每個 GOP(MPEG 所使用的一種視頻壓縮技術)的第一個幀,經過適度地壓縮,做為隨機訪問的參考點,可以當成圖象。I幀可以看成是一個映像經過壓縮後的產物。
P frame: 前向預測性編碼幀 又稱predictive-frame,通過充分將低於映像序列中前面已編碼幀的時間冗餘資訊來壓縮傳輸資料量的編碼映像,也叫預測幀;
B frame: 雙向預測插入編碼幀 又稱bi-directional interpolated prediction frame,既考慮與源映像序列前面已編碼幀,也顧及源映像序列後面已編碼幀之間的時間冗餘資訊來壓縮傳輸資料量的編碼映像,也叫雙向預測畫面;
I frame: 自身可以通過視頻解壓演算法解壓成一張單獨的完整的圖片。
P frame:需要參考其前面的一個I frame 或者B frame來產生一張完整的圖片。
B frame:則要參考其前一個I或者P幀及其後面的一個P幀來產生一張完整的圖片。
I frame 的解碼不依賴於任何的其它的幀.而p frame的解碼則依賴於其前面的I frame或者P frame.B frame的解碼則依賴於其前的最近的一個I frame或者P frame 及其後的最近的一個P frame.