1. 程式人生 > >基於 WebRTC 實現自定義編碼解析度傳送

基於 WebRTC 實現自定義編碼解析度傳送

2020年如果問什麼技術領域最火?毫無疑問:**音視訊**。2020年遠端辦公和線上教育的強勢發展,都離不開音視訊的身影,視訊會議、線上教學、娛樂直播等都是音視訊的典型應用場景。 更加豐富的使用場景更需要我們考慮**如何提供更多的可配置能力項,**比如解析度、幀率、位元速率等**,以實現更好的使用者體驗**。本文將主要從“**解析度**”展開具體分享。 ## 如何實現自定義編碼解析度 我們先來看看“解析度”的定義。**解析度:**是度量影象內畫素資料量多少的一個引數,是**衡量一幀影象或視訊質量的關鍵指標**。解析度越高,影象體積(位元組數)越大,畫質越好。對於一個YUV i420 格式、解析度 1080p 的視訊流來說,一幀影象的體積為 1920x1080x1.5x8/1024/1024≈23.73Mbit,幀率 30,則 1s 的大小是 30x23.73≈711.9Mbit。可見資料量之大,對位元速率要求之高,所以在實際傳輸過程中就需要對視訊進行壓縮編碼。因此,視訊採集裝置採集出的原始資料解析度我們稱**採集解析度,**實際送進編碼器的資料解析度我們就稱之為**編碼解析度**。 視訊畫面是否清晰、比例是否合適,這些都會直接影響使用者體驗。攝像頭採集解析度的選擇是有限的,有時我們想要的解析度並不能直接通過攝像頭採集到。那麼,根據場景配置合適編碼解析度的能力就至關重要了。**如何將採集到的視訊轉換成我們想要的編碼解析度去傳送?**這就是我們今天的主要分享的內容。 WebRTC 是 Google 開源的,功能強大的實時音視訊專案,市面上大多開發者都是基於 WebRTC 構建實時音視訊通訊的解決方案。在 WebRTC 中各個模組都有很好的抽象解耦處理, 對我們進行二次開發非常友好。在我們構建實時音視訊通訊解決方案時,需要去了解和學習 WebRTC 的設計思想及程式碼模組,並具備二次開發和擴充套件的能力。本文我們基於 WebRTC Release 72 版本,聊聊如何實現自定義編碼解析度。 首先,我們思考下面幾個問題: - 視訊資料從採集到編碼傳送,其 Pipeline 是怎樣的? - 怎麼根據設定的編碼解析度選擇合適的採集解析度? - 怎麼能得到想要的編碼解析度? 本文內容也將從以上三點展開具體分享。 ## 視訊資料的 Pipeline 首先,我們來了解一下視訊資料的 Pipeline。視訊資料由 VideoCapturer 產生,VideoCapturer 採集資料後經過 VideoAdapter 處理,然後經由 VideoSource 的 VideoBroadcaster 分發給註冊的 VideoSink ,VideoSink 即編碼器 Encoder Sink 和本地預覽 Preview Sink。 對視訊解析度來說,流程是:將想要的解析度設定給 VideoCapturer,VideoCapturer 選擇合適的解析度去採集,原始的採集解析度資料再經過 VideoAdapter 計算,不符合預期後再進行縮放裁剪得到編碼解析度的視訊資料,將資料再送進編碼器編碼後傳送。 ![視訊資料的 Pipeline](https://img2020.cnblogs.com/blog/855570/202101/855570-20210122144122324-2007619225.png) 這裡就有兩個關鍵性問題: - VideoCapturer 如何選擇合適的採集解析度? - VideoAdapter 如何將採集解析度轉換成編碼解析度? ## 如何選擇合適的採集解析度 ### 採集解析度的選擇 WebRTC 中對視訊採集抽象出一個 Base 類:videocapturer.cc,我們把抽象稱為 VideoCapturer,在 VideoCapturer 中設定引數屬性,比如視訊解析度、幀率、支援的畫素格式等,VideoCapturer 將根據設定的引數,計算出最佳的採集格式,再用這個採集格式去呼叫各個平臺的 VDM(Video Device Module,視訊硬體裝置模組)。具體的設定如下: 程式碼摘自 WebRTC 中 src/media/base/videocapturer.h ```cpp VideoCapturer.h bool GetBestCaptureFormat(const VideoFormat& desired, VideoFormat* best_format);//內部遍歷裝置支援的所有采集格式呼叫GetFormatDistance()計算出每個格式的distance,選出distance最小的那個格式 int64_t GetFormatDistance(const VideoFormat& desired, const VideoFormat& supported);//根據演算法計算出裝置支援的格式與我們想要的採集格式的差距,distance為0即剛好滿足我們的設定 void SetSupportedFormats(const std