天天看點

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

文/陳爐軍

整理/LiveVideoStack

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃
大家好,我是阿裡巴巴閑魚事業部的陳爐軍,本次分享的主題是Flutter浪潮下的音視訊研發探索,主要内容是針對閑魚APP在當下流行的跨平台架構Flutter的大規模實踐,介紹其在音視訊領域碰到的一些困難以及解決方案。
Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃
分享内容主要分為四個方面,首先會對Flutter有一個簡單介紹以及選擇Flutter作為跨平台架構的原因,其次會介紹Flutter中與音視訊關系非常大的外接紋理概念,以及對它做出的一些優化。之後會對閑魚在音視訊實踐過程中碰到的一些Flutter問題提出了一些解決方案——TPM音視訊架構。最後是閑魚Flutter多媒體開源元件的介紹。

Flutter

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

Flutter是一個跨平台架構,以往的做法是将音頻、視訊和網絡這些子產品都下沉到C++層或者ARM層,在其上封裝成一個音視訊的SDK,供UI層的PC、iOS和Android調用。

而Flutter做為一個UI層的跨平台架構,顧名思義就是在UI層也實作了一個跨平台開發。可以預想的是未Flutter發展的好的話,會逐漸變為一個從底層到UI層的一個全鍊路的跨平台開發,技術人員分别負責SDK和UI層的開發。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

在Flutter之前已經有很多跨平台UI解決方案,那為什麼選擇Flutter呢?

我們主要考慮性能和跨平台的能力。

以往的跨平台方案比如Weex,ReactNative,Cordova等等因為架構的原因無法滿足性能要求,尤其是在音視訊這種性能要求幾乎苛刻的場景。

而諸如Xamarin等,雖然性能可以和原生App一緻,但是大部分邏輯還是需要分平台實作。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

我們可以看一下,為什麼Flutter可以實作高性能:

原生的native元件渲染以IOS為例,蘋果的UIKit通過調用平台自己的繪制架構QuaztCore來實作UI的繪制,圖形繪制也是調用底層的API,比如OpenGL、Metal等。

而Flutter也是和原生API邏輯一緻,也是通過調用底層的繪制架構層SKIA實作UI層。這樣相當于Flutter他自己實作了一套UI架構,提供了一種性能超越原生API的跨平台可能性。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

但是我們說一個架構最終性能怎樣,其實取決于設計者和開發者。至于現在到底是一個什麼狀況:

在閑魚的實踐中,我們發現在正常的開發沒有特意的去優化UI代碼的情況下,在一些低端機上,Flutter界面的流暢性是比Native界面要好的。

雖然現在閑魚某些場景下會有卡頓閃退等情況,但是這是一個新事物發展過程中的必然問題,我們相信未來性能肯定不會成為限制Flutter發展的瓶頸的。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

在閑魚實踐Flutter的過程中,混合棧和音視訊是其中比較難解決的兩個問題,混合棧是指一個APP在Flutter過程中不可能一口氣将所有業務全部重寫為Flutter,是以這是一個逐漸疊代的過程,這期間原生native界面與Flutter界面共存的狀态就稱之為混合棧。閑魚在混合棧上也有一些比較好的輸出,例如FlutterBoost。

外接紋理

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

在講音視訊之前需要簡要介紹一下外接紋理的概念,我們将它稱之為是Flutter和Frame之間的橋梁。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

Flutter渲染一幀螢幕資料首先要做的是,GPU發出的VC信号在Flutter的UI線程,通過AOT編譯的機器碼結合目前Dart Runtime,生成Layer Tree UI樹,Layer Tree上每一個葉子節點都代表了目前螢幕上所需要渲染的每一個元素,包含了這些元素渲染所需要的内容。将Layer Tree抛給GPU線程,在GPU線程内調用Skia去完成整個UI的渲染過程。Layer Tree中有PictureLayer和TextureLayer兩個比較重要的節點。PictureLayer主要負責螢幕圖檔的渲染,Flutter内部實作了一套圖檔解碼邏輯,在IO線程将圖檔讀取或者從網絡上拉取之後,通過解碼能夠在IO線程上加載出紋理,交給GPU線程将圖檔渲染到螢幕上。但是由于音視訊場景下系統API太過繁多,業務場景過于複雜。Flutter沒有一套邏輯去實作跨平台的音視訊元件,是以說Flutter提出了一種讓第三方開發者來實作音視訊元件的方式,而這些音視訊元件的視訊渲染出口,就是TextureLayer。

