音視訊編解碼對于前端工程師是一個比較少涉足的領域,涉及到流媒體技術中的文本、圖形、圖像、音頻和視訊多種理論知識的學習,才能夠應用到具體實踐中,本團隊在多媒體領域深耕兩年多,才算是有一定産出,我們自研web播放器并支援h.265解碼,在碼率優化的大背景下(保持畫質不變情況下,應用圖像增強、roi區域檢測、智能場景分類和h265編解碼等多種技術能力,将碼流降低50%。達到減少帶寬成本,提升視訊服務QoE的目的),真正做到了h265解碼播放的全域覆寫。
播放器整體架構
我們播放器整體架構設計如下:

本文主要分享了我們基于WebAssembly實作H.265格式的解封裝、解碼和播放。
背景
H.265又稱HEVC(全稱High Efficiency Video Coding,高效率視訊編碼),是ITU-T H.264/MPEG-4 AVC标準的繼任者。相比H.264,H.265擁有更高的壓縮率,也就意味着同樣碼率(又稱比特率是指每秒傳送的比特(bit)數。機關為bps(Bit Per Second),比特率越高,每秒傳送資料就越多,畫質就越清晰),H.265的畫質會更清晰,更高的壓縮率就能使用更低的存儲和傳輸成本。
- 帶寬成本:在有限帶寬下H.265能傳輸更高品質的網絡視訊,理論上,H.265最高隻需H.264編碼的一半帶寬即可傳輸相同品質視訊。更低的帶寬可以更好的降低存儲及傳輸成本,并為未來基于短視訊及直播領域更多更複雜好玩的互動玩法做鋪墊。
-
轉碼成本:但是目前主流浏覽器均不支援H.265原生視訊播放,是以通常視訊生産端需要針對浏覽器做一次H.264視訊的轉碼來适配浏覽器端如PC場景的播放,而增加了轉碼成本。如在淘寶直播中,假設以每天5萬場直播計算,每場直播轉碼成本20元,一天就是100萬的轉碼成本。
為此,我們團隊對浏覽器端H.265視訊播放的可行性及相容性進行了一次探索,為移動端及PC端全量H.265做準備,也對浏覽器端視音頻處理、WebAssembly實踐進行一次深入的嘗試。
H.264 vs H.265
H.264是當下用的最為廣泛的視訊編碼格式,H.265标準圍繞着現有的視訊編碼标準H.264,保留原來的某些技術,同時對一些相關的技術加以改進。新技術使用先進的技術用以改善碼流、編碼品質、延時和算法複雜度之間的關系,達到最優化設定。H.265和H.264都是基于塊的視訊編碼技術,主要的差别在于編碼單元的大小以及一些編碼算法細節,H.265将圖像劃分為“編碼樹單元(coding tree Unit, CTU)”,而不是像H.264那樣的16×16的宏塊。根據不同的編碼設定,編碼樹單元的尺寸可以被設定為64×64或有限的32×32或16×16。一般來說區塊尺寸越大,壓縮效率就越好。具體的算法及相關細節這裡不具體展開了,還有一些其他的壓縮算法如因為H.265專利限制而生的開放編碼格式如AV1等,讀者可以參考其他相關文章。
如下圖,可以看到同樣主觀畫面品質,H.265(500K)僅需H.264(800K)一半左右的帶寬碼率。
浏覽器現狀
如下圖,因為H.265專利及硬解支援情況不完善的原因,主流現代浏覽器均不相容H.265編碼的視訊播放(Edge新版本以插件方式支援),但是因為Apple對H.265的支援(這裡作者認為這可能是一個很重要的标志,因為技術的發展很多時候不光是這個技術本身所決定的,而是很多因素共同作用的結果,商業也是其中很重要的一個因素),移動端ios safari在11.0版本以上支援原生播放。
想要在浏覽器端播放H.265視訊原生的
<video />
标簽沒有辦法支援,但是因為視訊格式本身是連續圖像畫面和音頻的集合,參考了chromium的源碼及video标簽内部的實作原理,可以通過
<canvas /> + Web Audio API
的結合來模拟實作一個虛拟的video标簽來實作播放器功能。
demo
因為直播流時效性的緣故,釋出了一個播放
H.265 mp4視訊(該視訊位址直接在浏覽器中播放隻有聲音而沒有畫面)的線上demo,讀者可以有一個直覺感受。
位址:
https://g.alicdn.com/videox/mp4-h265/1.0.2/index.html效果:
前期調研
視音頻基礎
因為前端領域對視訊領域的涉及場景不多,一個
<video />
标簽就可以滿足大部分場景,但是經曆了這幾年直播和短視訊的爆發,視訊的需求和功能也變得越來越複雜,開發之前閱讀了很多視音頻領域相關的書籍和文章,在此先對視音頻基礎進行一個簡單的介紹。
視訊中我們通常說的視訊的格式,比如 .mp4, .mov, .wmv, .m3u8, .flv 等等被稱為
container
。在一個視訊檔案中音頻、視訊資料是分開存儲的,使用的壓縮算法也不一樣。其中container作為容器主要包含了video資料、audio資料、metadata(用于檢索視音頻payload格式等資訊)。每個格式的封裝格式不一樣,比如FLV格式的基本單元是Tag,而MP4格式的基本單元是Box,輔助的meta資訊用于檢索找到對應的原始資料。
而平時聽到的H.264, H.265等視訊編碼标準被稱為
codec
(COmpress and DECompress )。一個視訊格式比如mp4可以使用任何标準化的壓縮算法,這些資訊都會被包含在一個視訊檔案的meta資訊中來告訴播放器該用什麼編解碼算法來播放。
用戶端播放器
一個傳統的用戶端播放器播放一個視訊流經過了如下各個環節:
拉取資料 => 解封裝 => 音視訊解碼 => 采樣/像素資料發送到裝置進行渲染。
對于流媒體,播放器用戶端通過拉流以資料源(音視訊流)為中心,進行管道式的傳輸。在此期間,對視訊流的讀取,轉換,分類,複制等一系列操作處理,以封裝的mp4流為例,需要對流進行解封裝、解碼、渲染等步驟:
浏覽器video标簽
在探究的過程中,為了了解主流浏覽器不支援H.265視訊播放的原因,以及浏覽器端實作播放器原理的了解,通過對Chromium浏覽器
官方文檔及video标簽實作源碼的閱讀,整理了一個流程圖。
可以看到浏覽器内部對視訊流播放的實作,在經過了PipelineController等資料傳輸管道的處理後利用FFmpeg軟解或者Gpu硬解之後交給視訊裝置及音頻裝置進行同步及渲染。其中H.265的視訊因為硬解支援情況不完善,軟解可能有性能風險,是以在chrome中被關閉了不支援,在chromium中可以通過參數打開。我們就依照這個思路,利用浏覽器提供的接口來實作一個模拟的video标簽。
設計過程
開發思路
開發思路按照從簡單到複雜的過程,對任務進行拆分,來完成H.265視訊點播及直播等各個場景的覆寫,以mp4短視訊出發完成播放流程,再覆寫直播場景,考慮如網絡抖動、記憶體控制等複雜因素,再針對直播m3u8等回放檔案進行播放并開發視訊seek、倍速等功能。
mp4播放=>flv播放=>hls播放=>加入seek、倍速等功能
可行性分析
- 思路:在最開始進行可行性分析時,參考結合了已有工具videoconverter.js和libde265.js對H.265視訊ffmpeg的編譯提取了hevc檔案及mp3音頻檔案在浏覽器端進行了播放。
- demo位址: https://sparkmorry.github.io/mse-learning/h265/
- 表現:将720P的mp4視訊進行視訊和音頻的分離,通過
繪制圖像,通過<canvas />
标簽播放音頻,畫面在Macbook Pro上Chrome浏覽器下在23fps左右。<audio />
- 問題:
- 不能達到解碼性能标準: 720P的視訊在Macbook Pro上僅在23fps左右,而原視訊是25fps,不能達到解碼性能标準,無法流暢播放。
- 無法做到音畫同步: 該方案因為直接提取了hevc裸流檔案,無法擷取視訊和音頻每幀的pts時間戳,無法做到嚴格的音畫同步。
- 解決方案:
- 性能:因為libde265.js是asm.js,通過對libde265.js開源庫的改造,打包WebAssembly測試性能情況
- 音畫同步:參考flv.js、hls.js等開源視訊庫的方案,根據曾經的實踐經曆,js在解封裝方面的性能能夠完成視訊流檔案解封裝,擷取每幀視訊、音頻播放的pts及原始資料交給解碼器進行解碼再渲染。
- 方案調整:
Web端H.265播放器研發解密播放器整體架構背景前期調研設計過程目前方案測試表現TODO未來展望參考後言
MP4點播流播放
- 思路:根據上一過程調整的解決方案,通過js對mp4流進行解封裝,因為音頻解碼的複雜度不高,也先用js進行解碼,僅将視訊解碼子產品用已有的三方子產品libde265并替換為wasm解決性能問題,音視訊解碼子產品都自身維護一段緩存區,負責存儲解封裝子產品傳過來的packet資料,解決音畫同步的問題。
- 表現:通過開源libde265實作的視訊解碼子產品,針對于720p的視訊流,平均解碼時間是45ms,不能滿足每一幀音頻播放時間間隔(40ms)。
- 問題:視訊解碼性能仍然不夠。
-
- 丢幀:保證了音頻同步,丢掉部分非參考幀,但損失了部分體驗。是以提升解碼性能和改善播放政策才能有可能滿足目前方案的可行性。提升解碼性能和改善播放政策。
- 提升解碼性能:用解碼性能更好的ffmpeg替換掉libde265。
- 改善播放流程:因為每個requestAnimationFrame循環任務都是同步的,邊解碼邊播放。引入用WebWorker線程。通過改善視訊解碼子產品,解碼器内部開啟循環解碼,當外部的視訊播放裝置需要播放下一幀時,直接從解碼器解碼完的幀緩存中讀取下一幀資料。實作了worker和主線程并行執行。
-
- https://static-assets.cyt-rain.cn/h265/index.html
- 設計流程
Web端H.265播放器研發解密播放器整體架構背景前期調研設計過程目前方案測試表現TODO未來展望參考後言
FLV直播流播放
- 思路:mp4視訊流暢播放,但在直播場景(如FLV視訊流)中,用戶端需要和服務端建立長連結,不斷接收流消息,借用FFmpeg本身對流媒體的支援,對視訊資料進行解封裝及解碼。
- 表現:無法編譯FFmpeg網絡庫,TCP無法建立連接配接。
- 無法編譯FFmpeg網絡庫:TCP建立連接配接建立Socket時報錯,Emscripten工具無法編譯TCP連接配接相關配置
codec不支援:FLV官方協定不支援H.265。
-
- 無法編譯FFmpeg網絡庫:主線程利用fetch方法進行拉流,放到FFmpeg自定義緩沖區進行解封裝及解碼。因為直播流長時間播放需要不停的開辟、釋放記憶體空間,采用環形的資料緩沖區。
- FLV官方協定不支援H.265:對FFmpeg及編碼端對H.265進行擴充,因為FFmpeg内部資料結構嵌套較深,替換js解封裝函數直接用FFmpeg的解封裝函數。
-
-
Web端H.265播放器研發解密播放器整體架構背景前期調研設計過程目前方案測試表現TODO未來展望參考後言
-
目前方案
播放流程
- 因為FFmpeg支援多種格式解封裝,隻需要在在主線程中通過浏覽器API(通常是fetch方法)拉取原始流資料并放到緩存中,等初始緩存到一個門檻值時開啟Worker進行解封裝及解碼;
- 在子線程(Worker)中通過主線程fetch方法觸發的資料回調接收資料存入環形緩沖區(記憶體環)中;
- 子線程将讀取到的音頻幀輸送到主線程中,通過Web Audio API緩存音頻資料,根據已解碼的視訊幀緩存隊列循環解碼保證緩存中一直緩存10幀rgba圖像資料;
- 主線程中canvas根據音頻播放回調的pts消費并渲染視訊圖像;
- 循環以上操作直到fetch接口傳回流已結束。
解碼器編譯
通過Emscripten工具可以把C語言編寫的FFmpeg庫編譯成wasm并在浏覽器中應用到視音頻解碼中。
我們的視訊解碼場景和通常的播放器一樣,通過依賴FFmpeg的通用接口來實作解封裝和解碼的工作。先通過emscripten編譯ffmpeg庫,再通過靜态庫的方式依賴到解封裝和解碼入口程式中。
測試表現
性能測試
測試視訊
因為flv直播視訊受時效性影響較大,拿720P高清的H.265 mp4視訊作為穩定輸入測試
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'https://gw.alicdn.com/bao/uploaded/LB1l2iXISzqK1RjSZFjXXblCFXa.mp4?file=LB1l2iXISzqK1RjSZFjXXblCFXa.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2mp41
encoder : www.aliyun.com - Media Transcoding
Duration: 00:01:00.10, start: 0.000000, bitrate: 907 kb/s
Stream #0:0(und): Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv, bt709, progressive), 1280x720, 854 kb/s, 25 fps, 25 tbr, 12800 tbn, 25 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 48 kb/s (default)
Metadata:
handler_name : SoundHandler
測試機器
- lenovo ThinkPad T430
- CPU: Intel(R) Core(TM) i5-3230M [email protected] x64處理器
- 記憶體: 8 GB
- 系統: windows 10
- MacBook Pro (Retina, 15-inch, Mid 2015)
- CPU: 2.2 GHz Intel Core i7
- 記憶體: 16 GB
- 系統: macOS 10.14.2
性能情況
- MBP下表現
decoder.wasm大小 | decoder.js大小 | 平均每幀解碼時長 | 記憶體占用 | cpu占用 |
---|---|---|---|---|
1.4M | 168K | 26.79ms | 27M | 17~25% |
-
針對兩個pc筆記本進行了測試,平均每幀解碼(包含yuv420轉rgba)時長在各個浏覽器的表現情況如下:
注:此處Native(原生)表示針對mac系統原生編譯的FFmpeg作為依賴的解碼器(相對不考慮具體如x86、arm等計算機架構的WebAssembly的跨平台方案而言)。
裝置 | Chrome | Safari | FireFox | Edge | Native |
---|---|---|---|---|---|
MacOS(i7) | 22.19ms | 24.77ms | - | 5.08ms | |
windows(i5) | 33.51ms | 36.74ms | 86.72ms | 未測試 |
意味着最高能提供720P高清視訊如下幀率視訊流暢播放的能力:
視訊基準 | ||||||
---|---|---|---|---|---|---|
37fps | 45fps | 40fps | 25fps | 196fps | ||
30fps | 27fps | 12fps |
可以看到這兩台機器中,在非高速運動等普通的如電商場景25fps幀率的高清720p視訊已經能達到生産環境的标準,但是距離原生的速度還有一定距離。
浏覽器相容性
主要用到了WebAssembly及WebWorker的支援,實際測試中主流浏覽器Chrome、Safari、Firefox、Edge均能通過相容性測試。
- WebAssembly
Web端H.265播放器研發解密播放器整體架構背景前期調研設計過程目前方案測試表現TODO未來展望參考後言 - WebWorker
Web端H.265播放器研發解密播放器整體架構背景前期調研設計過程目前方案測試表現TODO未來展望參考後言
TODO
目前的技術方案已經能在大部分機器的主流浏覽器上流暢的播放720P的高清直播流,但是在Edge浏覽器及性能稍差的機器上還是存在高清視訊解碼性能不能滿足流暢播放的風險,針對WebAssembly達到native速度的目标還有一定距離,尤其是彙編并行計算的支援,在視音頻及大規模資料進行中是很常見的性能優化政策,作者整理了幾個優化的方向,在未來還有更多探索的空間:
-
彙編
FFmpeg中解碼有較多利用彙編進行并行計算的優化,但是彙編指令是cpu specific的(比如x86指令和arm指令),而wasm是跨平台的基于棧的虛拟機。Emscripten不支援彙編的編譯,考慮用clang等llvm前端将FFmpeg的.c和彙編.asm檔案編譯成LLVM IR(LLVM Intermediate Representation),然後通過fastcomp或者其他後端來編譯測試。
-
硬解
FFmpeg3.3以上開始支援自動硬解探測,支援的硬體裝置根據不同作業系統及硬體會有不同的支援,具體參考:
https://trac.ffmpeg.org/wiki/HWAccelIntro 。因為wasm是跨平台的虛拟指令集,支援程度還要待進一步探究。 -
多線程
FFmpeg内部解碼有多線程來提高解碼性能,通過pthread可以支援跨平台的多線程支援的,但是如果不支援共享記憶體,則線程之間的資料傳輸會有很多性能消耗(深拷貝或者Transfered Object)。浏覽器端共享記憶體通過SharedArrayBuffer來實作,因為有安全隐患,大部分主流浏覽器關閉了SharedArrayBuffer、Chrome67+開始恢複。考慮到相容性多線程的支援還要再進行嘗試。
-
WebGL渲染
解碼平均時長中有4ms左右(15%)在yuv轉rgba上,通過WebGL可以用gpu加速圖像的計算,但是同時與WebGL的資料交換又會産生一定的性能損耗,需要再測試檢視性能結果
未來展望
通過H.265視訊播放将開源視音頻庫FFmpeg的能力及WebAssembly性能的優勢在浏覽器端視音頻處理上有了一次深入的嘗試。視訊作為一種多媒體形式,相比現有的文字、圖像、音頻都能有更生動及更豐富資訊的表現。尤其經過了直播和短視訊的爆發增長後,成為了一種基礎的多媒體形式,也是網絡及移動端手機性能等技術發展的展現。未來随着5G及更高性能的硬體裝置的發展會被更廣泛的應用到各個領域。浏覽器在這場視訊革命中也是不可或缺的一個環節,通過這次的探索,為未來浏覽器端擴充視音頻處理的通用能力提供了想象的空間,同時也在浏覽器端通過WebAssembly向native性能及能力靠近的路上做了一個落地的嘗試,雖然從測試情況看現在的表現還不如native,但是随着标準及技術的演進,為未來對性能要求比較高的圖形圖像及人工智能等相關方向在浏覽器端處理一定會漸漸被廣泛的應用起來,比如如下幾個方向:
-
擴充浏覽器端視訊播放能力
借助FFmpeg強大的編解碼能力,除了H.265視訊的播放,未來還可以在浏覽器端相容各種格式及編碼類型的視訊播放。如不同的編碼格式AV1、不同的容器格式mov格式等等。
-
擴充浏覽器端視音頻處理能力
借助FFmpeg及其他語言架構的現有能力,還可以在視音頻領域做更多複雜的操作如視訊濾鏡、視訊剪切、視訊格式轉換等功能,減少網絡傳輸及存儲的成本。
-
基于WebAssembly的高性能web應用
借助WebAssembly的跨平台優勢,可以将傳統的其他語言的開源架構如圖形相關開源庫OpenGL、SDL等的能力移植到浏覽器上來。借助性能上的優勢也可以将傳統的圖像、3D等運算能力要求較高的應用擴充到浏覽器端。
參考
- Chromium媒體元素源碼: https://github.com/chromium/chromium/tree/master/media
- WebAssembly: https://webassembly.org/
- 優秀的開源視音頻處理架構FFmpeg: https://www.ffmpeg.org/
- 基于LLVM編譯的WebAssembly打包工具集Emscripten: https://emscripten.org/index.html
- 基于WebAssembly的ogg播放器: https://github.com/brion/ogv.js
- 基于FFmpeg的簡單點傳播放器: https://github.com/leixiaohua1020/simplest_ffmpeg_player
後言
本文介紹了我們在Web端H.265播放器上研發的過程和進展,後續還有很多繼續優化和深入的點。對相關知識感興趣的同學歡迎溝通交流,附上我們前端團隊的介紹:
淘寶技術部内容與開放平台前端團隊是淘系核心的商業變革陣地,相對于橫向資源前端團隊,我們更深入在内容電商、音視訊技術領域,探尋創新商業模式及業界領先技術。
本團隊目前正火熱招聘中,歡迎有志之士加入!
直接聯系團隊負責人: 林晚 [email protected]