前端串流媒體:MSE入門

2021-05-08 21:00:22

前言

串流媒體協定多種多樣,音視訊編碼格式更是繁多,要想在瀏覽器中正常瀏覽並非不容易。除開 WebRTC 這種瀏覽器已經支援的協定,HLS、FLV、RTSP、RTMP、DASH 等協定都需要預處理,不過流程大致都是:

  • 通過 HTTP、WebSocket 等方式獲取資料;
  • 處理資料,解協定、組幀等得到媒體資訊及資料;
  • 封裝成媒體片段,或解碼成一幀畫面;
  • 通過 video 或 canvas(WebGL)等進行播放。

目前市面上也有一些前端解碼的方案,如藉助 WASM 的高效能呼叫 c 解碼庫,或者直接使用瀏覽器的 WebCodecs API 進行編解碼......但都存在侷限性,WebCodecs 仍是實驗性功能;而 WASM 方案雖然突破瀏覽器沙盒限制(能播放瀏覽器不支援的編碼格式如H265等),但解碼和瀏覽器原始解碼之間仍有差距,並且由於只能走軟解導致多路效能也吃不消。所以,市面上更多的是採用另一種方式,解協定+封裝+這篇文章的主角 Media Source Extensions(以下簡稱MSE)。

開始

HTML5 規範允許我們直接在網頁中嵌入視訊,

<video src="demo.mp4"></video>

但 src 指定的資源地址必須是一個完整的媒體檔案,如何在 Web 做到流式的媒體資源播放?MSE 提供了這樣的可能性,先看下 MDN 對它對描述:

媒體源擴充套件 API(MSE) 提供了實現無外掛且基於 Web 的串流媒體的功能。使用 MSE,媒體串流能夠通過 建立,並且能通過使用 <audio> 和 <video> 元素進行播放。

正如上面所說,MSE 讓我們可以通過 JS 建立媒體資源,使用起來也十分方便:

const mediaSource = new MediaSource();

const video = document.querySelector('video');
video.src = URL.createObjectURL(mediaSource);

媒體資源物件建立完畢,接下來就是餵給它視訊資料(片段),程式碼看上去就像是:

mediaSource.addEventListener('sourceopen', () => {
  const mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
  const sourceBuffer = mediaSource.addSourceBuffer(mime);

  const data = new ArrayBuffer([...]);    // 視訊資料
  sourceBuffer.appendBuffer(data);
});

此時,視訊就可以正常播放了。要想做到流式播放,只需要不停的呼叫 appendBuffer 喂音視訊資料就行了......但不禁有疑問, 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"' 這段字串什麼意思?音視訊資料又要從哪來的?