在整個Layer Tree渲染的過程中,TextureLayer的資料紋理需要由外部第三方開發者來指定,可以把視訊資料和播放器資料送到TextureLayer裡,由Flutter将這些資料渲染出來。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

TextureLayer渲染過程:首先判斷Layer是否已經初始化,如果沒有就建立一個Texture,然後将Texture Attach到一個SufaceTexture上。

這個SufaceTexture是音視訊的native代碼可以擷取到的對象,通過這個對象建立的Suface,我們可以将視訊資料、攝像頭資料解碼放到Suface中,然後Flutter端通過監聽SufaceTexture的資料更新就可以順利把剛才建立的資料更新到它的紋理中,然後再将紋理交給SKIA渲染到螢幕上。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

然而我們如果需要用Flutter實作美顔,濾鏡,人臉貼圖等等功能,就需要将視訊資料讀取出來,更新到紋理中,再将GPU紋理經過美顔濾鏡處理後生成一個處理後的紋理。按Flutter提供的現有能力,必須先将紋理中的資料從GPU讀出到CPU中,生成Bitmap後再寫入Surface中,這樣在Flutter中才能順利的更新到視訊資料,這樣做對系統性能的消耗很大。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

通過對Flutter渲染過程分析,我們知道Flutter底層需要渲染的資料就是GPU紋理,而我們經過美顔濾鏡處理完成以後的結果也是GPU紋理,如果可以将它直接交給Flutter渲染,那就可以避免GPU->CPU->GPU這樣的無用循環。這樣的方法是可行的,但是需要一個條件,就是OpenGL上下文共享。

OpenGL

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

在說上下文之前,得提到一個和上線文息息相關的概念:線程。

Flutter引擎啟動後會啟動四個線程:

第一個線程是UI線程,這是Flutter自己定義的UI線程,主要負責GPU發出的VSync信号時候用目前Dart編譯的機器碼和目前運作環境建立出Layer Tree。

還有就是IO線程和GPU線程。和大部分OpenGL處了解決方案中一樣,Flutter也采取一個線程責資源加載,一部分負責資源渲染這種思路。

兩個線程之間紋理共享有兩種方式。一種是EGLImage(IOS是 CVOpenGLESTextureCache)。一種是OpenGL  Share Context。Flutter通過Share Context來實作紋理共享,将IO線程的Context和GPU線程的Context進行Share,放到同一個Share Group下面,這樣兩個線程下資源是互相可見可以共享的。

Platform線程是主線程,Flutter中有一個很奇怪的設定,GPU線程和主線程共用一個Context。并且在主線程也有很多OpenGL 操作。

這樣的設計會給音視訊開發帶來很多問題,後面會詳細說。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

音視訊端美顔處理完成的OpenGL紋理能夠讓Flutter直接使用的條件就是Flutter的上下文需要和平台音視訊相關的OpenGL上下文處在一個Share Group下面。

由于Flutter主線程的Context就是GPU的Context,是以在音視訊端主線程中有一些OpenGL操作的話,很有可能使Flutter整個OpenGL被破壞掉。是以需要将所有的OpenGL操作都限制在子線程中。

通過上述這兩個條件的處理,我們就可以在沒有增加GPU消耗的前提下實作美顔和濾鏡等等功能。

TPM 

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

在經過demo驗證之後,我們将這個方案應用到閑魚音視訊元件中,但改造過程中發現了一些問題。

上圖是攝像頭采集資料轉換為紋理的一段代碼,其中有兩個操作:首先是切程序,将後面的OpenGL操作都切到cameraQueue中。然後是設定一次上下文。然後這種限制條件或者說是潛規則往往在開發過程中容易被忽略的。而這個條件一旦忽略後果就是出現一些莫名其妙的詭異問題極難排查。是以我們就希望能抽象出一套架構,由架構本身實作線程的切換、上下文和子產品生命周期等的管理,開發者接入架構以後隻需要安心實作自己的算法,而不需要關心這些潛規則還有其他一些重複的邏輯操作。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

在引入Flutter之前閑魚的音視訊架構與大部分音視訊邏輯一樣采用分層架構:

1:底層是一些獨立子產品

2:SDK層是對底層子產品的封裝

