Web端實現RTC視訊特效的解決方案

語言: CN / TW / HK

需求

隨著 RTC 技術的發展,音視訊通訊的門檻降到了一個極低的標準。移動端、PC 端、Web 端、小程式,隨手拿起一個裝置就可以完成高質量的音視訊通話。而且伴隨著移動網際網路的發展(4G,5G),AI 技術的演進,人們對於音視訊通訊的需求不再停留在聽得見看得到,而是開始追求更多互動新穎的通訊方式,如美顏、道具、互動塗鴉等等。音視訊通訊方向的拓展層出不窮,尤其在 ToC 的場景。

從技術的角度來講,原生的視訊處理技術已經並不稀奇。很多類似於 OpenCV 這樣的庫早已將自己的人臉捕捉,影象處理等能力開源,新建一個工程呼叫不多的介面就可以實現一些簡單的視訊處理。然而 Web 端在這一塊卻始終落後原生,再厲害的前端技術在鼓吹效能的時候都只敢說接近原生,其瓶頸在此可見一斑(JavaScript 的設計初衷並不是執行速度)。

 

技術選型

 

 ActiveX 方案 

 

2000年左右,微軟為了打敗當時崛起的新興瀏覽器 Netscape,希望研發一個方案可以讓自己的龍頭產品 office 在 IE 上執行,這便是 ActiveX 技術。聽起來很夢幻的一項技術原生與瀏覽器的無縫互動。ActiveX 與 Office 的結合最終也確實遏制了 Netscape 的發展,讓 IE 瀏覽器在很長一段時間霸佔著主流的地位。

ActiveX 實際就是一個基於 COM 標準開發的 COM 元件,其通過在安裝的時候將自己的 GUID 配合安裝路徑寫入到登錄檔中,JavaScript 可以輕鬆通過 GUID 來載入到這個原生物件並通過簡單的點語法完成呼叫。由於是 COM 元件,介面呼叫居然是直接在記憶體間進行,與原生工程呼叫動態庫(DLL)無異。更離譜的是,ActiveX 支援原生的 UserControl 直接渲染在瀏覽器。MFC、QT、winform、WPF,主流的 Windows 介面開發框架都可以完成 ActiveX 的開發。(不得不承認,隨著移動網際網路的蓬勃發展,PC 上的開發技術開始式微了,這些名詞遠沒有 flutter、vue 等名詞來得耳熟能詳)。在使用 WPF 完成了一個 ActiveX 外掛的開發呼叫後我們大受震撼。就是這樣一個聽起來無所不能的方案,為什麼就變得如此冷門?答案是:安全性。

由於 ActiveX 的高許可權,高靈活性,使得它可以在使用者的 PC 上“為所欲為”。肆意操作新增或修改本地檔案內容、訪問登入資訊、在瀏覽器中直接執行外部可執行檔案等,光聽這些就讓人覺得毛骨悚然。在21世紀初,網際網路剛剛興起的年代,大家普遍沒搞明白計算機、網際網路是什麼的年代,不知道有多少遊戲賬號就因為使用者點選了允許載入 ActiveX 外掛而被盜。

所以 Chrome、Firefox 等瀏覽器開始逐漸拋棄對 ActiveX 的支援,就連微軟自己也在 Edge 中不再支援 ActiveX ,只有年老失修的 IE 還在頑強支援。然而可惜的是,IE 瀏覽器也已經停止維護,而且即將退出 Windows 系統預裝的名單。大勢所趨,ActiveX 的方案也註定被淹沒在技術發展的潮流中。

 

ActiveX 很好,尤其是銀行、政府等使用私有網路的單位,ActiveX 的安全性問題對他們來說似乎不那麼致命。然而我們不可能針對一個將死的技術來進行我們的新方案設計,或者說 ActiveX 會是我們特定場景下的備選方案,但永遠不可能成為我們的首選。

 WebAssembly 方案 

 

