一、如何判斷當前的網絡狀況
可以以發送一幀視頻數據的時間為依據,判斷當前網絡擁塞情況。
網絡中出現丟包和抖動,導致接收端接收數據超時,會激發發送端數據重傳,重傳機制本身擠占網絡帶寬,導致sendbuffer中的數據進一步發送失敗,致使sendbuffer中的數據不斷增多,達到上溢的警戒線,此時應用層函數下發數據到sendbuffer就不會瞬間完成,而是會等待sendbuffer中的數據低於警戒線,再將數據下發。因此可以根據應用層函數寫數據到sendbuffer的時間來判斷網絡的擁塞情況。
可以實時監控直播網絡狀況,當網絡帶寬變差時,推流端會迅速地逐級降低視頻的幀率、碼率、分辨率,以保證推流視頻的流暢。而當網絡恢復良好時,在確保流暢的前提下,推流端會逐漸提升視頻的幀率、碼率、分辨率,提升直播視頻的清晰度。
二、弱網情況下的一些優化
1. 根據網絡狀況動態調整視頻的幀率、分辨率,使占用的網絡帶寬更低;
2. 當網絡狀況不好時,選擇性的丟棄參考幀(不丟I幀和音頻幀);
3. 選擇更高編碼壓縮率的編碼格式(如H.265)。
三、推流端自適應碼率
直播推流端實時根據主播所處的網絡環境,調整主播的視頻碼率。在推流過程中,我們可以根據當時主播的網絡狀況,測算出網絡出口帶寬是多少,進而和編碼器產生的數據量進行比較:如果網絡出口帶寬大於編碼器產生的數據量,則可以提高視頻質量(增大編碼器的碼率設置,同時增大視頻的fps以達到更加流暢的效果);如果網絡出口帶寬和編碼器產生的數據量相近,那么視頻質量可不做任何改變;如果小於,那就要降低視頻質量,以使得主播可以流暢的進行直播。由於整個流的碼率中視頻軌碼率達90%以上,所以只處理視頻一般就能滿足大部分場景。
1. 網絡帶寬監測模塊
網絡上行帶寬成為發送碼率,編碼器編碼出來的碼率成為壓縮碼率。實際的監測過程應該是一個窗口時間段的平均碼率(一般為3~10s)。
2. 碼率調整策略
我們的目的就是按照發送碼率反饋給編碼器來調整壓縮碼率。一般會使用幾個窗口時間長度的發送平均碼率去設置知道編碼器改變碼率。但是這種策略只能作為將碼率的條件,因為這種統計方式統計出來的發送碼率不可能會大於壓縮碼率。因此,如果想要做到升碼率,就需要在策略中加上當前H264隊列大小的變化趨勢,比如隊列大小哦啊一直在0和1之間進行變化,則代表編碼器編碼出來的視頻幀,Publisher模塊就立馬將他發送出去,這時我們就可以嘗試去上升碼率;比如如果隊列編碼趨勢在隊列大小的10%~70%范圍內徘徊,則代表有網絡抖動發生,可以暫時不做處理(也就是說升碼率同時也要看當前視頻buffer的大小)。
3. 實時改變編碼器的碼率
ios和android的硬解分別有相應的接口可以實時改變碼率。而FFmpeg的libx264可以通過x264_encoder_reconfig函數實時改變碼率。
總結,對於直播場景,采用qos策略,動態調整編碼參數,包括幀率,碼率,分辨率,緩沖區。當直播出現卡頓,采用快降慢升的策略,當網絡波動比較厲害,這樣可以避免編碼參數頻繁的來回調整,造成惡性循環。當進行編碼參數調整時,一般是根據分辨率把碼率,幀率分成幾個檔次,然后在根據一定時間段內的統計數據,在這幾組參數集合之間進行來回切換,確保音視頻流暢的同時,盡量提高圖像質量。
五、GOP(Group of pictures)
GOP的長度就是指2個I幀之間的幀數(通常也稱為“關鍵幀間隔”)。
GOP 長度越小,直播內容延時越小,GOP 長度越大,直播內容延時越大;
GOP 越長,越有利於減少視頻碼率,降低其所需要消耗的存儲和帶寬。
六、播放體驗
兩個問題:
1. 至少一個 GOP 的直播內容延時不可避免;
2. 如果 GOP 尚未生成完畢時進行播放,會遇到黑屏(或是花屏)。
針對第一個問題,其實很好解決,推流端編碼器或直播服務器將 GOP 長度設置的足夠低(比如 0.5s 或是 1s, 不影響編碼畫質的前提下),播放畫面與現場畫面的時間差將會越低。
針對第二個問題,單純修改播放器業務邏輯也解決不了問題。有一種辦法是即修改直播服務器,也修改客戶端播放器行為邏輯,實現 “雙 I 幀交替秒開優化”。
七、雙 I 幀交替秒開優化
修改直播服務器由緩存一個 GOP 為緩存一個 I 幀,快速下發給播放器;
修改客戶端播放器行為,當遇到一個 I 幀后立即渲染顯示,達到秒開,並且是“首幀秒開”;
為了防止時間差內首次播放請求沒有遇到 I 幀播放會出現花屏,直播服務器與客戶端播放器建立連接后,將緩存的 I 幀快速下發,將第二個 I 幀之前的非 I 幀全部丟棄,直到第二個 I 幀之后傳輸正常的 GOP。這樣,通過 “雙 I 幀交替秒開優化”,即可以減少一個 GOP 的直播內容延時,又可以避免黑屏或花屏達到播放請求一次性秒開。