3:最上層是UI層。

引入Flutter之後,通過分析各個子產品的使用場景,我們可以得出一個假設或者說是抽象:音視訊應用在終端上可以歸納為視訊幀解碼之後視訊資料幀在各個子產品之間流動的過程,基于這種假設去做Flutter音視訊架構的抽象。

鹹魚Flutter多媒體開源元件

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

整個Flutter音視訊架構抽象分為管線和資料的抽象、子產品的抽象、線程統一管理和上下文同一管理四部分。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

管線,其實就是視訊幀流動的管道。資料,音視訊中涉及到的資料包括紋理、Bit Map以及時間戳等。結合現有的應用場景我們定義了管線流通資料以Texture為主資料,同時可以選擇性的添加Bit Map等作為輔助資料。這樣的資料定義方式,避免重複的建立和銷毀紋理帶來的性能開銷以及多線程通路紋理帶來的一些問題。也滿足一些特殊子產品對特殊資料的需求。同時也設計了紋理池來管理管線中的紋理資料。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

子產品:如果把管線和資料比喻成血管和血液,那架構音視訊的場景就可以比喻成器官,我們根據子產品所在管線的位置抽象出采集、處理和輸出三個基類。這三個基類裡實作了剛才說的線程切換,上下文切換,格式轉換等等共同邏輯,各個功能子產品通過內建自這些基類,可以避免很多重複勞動。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

線程:每一個子產品初始化的時候,初始化函數就會去線程管理的子產品去擷取自己的線程,線程管理子產品可以決定給初始化函數配置設定新的線程或者已經配置設定過其他子產品的線程。

這樣有三個好處:

一是可以根據需要去決定一個線程可以挂載多少子產品,做到線程間的負載均衡。第二,多線程并發式能夠保證子產品内的OpenGL操作是在目前線程内而不會跑到主線程去,徹底避免Flutter的OpenGL 環境被破壞。第三,多線程并行可以充分利用CPU多核架構,提升處理速度。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

從Flutter端修改Flutter引擎将Context取出後,根據Context建立上下文的統一管理子產品,每一個子產品在初始化的時候會擷取它的線程,擷取之後會調用上下文管理子產品擷取自己的上下文。這樣可以保證每一個子產品的上下文都是與Flutter的上下文進行Share的,每個子產品之間資源都是共享可見的,Flutter和音視訊native之間也是互相共享可見的。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

基于上述架構如果要實作一個簡單的場景,比如畫面實時預覽和濾鏡處理功能,

1:需要選擇功能子產品,功能子產品包括攝像頭子產品、濾鏡處理子產品和Flutter畫面渲染子產品,

2:需要配置子產品參數,比如采集分辨率、濾鏡參數和前後攝像頭設定等,

3:在建立視訊管線後使用已配置的參數建立子產品

4:最後管線搭載子產品,開啟管線就可以實作這樣簡單的功能。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

上圖為整個功能實作的代碼和結構圖。

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

結合上述音視訊架構,閑魚實作了Flutter多媒體開源元件。

組要包含四個基本元件分别是:

1:視訊圖像拍攝元件

2:播放器元件

3:視訊圖像編輯元件

4:相冊選擇元件

現在這些元件正在走内部開源流程。預計9月份,相冊和播放器會實作開源。

後續展望和規劃

Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

1:實作開頭所說的從底層SDK到UI的全鍊路的跨端開發。目前底層架構層和子產品層都是各個平台各自實作,反而是Flutter的UI端進行了跨平台的統一,是以後續會将底層也按照音視訊常用做法把邏輯下沉到C++層,盡可能的實作全鍊路跨平台。

2:第二部分内容為開源共建,閑魚開源的内容不僅包括拍攝、編輯元件,還包括了很多底層子產品,希望有開發者在基于Flutter開發音視訊應用時可以充分利用閑魚開源出的音視訊子產品能力,搭建APP架構,開發者隻要去負責實作特殊需求子產品就可以,盡可能的減少重複勞動。

————————————————

版權聲明:本文為CSDN部落客「LiveVideoStack_」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

原文連結:

https://blog.csdn.net/vn9PLgZvnPs1522s82g/article/details/100165250
「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。
Flutter浪潮下的音視訊研發探索Flutter外接紋理OpenGLTPM 鹹魚Flutter多媒體開源元件後續展望和規劃

繼續閱讀