隨著 ActiveX 的沒落,急需有一個新的方案來補充原生與前端互動的需求,此時 WebAssembly 應運而生。

通過 Emscripten 即可將 C、C++、Rust 程式碼編譯為 WebAssembly,編譯獲得的 .wasm 檔案為一種可被 JavaScript 呼叫的位元組碼。

看到這些,這個方案是令人期待的,於是我們動手來搭建自己的 WebAssembly。目前比較成熟的支援 WebAssembly 框架有 Unity、QT 等,Unity 與 QT 編譯 WebAssembly 的過程都很簡單,可以輕易搭建出測試 Demo,且原生的介面也很好地渲染到了前端,不禁讓我想起 ActiveX 曾經的榮光!

接下來讓我們來調起攝像頭並做些簡單的視訊處理吧。滿懷期待寫好程式碼,嘗試在前端執行,無法完成。看了一眼 QT WebAssembly 的官網:

 

 

QtMultimedia 框架已經被確定無法在 WebAssembly 使用,連他們自身都還沒搞清楚哪些 Module 可用哪些不可用,在我們看來前路有數不清的“坑”。

 

為了保證安全性,WebAssembly 執行在沙盒環境,其許可權必然受限。我們開玩笑地聊到,對於開發者而言 WebAssembly 相對於 ActiveX 都像是一種退步(對使用者無疑是進步)。

 

本著科學嚴謹的態度,我們決定另闢蹊徑將這個方案驗證到底,由前端採集視訊,WebAssembly 做處理,以此來驗證其最終的可行性,以及網上所吹噓的接近原生的執行速度。

 

幸運的是 OpenCV 提供了 WebAssembly 的版本,正好可以供我們做一些簡單驗證。搭建原生工程,整合 OpenCV 的 C++ 版本,而 WebAssembly 版本的 OpenCV 其官方已經提供了測試地址,幫我們節省了不少工作。

以雙邊濾波為例,選取一組合適引數進行對比驗證,diameter 選取15,sigma 選取30。

 

WebAssembly 的表現如下:

圖片

視訊的幀率已經下降到了 4FPS(上下浮動),觀感已有明顯示卡頓。

原生上的表現如下:

圖片

視訊的幀率依然保持 16FPS(上下浮動),雖然體驗有所影響,但是該值依然滿足 RTC 傳輸要求(RTC 傳輸一般視 13~30FPS 為正常)。

繼續在原生上新增高斯濾波處理,選取高斯核長寬各為3,表現如下:

 

 

視訊的幀率依然保持在 14FPS(上下浮動),對效能影響可忽略,依然滿足 RTC 傳輸要求(RTC 傳輸一般視 13~30FPS 為正常)。

其他引數的表現大致與這組測試相同,起碼在特殊場景的視訊處理中 WebAssembly 的效能是遠低於原生。當然可能是 OpenCV 對 WebAssembly 的支援還不夠好,但是這組對比以及 WebAssembly 的許可權支援已經讓我們對其有些失望。

 WebSocket 本地連線方案 

這個方案並無系統的定義,其實現思路為以原生工程為 Server,前端通過 localhost 的埠與其互動,資料量小的可以用 HTTP(支援的瀏覽器更廣),資料量大的可以用 WebSocket(IE10以上)。對於 RTC,如果傳送在前端,則 WebSocket 可能需要承擔每秒數M的資料傳輸來將視訊幀從原生程序傳送到前端,前端還需要通過 WebGL 進行渲染。

雖然是在本地通訊,但溢位的採集幀率以及音視訊在兩個程序採集所可能導致的音畫同步問題都讓我們對其的表現表示擔憂,所以並未有過多嘗試。

 虛擬攝像頭方案 

 

多個方案都行不通,讓我們對 ActiveX 念念不忘。COM 在效能上有著其他方案所不具備的巨大優勢,其他方案或是效能不如原生或是鼓吹效能接近原生,而 COM 則是實實在在的原生效能。

 

