03.05 珍稀乾貨!阿里 Web 音視頻開發趟坑指南

珍稀乾貨!阿里 Web 音視頻開發趟坑指南

作者 | 阿里文娛前端技術專家 歸影

出品 | CSDN(ID:CSDNnews)

這不是一篇基於MSE開發Web播放器的入門文章,而是圍繞Web播放器開發遇到的常見問題與解決方案,畢竟入門文章常有而趟坑乾貨不常有。如果您有Web播放開發經驗和音視頻技術基礎,讀起來會更有共鳴。

珍稀干货!阿里 Web 音视频开发趟坑指南

Web播放器開發基礎知識

先介紹Web播放器開發的一些基礎知識。有人要問了,Web播放器開發難道不是一個video標籤就夠了麼?非也!

1、瀏覽器Video支持的格式非常有限

在W3C的標準裡面Video只支持MP4格式 準確的說是ISOBMFF(Fragment MP4)。當然chrome支持WEBM,safari支持HLS(MPEG-TS)這都是自家的私有實現,做不得數。

2、瀏覽器Video無法逐個加載視頻切片

現在主流的流媒體點播/直播技術,都會把視頻切片。而video標籤src只能掛載整個MP4資源。沒法逐個的加載視頻分段。

所以我們的主角出場—— MediaSource Extenstion,簡稱MSE,是一套能不斷的把音視頻二進制數據塞給video標籤播放的API。

珍稀干货!阿里 Web 音视频开发趟坑指南

圖1:MSE簡明結構

MSE內部可以創建一系列的sourcebuffer,一般是一個音頻buffer,一個視頻buffer。把MSE做成blob url之後綁定給video的src。然後就可以通過appendBuffer往video裡追加音視頻數據了。有了MSE,播放器器的整體結構是什麼樣的呢,見下圖。

珍稀干货!阿里 Web 音视频开发趟坑指南

圖2:Web播放器簡明結構

首先在瀏覽器層面,主要使用video標籤、MSE、XHR 和UI。那麼播放器主要由Manager驅動加載視頻的playlist(比如HLS裡的m3u8,dash裡的MPD,FLV雖然不是playlist概念,但是是原理上差別不大,都是為了拿到視頻的一個個的片段的地址),並通過數據服務加載這一個個的分片。然後通過transmuxer也就是所謂的轉封裝器,把分片的封裝格式比如TS拆開(demux) 把連原始的音視頻數據解出來,再重新打包成fmp4(remux),最後通過MSE API餵給video標籤裡,讓video去播放。

因此播放器所做的事情最主要有兩點:

1) 轉封裝。即將video不支持的封裝格式轉碼成video所支持的封裝格式;

2) 如何驅動整個播放進行。即決定何時下載下一個分片,何時需要解碼插入到video的buffer裡。

珍稀干货!阿里 Web 音视频开发趟坑指南

時間戳對齊

轉封裝除了的封裝格式的解複用(demux)和再複用(remux)之外最重要的環節就是分片的時間戳對齊策略,以及音視頻同步。

珍稀干货!阿里 Web 音视频开发趟坑指南

圖3(傳說中的“開局一張圖 原理全靠猜”)

簡單講一下上圖:紅色代表音頻的時間軸。藍色/青色是視頻的時間軸。PTS(Presentation Time Stamp) 指的是這一幀需要渲染的時間。 DTS(Decoding Time Stamp) 指的是這一幀需要解碼的時間。

1、首片首幀的對齊策略

正常來說音頻PTS和DTS是一樣的,而視頻如果有B幀的話DTS往往要比PTS早一些(因為要預留一定的時間解碼)。因此視頻的首幀會有一個洞(gap/shift隨便你怎麼叫),如果不經處理插到video裡,那麼video裡的buffer也會呈現出一小段的洞,一般是0.08s(比如10s的分片 插進去可能出現0.08~10.08的情況)。現在主流的做法是削掉這個洞。就是把DTS跟PTS強行拉平,一般來說chrome 不會出現太大的問題。但是safari不行,如果不預留一定的DTS/PTS偏移,safari前兩幀的播放會明顯卡頓。

2、後續對齊策略後續分片的對齊,會通過DTS/PTS兩個尾部指針來做。如果發現後續分片時間軸有間隔就往前推從而填上間隔。如果發現重疊,就把重疊幀後移。這樣雖然會導致後續分片的前幾幀重疊。但在播放的過程中幾乎沒有影響。

珍稀干货!阿里 Web 音视频开发趟坑指南

音視頻同步

首先,什麼情況下會導致音畫不同步?

