在對音視頻從新編碼並須要進行同步的場景中,須要遵照幾項基本原則(不然音視頻就會卡頓,不流暢。以音頻aac編碼頻率44.1k,視頻h264編碼25幀幀率爲例):
1. 保證輸入端的音視頻幀到達間隔基本精確。音頻aac每幀時長是23.2ms(1000*1024/44100),視頻每幀時長是40ms(1000/25)。因此,用於編碼的原始音頻samples的到達頻率(或從buffer中獲取的頻率)應該爲441 samples/per channel/ per 10ms(每一個樣本假設16bits,即882字節/通道/10ms,若是原始音頻採樣率不是44.1k,編碼前須要從新採樣);原始視頻幀到達頻率(或從buffer中獲取的頻率)應該爲1幀/per 40ms(視頻幀率可能須要從新採樣)。若是輸出的音視頻流不流暢,可先檢查輸入端音視頻流的輸入間隔狀況。
2.保證輸出端的音視頻流時間戳使用同一參考系。好比音視頻流都使用當前系統時間做爲同一時間參考系,但音視頻流能夠有不一樣的系統時間起始點。好比音頻流先開始於1492764087000 ms,視頻稍後700ms開始於1492764087700ms。好比rtmp裏面使用32位時間戳,則音視頻流只能使用相對時間戳,接上例,音頻時間戳增加到700ms的時候視頻流才從0開始,表示視頻流是從音頻流的700ms處開始的,這樣才能達到同步的效果。 另一種時間戳方案是每一個音視頻幀按固定間隔增加,好比音視頻時間戳都從0開始,音頻每一個aac幀增長23.2ms,每一個視頻幀增加40ms。正常狀況下,音視頻流是同時從0開始按相應各自間隔發送幀的,但也有視頻流晚於音頻流或音頻流晚於視頻流的狀況。這種狀況須要作時間戳同步,稍晚的流起始時間要根據超前的流的時間來設置。前端
3.保證交叉輸出時音視頻間隔基本精確。這裏的輸出端就徹底等同於一個硬件編碼器,只有保證交叉輸出的音視頻幀間隔穩定,才能保證播放端的流暢。好比rtmp,每一個aac音頻幀輸出間隔應該在23ms左右,每一個視頻幀輸出間隔應該在40ms左右,並且音視頻幀是交叉輸出。換句話說,每23ms要發送一個aac音頻幀,每40ms發送一個視頻幀(可使用兩個單獨的線程來分別發送音視頻流)。若是排除了上面的兩個問題仍是不能流暢播放,能夠檢查這個環節是否正常。
編碼
總之,從新編碼並同步的這個環節,必須創建在數學測量的基礎上。有錯誤或補充的地方,歡迎指出。spa
下面是一個實際項目中基於以上規則的調整實現版本:線程
實際環境中與上述假設條件不符的地方:視頻
1.前端輸入幀率變化,x264不能穩定輸出每秒固定24/25幀。同步
時間戳調整方案:由標準的音視頻固定幀間隔累加調整爲按幀間實際時間偏移累加。如音頻,再也不按每幀間隔23ms去累加,緣由是會出現系統時間間隔1s的狀況下音頻時間戳增長小於1s的狀況;視頻再也不按每幀間隔40ms去累加,也改成實際幀間間隔,好比每次編碼完以後每幀之間間隔是變化的,幀率可能不到24/25。最終實現音視頻時間戳的同步。以系統絕對時間間隔來增長音視頻時間戳自己就是同步的;若是使用其餘人爲制定的時間戳增加方案(好比上面的音視頻按固定間隔遞增),就須要再引入一個同步模塊來處理音視頻時間戳之間的遞增偏移問題,比較麻煩也難於精確控制。該方法其實就是上面提到的第2條原則:音視頻使用同一時間參考系。數學
項目中幾種嘗試過的錯誤的方案:it
1. 上面標準的音視頻幀間隔累加計算時間戳。這種狀況會出現音視頻時間戳偏移愈來愈大的問題,可能視頻大於音頻或者音頻大於視頻,時間戳會差距愈來愈大。基礎
2. 視頻流使用原始幀時間戳做爲參考。此種方法也不可取,緣由是原始幀的時間戳是基於原始視頻流幀率的,你x264從新編碼後,幀率已經不同了。幀與幀之間的間隔也沒有參考意義。音頻