圍繞 COM 進行一番調研,我們發現還有其他路徑可以滿足我們的需求,即 COM 元件結合 DirectShow 來將視訊傳送到模擬攝像頭,從而在採集層面完成偷天換日!如果這個方案可行,那麼最終的產品將不僅可以用於我們眼下的場景,所有使用 DirectShow 進行攝像頭呼叫的應用都將可以使用我們封裝的視訊處理技術。

 

搭建 COM 工程,封裝 AI 數字人形象的實現,呼叫 DirectShow 介面完成虛擬攝像頭註冊與視訊流傳遞,編寫批處理指令碼將我們的 COM 註冊到系統路徑。完成一系列工作,使用諸多攝像頭測試工具進行測試,效果出奇的好。

以下為使用 AR 面具處理後的虛擬攝像頭接入網易會議的效果:

圖片

 

圖片

最終方案

 

經過大量的方案驗證,我們決定以虛擬攝像頭的方案作為我們最終的方案,無論從效能還是耦合性來說,這個方案都是無可挑剔。

方案結構 

 

圖片

關鍵實現 

 

1. 首先我們新建一個動態庫工程命名 WebCamCOM,並使用 CoCreateInstance 與 RegisterFilter 等介面將我們的物件註冊為 DirectShow Filter。

2. 藉助 memoryapi.h 的介面來傳遞我們定義的資料,此處我們除了傳遞基本的視訊資料之外還額外傳遞了視訊長寬與時間戳的資訊。

3. 通過使用 CreateMutex 來保證記憶體共享時的訪問安全。

4. 新建另一個動態庫工程命名 SharedImageWrapper,對外只定義一個介面。

圖片

5. 根據 shouldRotate 入參來決定是否需要做垂直方向的翻轉(用於適配 Unity)。

6. 簡單處理 data 之後同樣通過 memoryapi.h 介面往我們定義好的 DirectShow Filter 傳遞視訊資料。

7. 上層整合 SendImage 介面即可以將採集的 RGB 資料傳送至 DirectShow。

8. 編寫批處理指令碼,使用 regsvr32 命令以管理員許可權將 WebCamCom 註冊至系統登錄檔。

 

問題 

 

1. Unity 對 Texture 的採集自下而上,直接使用其 data 會有上下顛倒的現象,故需要做一次垂直翻轉。

圖片

 

2. Unity 可選 OpenGL 渲染與 Direct3D 渲染,兩種渲染方式的 Texture 控制代碼解析需要用兩套介面。

 

OpenGL:

圖片

 

D3D:

圖片

展望

 

  • DirectShow 雖然是目前主流的操作攝像頭的框架,但是 Media Foundation 框架的使用已經成為趨勢,考慮未來將介面適配到 Media Foundation 框架(基於 USB 攝像頭驅動開發也是一個可行的方案)。

 

  • 目前視訊處理所支援的能力主要還是圍繞數字人形象、美顏、虛擬背景,基於現有的框架其實可以結合更多好玩的視訊處理技術進來。

 

  • 外掛本身可以結合 WebSocket(HTTP)的方案來開放一些介面,諸如美顏引數、數字人形象的外形,這樣前端可以默默完成對外掛的配置。

 

  • 外掛可以整合出實用的設定介面,可通過拖拖拽拽檢視預覽效果。

 

總結

 

本文介紹了網易在 PC Web 端視訊處理方案上的一些探究,從多個方面對比了一些可選方案的優劣,最終在虛擬攝像頭方案上大致闡述了實現思路。也許您不從事音視訊領域的開發,也許您對 PC 開發不以為意,希望本文可以給您一些不一樣的角度去認識這些技術。受限於篇幅,未對核心的 COM 元件機制做詳細介紹略有遺憾,大家如有興趣也可逆潮流來玩轉一下 PC 開發中的黑科技。

作者:

 
金傑,網易雲信客戶端開發工程師,從事音視訊能力及IM能力場景化開發五年有餘,偏愛移動端開發。