RTMP直播累積延時和網(wǎng)絡抖動的優(yōu)化(卷一原理)

本文首發(fā)地址:開源實踐網(wǎng):RTMP直播累積延時和網(wǎng)絡抖動的優(yōu)化(卷一原理)

問題一 累積延時

對于交互性要求較高的直播業(yè)務來說,采集推流端和觀看端的延時太高是不可接受的。在 直播協(xié)議的選擇:RTMP vs. HLS 一文中提到了采用 RTMP 協(xié)議做直播業(yè)務,一般可以將延時控制在 1-3s 或者更低。但是如果在直播中發(fā)生卡頓、播放暫停等情況時,也會不斷積累推流端和觀看端的延時。這種累積延時要怎么優(yōu)化呢?

一、優(yōu)化切換前后臺帶來的累積延時

在直播場景中,有一種情況是切換前后臺造成累積延時。這里舉個例子:在前臺時,直播視頻在播放,然后退到后臺,此時暫停播放器,音視頻數(shù)據(jù)繼續(xù)緩存,當回到前臺時,繼續(xù)從剛才退出時的視頻流數(shù)據(jù)開始播放,而實際的直播現(xiàn)在已經(jīng)不在這個時間點了。這段前后臺切換的時間里,就積累了一段延時。

對于這種延時改怎么處理呢?

  1. 第一種方案是播放器采用視頻同步音頻的策略,然后退到后臺時保持音頻繼續(xù)播放(在 iOS 平臺需要開啟 App 的 Background Audio 能力來配合)。這樣可以保持音頻一直播放不產(chǎn)生延時,而當回到前臺時,視頻同步音頻直接切換到最新時間戳即可。
  2. 第二種方案是回到前臺時重新刷新直播,重連直播流,這樣即可消滅累積延時。但是這種方案的問題是重連直播流的過程需要一定的時間,這樣回到前臺時會有卡頓,或者出現(xiàn)黑屏,尤其是當你的首屏加載優(yōu)化不夠時,這個卡頓或黑屏時間會較長。所以這種方案在你的首屏加載優(yōu)化的比較好的情況下可以采用。此外,你可以退到后臺時截取視頻當前幀貼圖到直播間上,從而當切回前臺時,防止黑屏,優(yōu)化體驗,實踐效果還是不錯的。
二、優(yōu)化卡頓帶來的累積延時

在理想的情況下:網(wǎng)絡狀況良好;采集推流端、流媒體服務器、播放端均吞吐正常無阻塞,可以不配置緩沖區(qū)。這時候推流端到播放端的延時將會很小,基本上就是網(wǎng)絡傳輸?shù)暮臅r。

但是在實際情況中,我們多多少少會遇到網(wǎng)絡不佳或網(wǎng)絡抖動的情況,在這種網(wǎng)絡環(huán)境下,如果沒有緩沖策略,直播將發(fā)生卡頓。為了解決卡頓,通常會根據(jù)具體情況在采集推流端、流媒體服務器、播放端增加緩沖策略,而一旦發(fā)生緩沖,就意味著推流端到播放端的延時。當卡頓情況多次出現(xiàn),這樣的延時就會累積。

此外,從 RTMP 協(xié)議層面上來講,累積延時本身是它的一個特征,因為 RTMP 是基于 TCP,所以不會丟包,在網(wǎng)絡情況不佳的情況下超時重傳策略、緩沖策略等自然會帶來累積延時。
所以,優(yōu)化卡頓帶來的累積延時首先是要優(yōu)化整個直播鏈條的網(wǎng)絡狀況去減少卡頓。從這個角度出發(fā),我們可以采用的策略包括:

  • 使用 CDN 分發(fā)網(wǎng)絡。
  • 合理采用 CDN 邊緣節(jié)點推流。
  • 推流端、播放端使用 HTTPDNS 選擇網(wǎng)絡狀況最好的節(jié)點接入。
  • 推流端實現(xiàn)碼率自適應策略,在網(wǎng)絡狀況不佳的情況下,降低推流碼率來降低上行帶寬壓力。
  • 流媒體服務器提供多檔位直播流服務,與此同時,播放端實現(xiàn)直播流多檔位切換策略,在網(wǎng)絡狀況不佳的情況下,切換到低檔位直播流來降低下行帶寬壓力。