1、視頻源流壓根沒對齊。

沒救了,看下一點。

2、還是因為有洞。很多時候視頻切出來的每個分片之間都不一定是嚴絲合縫的,分片間的音視頻時間戳可能有洞。而且對於TS由於音頻每一幀的duration(≈23ms) 跟視頻每一幀的duration(40ms@25fps) 無法吻合(整除) 所以加劇了這種參差不齊的情況。那麼,重點來了!chrome有個特殊的機制,如果發現音頻之間有洞之後,為了保證音頻的平順,會自動把後續音頻往前推抹平這個洞。如果每個分片都有洞,悲劇了,這種往前推的操作就會積累越來越多導致音視頻不同步。

小tips:

打開chrome的媒體調試頁面 chrome://media-internals 可以看到媒體播放相關的所有debug信息和error信息非常有用。其中就會有一條關於音頻處理的提示:

珍稀干货!阿里 Web 音视频开发趟坑指南

當然這條顯示的具體原因是自動切掉重疊overlap導致的。其實gap/overlap本質是一樣的。怎麼辦?當然是播放器自己主動把洞填上。具體做法是插幀。目前主要是插靜音幀,或者複製前一幀。靜音幀會帶來毛刺音,複製幀會導致拖音。我們目前的優化方案是判斷附近的音頻數據量,數據量大時說明此處聲音豐富(其實不算靠譜,姑且這麼處理,因為沒有更好的判斷方式),如果插靜音幀會毛刺很明顯,所以此時用複製幀,反之插靜音幀。

珍稀干货!阿里 Web 音视频开发趟坑指南

那些年我們趟過的坑

1、 不同版本表現差異 容忍度不同

1) Chrome 35分水嶺。chrome35之前要求關鍵幀之後的第一幀dts不允許跟關鍵幀dts相同,否則拋錯。

2) 低延遲的模式。把轉封裝出來的FMP4中的視頻軌duration(tkhd box) 設置成0xffffffff 時會讓chrome認為這是直播流,會開啟低延遲模式,所謂低延遲模式就是會極大的減少幀緩存,基本上視頻幀立馬解碼立馬播放減少每個分片的起播延遲。但是呢在CPU負載過高的情況下(解不過來)會造成視頻頻繁卡頓(網絡無關的)。

2、 不同瀏覽器表現有差異

1) timeupdate事件。W3C的標準是不能超過250ms觸發一次。windows下360等瀏覽器會達到500ms左右。

2) safari對每一幀duration平順度更敏感。safari需要對每一視頻幀的duration標準化處理,例如TS下要處理成3600。

3) 對洞的容忍度不同。chrome遇到buffer中有0.08的間隔以內會自動跳過去。像IE edge等瀏覽器不行會卡住,所以播放器一定要有跳洞邏輯。比如判斷當前卡在洞的邊界,要主動跳過去(seek)。

3、內存限制

通過MSE push給video的視頻數據會在內部維護一個buffer,這個尺寸是有限制的。

1) chrome系列約100M

2) IE系列約30M

超過的話就會導致拋出 QuotaExceededError 。所以需要處理好buffer的尺寸以及及時清除不用的buffer。比如已經播放過的,正常瀏覽器會自己清除,但是不那麼的及時。

珍稀干货!阿里 Web 音视频开发趟坑指南

優化

簡單說一下卡頓相關的優化。

  • 多級Buffer控制

  • ABR 自適應碼率算法

  • 基於WebRTC的P2P

1、多級buffer

為什麼要有多級的buffer?因為video本身的解碼buffer有大小限制,而且buffer過長會導致長時間解碼,會導致CPU一直佔用高。所以我們搞了兩級buffer一級就是video的buffer另外一級是內存中的,只負責下載,二級很長。可以消除網絡抖動帶來的卡頓影響。

2、ABR自適應碼率的算法

這個主要是來預測用戶本身的帶寬範圍,然後選用不同碼率的視頻流來無縫切換播放。當然還有一些策略算法,比如根據用戶現在buffer的水位,或者檢測到用戶頻繁超時,來採用不同的策略。

3、基於WebRTC的P2P ‍‍

因為P2P是基於UDP的傳輸,可以突破一些帶寬限制或網絡擁塞而導致的卡頓問題。不過P2P不一定靠譜所以還是要輔以普通的HTTP傳輸相結合。我們一般是利用P2P加indexDB 來變相延長視頻的緩衝區。因為P2P帶寬成本便宜,我們利用P2P做了一個非常長又很便宜的buffer。這樣的話網絡再波動也不會導致卡頓了。


分享到:


相關文章: