牛赞:音视频前端跨平台技术应用
點擊上方“LiveVideoStack”關注我們
Flutter是近兩年大火的跨終端框架,實時音視頻因為疫情的緣故也越來越融入到人們的日常工作生活中,如線上會議、在線教育等。兩者結合起來可以碰撞起什么樣的火花呢?利用Flutter實時音視頻SDK,我們可以快速開發一個跨平臺的會議、娛樂、教育等APP。LiveVideoStackCon 2021北京站邀請到騰訊云高級工程師——牛贊,為我們分享利用Flutter如何進行實時音視頻渲染,并深入底層,優化視頻渲染的性能。
文?| 牛贊
整理 | LiveVideoStack
我來自騰訊云音視頻,本次分享主題是音視頻前端跨平臺技術應用。
我在2015年加入騰訊,先后負責過王者榮耀、英雄聯盟競猜、QQ會員等業務,目前負責騰訊云實時音視頻TRTC前端技術研發工作。
1. 跨平臺技術
首先為什么需要跨平臺框架?因為它在理想情況下可以實現一次開發,多端運行,組件互用,提升效率。對于管理者來說,可以降低人力成本,不用分別組建IOS和Android團隊。對于開發者來說,可以降低學習成本,只需理解一套跨平臺框架即可實現雙端開發,提升自我業務價值。
跨平臺技術發展幾大階段如下:
第一階段——Hybrid APP,核心原理是封裝原生接口并暴露于JS。業務運行在外部應用中,背靠前端龐大生態,開發迭代速度非常快。不足之處是能力受限于調節層,擴展性較弱,在Webview中體現的性能較差。
第二階段——2015年,Facebook推出ReactNative,核心改變是摒棄了低效的Webview渲染,轉為Native控件,交由系統進行繪制。優勢在于用戶能夠使用前端開發體系(龐大的React體系),且因其渲染交于系統繪制,所以性能優于Webview。但缺點是在渲染時需要和Native通信,當用戶處于通信頻繁場景時,處理不佳時會導致卡頓。ReactNative底層使用JS語言,只能使用JIT即時編譯,其性能和Native端存在一定差距。
第三階段——2018年,Google推出Flutter,一套代碼可以同時構建多平臺應用,它支持熱重載從而能夠高效進行開發工作,其底層使用Dart語音,同時支持JIT編譯和AOT編譯,自帶渲染引擎skia,性能基本可以達到原生水平。
對比Flutter和ReactNative的熱度趨勢,數據來源于statisa、github、stack overflow。可以發現Flutter熱度趨勢已超過ReactNative,在跨平臺領域后發制人,是目前最熱門的跨平臺技術方案。
圖中是Flutter的架構,綠色部分是Flutter的Framework,是一個Dart實現的UI SDK,從上到下包括兩大組件庫、基礎組件庫、圖形繪制、手勢識別、動畫等功能,其中兩大組件庫分別實現了基于IOS及Material UI風格的UI組件,使UI開發更加靈活。藍色部分是Flutter的核心Engine,實現Flutter渲染引擎、Dart虛擬機、Platform通信通道、時間通知、插件架構等功能。
Platform通信通道特性應用于SDK接口的封裝,還用于Flutter和Native異步消息傳遞,整個過程中消息的發送及響應都使用異步方法從而避免阻塞UI界面。Flutter引擎已經完成了橋接通道,用戶只需在通信層編寫底層的IOS/Android代碼就可以在Flutter Dart中直接使用。
2. TRTC Flutter SDK架構設計
圖中是Flutter SDK架構,SDK基于原生IOS/Android進行封裝,能夠直接對齊原生SDK,最大程度封用已有能力如音視頻采集、編碼解碼等。
設計框架過程中,我們做到了以下幾點:
對數據通信能力進行優化:由于Flutter和原生SDK進行通信的消息通道只支持簡單的如基礎類型技術,優化數據通信能力能夠使其支持更多復雜的技術類型。
將實驗層設計得更具擴展性:考慮到Flutter后續會支持更多平臺,此設計便于未來擴展更多平臺。
聚合美顏、設備、音頻相關API:以便開發者使用騰訊云的API,更加易用。
優化視頻渲染能力:GPU性能基本達到原生SDK水平。
上段提到了Flutter通信和原生通信僅支持基本的數據類型,這會帶來以下幾點挑戰:
如何實現復雜的類結構體傳輸?
圖片如何高效在Flutter和原生SDK之間傳輸?
Flutter沒有原生平臺類似的系統view組件,如何渲染視頻?
API接口繁多,如何助力開發者快速接入?
下文將分別對這四個問題進行詳細探討。
Flutter本質是Dart調用Native的接口,并異步返回Native的數據。原生SDK存在大量類結構體的類型定義,如進房接口存在TRTC Params定義了應用ID、用戶ID、用戶密鑰等相關信息,由于原有消息通道不支持傳遞這種類結構體,所以我們對數據通信能力進行了升級。
首先將Flutter定義的類結構體轉為Map對象,對其進行JSON序列化,底層消息通道會將傳輸數據高效序列化為二進制傳輸。通信層收到數據后進行反序列化,轉為對應JAVA類結構體后即可傳輸給原生SDK。
類結構體可以對參數進行約束、類型校驗、便于開發者早期發現問題,提升易用性。
直播場景中有時需要給視頻打上水印(如左上圖右下角的熊貓水印),直播過程中給視頻設置水印等接口需要把Flutter項目定義的圖片資源傳給原生SDK。Flutter有自帶的一套圖片資源管理機制,而底層SDK只能識別一個Bitmap位圖對象,問題在于Flutter沒有Bitmap這種數據類型,那么如何把Flutter項目的圖片資源轉成原生SDK需要的Bitmap呢?
首先利用應用程序的文檔目錄(Flutter和Android都可訪問),上端提到Flutter自帶一套圖片資源管理機制,所以做法是在Flutter層拷貝其圖片資源到文檔目錄,再將圖片文件地址傳輸到通信層,通信層收到地址后解析為Android原生SDK所需要的Bitmap位圖對象。雖然通過文檔目錄傳遞文件路徑的方式能夠實現共享,但當是由1張100kb的圖片進行測試時,發現拷貝文件耗時較高,于是我們思考是否能夠舍棄拷貝文件過程從而使圖片傳輸過程更加高效。
通過查看Flutter programme的源碼發現它的圖片資源文件被打包在原生資源包下面,而且Flutter暴露的API能夠使通信層拿到資源路徑,這就可以直接將Flutter圖片的Asset資源地址傳遞至通信層,通信層拿到地址后通過調用Flutter提供的AssetManager的API直接讀取對象并轉為Android所需要的Bitmap位圖對象。
網絡圖片可以采取預下載的方式提前下載至文檔目錄從而實現網絡圖片的傳遞。
如果利用Flutter定義的通信機制以實現在Flutter里進行渲染,需要將攝像頭采集的每一幀畫面數據都從原生傳輸到Flutter中,而圖像幀數據通過消息通道實時傳輸必然會引起CPU及GPU性能的巨大消耗。
為此,Flutter提供了以下兩種視頻渲染方案:
外界紋理:可以將原生端OpenGLl圖像數據共享給Flutter進行渲染。需要原生SDK提供視頻幀圖像數據回調接口,實現較為復雜。
PlatformView:主要適用于Flutter中不太容易實現的組件,如Webview、視頻播放器、地圖等,給Flutter提供了嵌入Android和IOS平臺原生view的能力。在之前Flutter技術設施尚不成熟時,PlatformView也為其注入了強大的生命力,在Native端不易實現的組件都可以通過PlatformView方案嵌入原生平臺view中。
原生SDK提供了視頻渲染view組件,我們只需利用PlatformView的能力,將Native端的視頻view嵌入Flutter中即可。PlatformView在Android端其實是AndroidView,圖片下方的第一行參數ViewType用于唯一標識Widget,用于和Android的View建立關聯。
實現PlatformView并不復雜,簡單了解官方文檔后可以利用公式及官方提供的框架代碼構造出PlatformView。
我們先嘗試了容易實現的PlatformView方案,在視頻渲染封裝好后,對輸出的視頻畫面進行性能測試,使用oppo的一部低端機進行測試,當房間有6個用戶的時候,第二屏畫面渲染異常(右側2圖)。
利用騰訊云的PerfDog性能狗進行性能分析,發現GPU占用異常高,于是繼續開展了一些列優化措施。
首先優化視頻列表,默認Flutter的ListView不支持懶加載,我們將其替換為ListView.builder,測試開始時,懶加載未生效且默認支持了預加載,Flutter底層默認預加載250像素以外的區域,考慮到視頻渲染的增加對GPU的負荷很大,于是摒棄了預加載能力,更進一步地對非可視區域視頻進行回收,當滑動到第二屏時就停止第一屏視頻的拉流渲染。
優化視頻列表后,GPU占用從72%下降到50%左右,視頻畫面能夠正常渲染顯示。
第一階段優化結束后,我們沒有就此止步。因為上線優化的Flutter之后,客戶會對比其與Native端的差距,數據顯示CPU、內存跟Android原生的占用差不多。
然而Flutter的GPU對比原生性能差距比較明顯,達到了15%。
接著我們仔細對照了PlatformView的實現原理,發現對于Android來說,在虛擬顯示模式下,其底層也是使用的外接紋理進行渲染,中間多了一塊圖形緩沖區,在Native端渲染好的視頻View的每一個像素都流經這塊圖形緩沖區,轉為圖像紋理數據后在SurfaceTexture(Flutter提供的畫板)上進行繪制,最終Flutter根據畫板數據渲染出完整視頻。
在以上環節中,性能的主要消耗點在于圖形緩沖區,因為已在Native端渲染好的視頻會重新經過這塊區域繪制到SurfaceTexture中,造成了顯存和繪圖性能的嚴重浪費。針對此問題的優化思路是將拿到的SDK裸數據接口通過OpenGL直接輸出到SurfaceTexture畫板上,而非利用Native端的系統view組件。
最終視頻渲染的架構如圖所示,遠端用戶進房時,本機通過云服務接收到進房信號,比如很多人在一個房間中,此時有新用戶進房,本機需要渲染新用戶,首先發送拉流指令,安卓原生SDK一幀幀地回調視頻幀紋理數據,再通過OpenGL繪制到SurfaceTexture畫板中,Flutter最終拿到通信層返回的Texture ID(原生側繪圖數據對應的ID),通過此ID,Flutter能夠在GPU中找到并使用相應繪圖數據,最后由Flutter的引擎進行渲染。
Flutter優化后的GPU性能提升了約10%,基本能達到Android原生SDK水平。
原始的SDK、API繁多,光是Flutter API就有100多個。開發者和客戶理解學習API的成本很高,接入耗時較久。于是我們建設了一系列場景化方案,客戶可以尋找契合自身的業務場景,參考源碼實現,提升接入效率。
TRTC應用的場景包括音視頻通話、多人會議、在線教育、互動直播、語音聊天室、狼人殺、在線醫療、在線K歌等。
設計場景的方案過程中主要采取UI和場景SDK分離模式,客戶能夠直接參考UI界面進行開發,也可以使用封裝好的場景SDK個性化定制UI。場景開發后臺采用了騰訊云函數服務,降低客戶接入門檻,所有組件都無服務器化,無需運維,節省人力成本。底層依賴TRTC SDK進行音視頻傳輸、IM SDK提供信令及群聊能力。
接著介紹一些已經實現的應用場景。
語音通話場景中,選擇呼叫用戶發送通話請求,對方接受后即可建立音視頻通話連接,類似于微信音視頻通話功能。互動直播包括互動連麥、主播PK、低延遲觀看,彈幕聊天等。延遲能夠控制在300ms以內,直播過程中提供高級美顏如瘦臉、微臉,圖中可以明顯看到微臉操作后的效果對比。視頻會議適合交流工作。語音沙龍,如年初熱度很高的ClubHouse,用戶能夠加入感興趣的話題房間,在房間中,由嘉賓發言,房間里的其他聽眾旁聽,聽眾如果想要發言,可以舉手申請成為嘉賓,之后提問或發言。在線教育場景中,老師能夠選擇語音、視頻、屏幕分享等授課方式。
結合在線教育場景,簡單介紹一下常見SDK的實現理念。該SDK主要針對在線教育場景中使用實時音視頻及通信能力的二次封裝,在封裝基本的音視頻聊天及屏幕分享能力的同時,還分裝了老師提問,學生舉手,老師邀請學生上臺回答,回答完畢等能力。客戶如果不滿意場景化默認實現的UI,可以使用場景化SDK個性化開發。場景化SDK的接口基本不超過30個,語意也更加場景化。客戶對接原始API,周期需要2-3個月;使用場景SDK進行對接,周期僅有1個月;復用場景化方案包括UI組件庫,最快1周就能上線項目。
目前已經有越來越多的公司在新項目中嘗試使用Flutter,這里列舉的都是比較典型的使用Flutter的用戶,其中有做互動直播場景的日本直播平臺yell live、幣安、騰訊游戲青少年直播;做教育的潭州教育、力拓飛遠,還有做音視頻通話的智聯招聘等客戶。
如果新業務有音視頻方面的需求,那Flutter可以是一個非常不錯的選擇。
3. Flutter音視頻未來展望
目前Flutter主要應用在移動端iOS/Android雙端,Flutter愿景是成為一個多端運行的UI框架,能夠支持不僅僅是移動端,還包括Web端和桌面端(MacOS/Windows),Flutter官方預計年底會正式支持桌面端,我們團隊已經將Beta階段的桌面端融合進TRTC音視頻能力中,并開放了對MacOS/Windows的支持,功能上能夠支持音視頻通話部分,還缺失屏幕共享等能力,我們后續會補齊。
FlutterWeb與FlutterNative的整體架構相似,它們都共用Framework層,核心區別在于FlutterWeb重寫了engine層,利用DOM/Canvas對齊了FlutterNative的UI渲染能力,使得Flutter編寫的UI能夠在瀏覽器上正常展示。雖然FlutterWeb在年初正式開放對Web的支持,但仍存在以下問題:
構建產物簡陋,目前所有文件都打包為main.dart.js,不可避免導致圖片文件非常大,基本為1-2mb,另外還缺少js拆包,文件hash等工作,影響頁面加載性能。
由于FlutterWeb自身實現了一套頁面滾動機制,頁面滾動過程中,會頻繁計算位置信息,引起滾動區域的重新渲染,最終導致頁面滾動性能較差。
目前Flutter官方建議是FlutterWeb端適合以下三種場景:
使用Flutter構建的漸進式Web應用程序;
單頁應用程序;
將現有的移動應用程序發布到web上。
Flutter不適用于web端常見的以文檔為中心的瀑布流式的場景。
目前我們的SDK在dev測試版上也開放了對Web的支持,跟Native的對比多了一層Web兼容層,主要為了兼容Flutter Native API設計,實際上Web和Native的通信并不依賴于消息通道。
WebApi和NativeApi差異比較大,所以我們在Web通信層也做了大量的邏輯去抹平這里的差異。底層的WebSDK是基于WebRTC的實時音視頻通話解決方案,目前主要支持Chrome58+和Safari瀏覽器。
未來,Flutter對桌面端/web端的支持會越來越好,一套框架打通全平臺非常值得期待。
4. Web端音視頻能力暢想
Web端的?視頻能?也在不斷的進化,瀏覽器已經變成?個完備的多媒體引擎。重點介紹一下瀏覽器帶來的三個新特性:編碼層面,可以應用webcodecs做低延遲編解碼,動態控制編碼的關鍵幀、編碼碼率;傳輸部分,使用WebTransport提供靈活可控的高性能UDP傳輸能力;WebAssenbly使我們可以復用C++寫的復雜算法,在瀏覽器端可以使用WebAssenbly將C++復雜算法編譯為瀏覽器可運行的代碼,從而在瀏覽器端實現音頻降噪、回聲消除等能力。
基于騰訊20多年的音視頻積累,進?步擴展瀏覽器的能?之后,在瀏覽器端再造一個自定義的RTC技術引擎,這樣做的好處有很多:
能復用一套TRTC的技術棧,一套C++的代碼可以復用在多個平臺。我們在Native端積累了很多最佳實踐可以同步用在Web端。
更可控的RTC QOS調控能力,比如在直播場景下,可以犧牲一定的延遲來換取直播的清晰度。
更豐富的使用場景,底層技術也可以復用到直播推流SDK和播放器SDK。
下一代Web的RTC引擎預計明年正式對外,大家可以期待一下。
在目前視頻會議產品中,虛擬背景已經成為了標配能力。舉個例子,在視頻會議中,背景可能是家中,不太正式,這時可以選擇合適的背景圖替換背景。利用WebGpu/WebgGl的圖形渲染能力、TensorFlow的機器學習能力和WebAssembly的多線程計算能力實現Web版本SDK的人像分割能力。
此外,我們還做了大量的優化,將模型文件精簡到1M以內。我們還提供了豐富的API幫助用戶在性能和效果之間達到很好的平衡。
結合瀏覽器新特性,還可以開發很多功能,通過shader算法打造WebAr引擎,適用于直播過程中美顏美妝、趣味貼紙等場景。
在日常的企業直播中,OBS已經成為了企業直播的標配。當瀏覽器的能力提升之后,一個Web版本的OBS成為了可能,它能帶來以下優勢:
多采集源的支持,能同時支持多人通話直播;
所見即所得的效果,可通過拖動改變布局;
操作簡單,打開網頁即能直播。
Web OBS能替代OBS80%的能力,可以應用在企業直播、在線直播等場景。
以上是本次的分享,謝謝!
掃描圖中二維碼或點擊閱讀原文
了解大會更多信息
喜歡我們的內容就點個“在看”吧!
總結
以上是生活随笔為你收集整理的牛赞:音视频前端跨平台技术应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LiveVideoStackCon 20
- 下一篇: 走近互联网先驱者——Henning Sc