問題二 網(wǎng)絡抖動的優(yōu)化

除了這些外,我們還可以優(yōu)化各端的緩沖策略來降低累積延時。直播鏈條各端的緩沖區(qū)通常都是為了防止網(wǎng)絡抖動以及端上性能抖動產(chǎn)生卡頓,但是各緩沖區(qū)的數(shù)據(jù)越多,通常也意味著累積延時越大。所以在各端上,我們還可以嘗試這些策略:

  • 在「卡頓」和「累積延時」這兩項體驗指標上尋找一個平衡點,在各端設置合適的緩沖區(qū)大小。
  • 在各端實現(xiàn)一些丟幀策略,當緩沖區(qū)超過一定閾值時,開始丟幀。
  • 在播放端的緩沖區(qū)過大時,嘗試斷開重連。
  • 服務端推流可以分高,中,低三種質(zhì)量的流,根據(jù)拉流端網(wǎng)絡質(zhì)量動態(tài)的切換

問題三 如何優(yōu)化弱網(wǎng)下推流端

推流端是整個數(shù)據(jù)的起點,如果推流端因為網(wǎng)絡原因推到服務端的視頻是卡頓的,那么接收端的視頻肯定也是卡頓的,所有推流端出現(xiàn)問題,一般都是批量問題。幸運的是,在具體的業(yè)務中,推流端一般能夠保證設備性能和網(wǎng)絡質(zhì)量。但如果不能保證,在弱網(wǎng)環(huán)境下,為了保證推流的流暢性和低延時,我們需要弄一些策略使推流更流暢,一般有如下策略:

(1) 降幀率

網(wǎng)絡發(fā)送層發(fā)現(xiàn)發(fā)送速度過慢,反饋給camera采集模塊,通過抽幀的方式來降幀率,降低整體發(fā)送的碼率

(2) 降編碼碼率

網(wǎng)絡發(fā)送層發(fā)現(xiàn)發(fā)送速度過慢,反饋給視頻編碼模塊,通過動態(tài)調(diào)整編碼器碼率,來減小視頻編碼的輸出碼率。Android上的MediaCodec在4.3+版本上都是支持動態(tài)調(diào)整碼率的; x264以及ios上的VideoToolbox也是支持的

(3) 使用H.265編碼推流

使用H.265編碼推流可以節(jié)省40%帶寬,可惜的是并不是所有手機都支持用H.265編碼格式播放,所以需要針對手機型號進行推流。

(4) 丟幀

上面兩種方法,反射弧比較長一點,它們從pipeline上來看,操作的模塊比較前面,生效比如慢一點,取決于各個模塊間的緩沖的大小。丟幀策略的話直接作用于pipeline的末端,立即生效。

RTMP發(fā)送線程循環(huán)從一個緩沖隊列里面讀取幀,然后發(fā)送。為了方便作丟幀處理,encoder采用baseline的profile,這樣,緩沖隊列里面只存在I幀和P幀

如下 mVideoCount是這個緩沖隊列里面視頻幀的個數(shù),mVideoCapbility是這個緩沖隊列總的大小

if(mVideoCount >= mVideoCapbility/2){
  dropFrame(0.3f);
} else if(mVideoCount >= mVideoCapbility/3) {
  dropFrame(0.1f);
} else if(mVideoCount >= mVideoCapbility/4) {
  dropFrame(0.05f);
} else if(mVideoCount >= mVideoCapbility/5) {
  dropFrame(0.02f);
}

dropFrame的參數(shù)是丟幀的百分比,意思是相臨兩個gop之前丟掉的P幀的百分比。為了播放端不花屏,從一個GOP的最后面的P幀開始丟

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容