使用wfs.js庫播放音視頻

use html5 video tag with MSE for h264 live streaming

本編博客記錄桌面虛擬化移動端預研。

完整demo: https://github.com/MarkRepo/wfs.js

常見的直播方案有RTMP RTSP HLS 等等, 由於這些流都需要先傳輸到服務器,然後進行推流,延時比較大,RTMP可以優化到1s,hls延時最高,大概10s左右。

虛擬桌面要求延時能在100ms以內。經過google查找資料發現有以下幾種方案可以實現:

1. 用websocket 傳輸h264編碼數據,在瀏覽器中使用broadway開源庫進行解碼,調用html5 canvas繪製圖像。在github上有一個demo,經過測試,broadway解碼效率不高。(測試環境 chrome book)

參考: https://github.com/131/h264-live-player

2. 使用webRTC 進行點對點直播,找了一個demo,搭建了一個聊天室測試,延時效果大概在500ms左右,應該可以優化。webRTC的接口封裝的很好,只有三個接口。

demo: https://github.com/LingyuCoder/SkyRTC-demo   參考:https://segmentfault.com/a/1190000000436544

上面的demo有一個地方需要注意: 使用http服務無法獲取到視頻流,瀏覽器報錯,提示需要https服務。改成https服務之後,測試成功。

這個方案可行,但是需要自己去改webRTC的源碼,工作量比較大,所以沒有采用。

3. 使用MSE(Media Source Extension, 具體參考W3C標準)擴展實現 HTML5 video tag的流式直播。(最終採用的方案)

方案描述: 使用websocket 從服務端傳輸h264編碼數據到瀏覽器, 在瀏覽器端使用JS 解析h264數據 , 封裝成fMP4 fragment, 餵給media source 中的sourceBuffer, 瀏覽器video tag自動獲取sourceBuffer中的數據進行解碼渲染。 

最後實現的demo體驗效果良好,延時能達到100ms以內,使用筆記本軟解、硬解, chrome book 軟解表現都很完美,唯獨chrome book 硬解會緩衝一幀數據,是一個瑕疵, 不過這個缺點可以在服務器端多發一幀數據解決。(見後文)

下面主要記錄預研過程中出現的重要問題和解決方案:

 (1)解析h264數據,封裝fMP4 fragment。

  這一步比較複雜,由於之前沒有JS開發經驗,沒有選擇自己寫,在github找了一個開源實現。參考:https://github.com/ChihChengYang/wfs.js; 根據wfs.js搭建的直播方案,主要出現三個問題(只有第一個延時是wfs.js庫的問題,其餘是自己的問題):

(2)第一個是延時問題,延時很大,在3~5s左右

原因有兩個: 1. wfs.js庫中做了緩存,收到一定的數據之後才執行fMP4 fragment的封裝。

       2. chrome瀏覽器的解碼器默認不是以直播流的模式解碼視頻幀,所以會在解碼的時候緩存4幀數據。

解決方法:    1. 把wfs.js庫中的緩存去掉,每來一幀數據都執行fMP4 fragment的封裝

      2. 設置mvhd.duration = 0,如果有mehd的話,設置mehd.fragmentDuration = 0, 這樣chrome 會進入“low delay mode”, 不會緩存數據。

具體參考: https://stackoverflow.com/questions/36364943/frame-by-frame-decode-using-media-source-extension

      https://bugs.chromium.org/p/chromium/issues/detail?id=465324

(3)第二個就是解碼問題,解碼花屏

原因: 虛擬機spice服務端使用了websokify代理(python 寫的)。首先,這個代理服務器是流式的(出現數據幀被分割和合並的現象),瀏覽器端js沒有進行數據幀邊界的解析; 第二,代理緩衝區過小,導致數據幀被分割傳輸。

解決方法:1. 修改websokify代理的接收緩衝區大小。

        2. 在wfs.js庫中對收到的數據進行解析,一幀一幀的提交數據,封裝fMP4 fragment。

(4)第三是屏幕倒轉問題

原因: spice服務端發過來的h264數據就是倒的,在終端平臺,是由終端處理的。

解決方法: 利用css的畫面旋轉功能,以x軸爲旋轉軸, 旋轉180度。如:

<style type="text/css" media="screen">
video.rotate180{
  width:100%;
  height:100%;
  transform:rotateX(180deg);
  -moz-transform:rotateX(180deg);
  -webkit-transform:rotateX(180deg);
  -o-transform:rotateX(180deg);
  -ms-transform:rotateX(180deg);
  }
</style>

(5)關於chrome book硬解碼緩存一幀問題解決辦法

通過看chrome源碼 decoder部分,發現decoder處理幾個數據類型會直接flush緩衝區,所以可以在wfs.js每收到一幀數據,

就構造一幀這種類型的空數據,餵給video tag, 把緩衝的一幀flush出來,同時把播放時間縮短一半即可(否則會幀堵塞)。示例:

var copy2 = new Uint8Array(4);
copy2[0] = 0, copy2[1] = 0, copy2[2] = 1, copy2[3] = 10; //類型10,11 都可以,但是10可以兼容軟解     
this.wfs.trigger(Event.H264_DATA_PARSING, {data: copy2});

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章