1. 程式人生 > >WebRTC的QP、解析度自動調整

WebRTC的QP、解析度自動調整

摘要

    描述WebRTC在編碼端解析度自動調整的原因,以及關閉解析度自動調整策略的方法。

版本

    主要針對57版本,同時也查看了65版本的程式碼,程式碼結構有所改變,但是邏輯不變。

問題

    最近把SDK整合到OBS,方便客戶端合流。這樣OBS可以把合好的影象通過WebRTC推到服務端(janus)。發現一個問題,在抓屏的場景下,拉到的流解析度迅速下降,最後模糊到看不清。

原因

    在不抓屏的情況下,例如採集攝像頭,WebRTC會開啟QualityScaler。在編碼的時候,計算每幅影象的量化引數(QP,Quantization Parameter,相當於影象的複雜度),當一系列影象的平均QP超過閾值時會調整解析度(H264的合法範圍是24~37),超過37要降解析度,低於24要提高解析度。
    但是對抓屏來說這個策略並不合理,因為螢幕影象有很多細節,文字也會提升QP值。所以在57版的webrtcvideoengine2.cc(2084行)有註釋"Do not adapt resolution for screen content as this will likely result in blurry and unreadable text",如果在抓屏時開啟解析度自動調整會造成模糊和不可讀的文字,因為抓屏和攝像頭採集不一樣,影象細節更豐富,並且基本不會切換到細節少的狀態。因此在抓屏的時候如果是使用AdaptedVideoTrackSource當作資料來源,則需要重寫is_screencast方法,直接返回true,告訴WebRTC視訊源是抓屏,這樣編碼端的解析度調整就不會生效。

    這個策略主要目的是為了控制編碼的消耗,不過這裡閾值寫死卻不太靈活,為了彌補這個策略在CPU與編碼效能的關係上的缺失,除了QP之外,編碼CPU佔用也在ViEEncoder中被考慮。當編碼的CPU佔用超過一定閾值的時候,解析度也將被調整,這個策略和is_screencast是兩個並列的條件(webrtcvideoengine2.cc 1639行)。

    在預設is_screencast為false並且根據cpu調整解析度策略都開啟的條件下,還有一種辦法禁用解析度scaling,就是自定義VideoEncoder,並在GetScalingSettings方法中返回false(vie_encoder.cc 441行),目前WebRTC的H264編碼器實現H264EncoderImpl的GetScalingSettings方法返回的是true。

總結

    在已經有視訊採集實現獲取到YUV資料時(NV12或者NV21),用AdaptedVideoTrackSource給WebRTC傳送視訊資料最方便,WebRTC的Android和IOS端都是這種實現,注意重寫is_screencast方法,返回合適的值確保解析度的調整策略。

題外話

    OBS整合基於WebRTC的SDK的方法主要參考以下連結:
    https://github.com/CoSMoSoftware/OBS-studio-webrtc
    實現了一個output外掛,並對OBS原始程式碼做了一點修改。
    該連結裡的程式碼並沒有採用AdaptedVideoTrackSource,而是過載了VideoCaputreImp和WebRtcVideoCapturer,這實際上是繞了彎路,並且這種方式在WebRTC內部支援的也不太好,關閉資源時會崩潰,所以在這份程式碼裡作者也沒有好好清理資源,留下一堆垃圾。