web視頻播放一杆到底

前言

毫無疑問,如今是短視頻、直播的時代。視頻內容逐漸代替圖文形式成爲網友們獲取新鮮事物以及展示自個人一大媒介。隨着5G的到來,2020年屬於直播短視頻爆發式增加的一年,電商平臺也都涌入直播營銷的大風口,成爲了各自平臺引流轉化的關鍵。不論是用戶仍是開發者,咱們處於這個風口中。本文將帶你探索瀏覽器視頻播放的奧祕。javascript

視頻的構成

一個完整可播放的視頻文件是由視頻和音頻兩部分構成。視頻和音頻又有各自的封裝格式(容器)和編碼格式。html

編碼格式

常見的視頻編碼格式有:MPEG四、H.26四、H.265等。
常見的音頻編碼格式有:MP三、AAC、WAV等。java

封裝格式

常見的視頻封裝格式有:MP四、FLV、mov、AVI、RMVB等。linux

先理解幾個名詞

就是影像動畫中的最小單位的影像畫面。一幀就是一張靜止的圖像。視頻中的動畫就是由多幅連續的幀畫面構成。nginx

幀率

幀率是以幀爲單位的圖像在顯示器上出現的頻率,也叫幀速率,單位:赫茲(Hz)。簡單理解爲每秒播放圖片的數量。git

碼率

碼率是比特率的俗稱,是指每秒傳送的比特數。github

FFmpeg

FFmpeg是能夠用來記錄、轉換數字視頻和音頻的一套計算機程序。FFmpeg是在linux下開發,因此天生跨平臺。它對音視頻編碼格式的支持比較全面,能對視頻的各個組成部分進行編碼。web

H264

一般被稱之爲H.264/AVC;是由國際標準化阻止和國際電信聯盟共同提出的繼MPEG4以後的新一代數字視頻壓縮格式。採用H.264壓縮後的數據具備低碼率、高質量圖像、容錯能力強、網絡適應性強等優勢。算法

MP4

MP4是一中標準的數字多媒體容器格式;用於音頻、視頻的壓縮編碼,也能夠存儲字幕和靜止圖像,同時能以流的方式進行網絡傳輸。npm

fMP4(Fragmented MP4)

fMP4是基於MPEG-4 Part 12的流媒體格式,與MP4很類似。簡單來講fMP4區別與MP4最大的區別就是它能很好地適應流式播放。

瀏覽器播放視頻

video標籤播放

在瀏覽器播放視頻,可使用HTML5原生的video標籤。但其播放的格式使用必定限制的,目前video只支持三種格式WebM、Ogg、MP4。

  • WebM:WebM 文件使用 VP8 視頻編解碼器和 Vorbis 音頻編解碼器
  • Ogg :Ogg 文件使用 Theora 視頻編解碼器和 Vorbis音頻編解碼器
  • MP4:MPEG 4文件使用 H264 視頻編解碼器和AAC音頻編解碼器

上面三種能夠直接使用video播放:

<video id="video-box" src="//cloud.video.taobao.com/play/u/755731755/p/1/e/6/t/1/283631891407.mp4" controls width="400px" heigt="400px"></video>

在頁面初始化完成後,video標籤會將整個mp4文件下載到瀏覽器,完成後便可播放。可是當mp4文件較大時,緩存時間就比較長,播放體驗很差。固然也可使用video.js 來播放,這裏就不贅述了。

播放HLS流

HLSHTTP Live Streaming)是一個由Apple公司提出的基於HTTP的流媒體傳輸協議。視頻的封裝格式是TS,編碼格式是H.264/ACC,除了定義TS視頻文件自己,還定義了用來控制播放的m3u8文本文件。移動端大部分瀏覽器都支持,也就是說,你能夠在移動端瀏覽器直接使用vedio標籤直接加載一個m3u8文件播放視頻或者直播。但在PC端只支持蘋果的safari瀏覽器,其餘瀏覽器想播放須要引入第三方庫,如:hls.js

<script src="https://cdn.jsdelivr.net/npm/hls.js"></script>
<video id="video"></video>
<script>
  var video = document.getElementById('video');
  var videoSrc = 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8';
  if (Hls.isSupported()) {
    var hls = new Hls();
    hls.loadSource(videoSrc);
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED, function() {
      video.play();
    });
  }
</script>

播放HLS流的邏輯很簡單,首先根據提供的m3u8地址源經過HTTP請求獲取到一級index文件內容如:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=64000
500kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=774000
1000kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=887000
500kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7692000
1000kbps.m3u8

bandwidth 指定視頻流的碼率,每個 #EXT-X-STEAM-INF 的下一行是二級index文件的路徑,能夠是相對路徑或者是絕對路徑。請求到的二級文件內容如:

#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXTINF:10,
1000kbps-00001.ts
#EXTINF:10,
1000kbps-00002.ts
#EXTINF:10,
1000kbps-00003.ts
#EXTINF:10,
1000kbps-00004.ts
#EXTINF:10,

... ...
#EXT-X-ENDLIST

能夠從二級文件中讀取到ts文件的路徑,一樣能夠是相對路徑或者絕對路徑。 #EXTINF 表示每一個ts切片的時長。 #EXT-X-ENDLIST 是視頻結束標誌,若是有這個標誌也代表該流不是一個直播流。
HLS播放的優點:

  • 可使用http協議請求數據流
  • 能夠切換不一樣的碼率,實現無縫播放

劣勢:

  • 延遲較高,實時性差,通常延遲在10s以上,不適合作直播
  • ts文件切片小且多,對存儲和緩存都有必定的要求

播放FLV流

FLV(Flash Video)是一種網絡視頻格式,FLV只能基於flash播放,可是因爲flash存在不少安全問題已經被衆多廠商拋棄,如今咱們若是要在H5中播放flv格式的視頻流可使用Blibli的開源庫:Flv.jsflv.js 原理是解析視頻的flv流並實時轉換爲fmp4格式,再經過 Media Source Extension 餵給瀏覽器的 video 標籤。

<script src="flv.min.js"></script>
<video id="videoElement"></video>
<script>
    if (flvjs.isSupported()) {
        var videoElement = document.getElementById('videoElement');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url: 'http://example.com/flv/video.flv'
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();
        flvPlayer.play();
    }
</script>

基於Media Source Extensions播放視頻流

咱們常常在不少直播網站去看視頻,你有沒有注意到他們是用的什麼流?咱們去B站隨便找一個直播或者視頻打開控制檯查看播放器,你會發現 video 標籤的 src 竟然是 blob 開頭的一個 url 。在前面講FLV播放時,咱們提到了Media Source Extension ,本節將介紹這種基於MSE的直播方案。
image.png

Media Source Extensions 是什麼

媒體源擴展(Media Source Extensions,縮寫MSE)是一項W3C規範,MSE容許Javascript爲audio標籤和video標籤動態地構造媒體源。

藉助MSE的能力,咱們能夠將接收到的實時流經過 blob url 往video標籤中灌入二進制數據(如fmp4格式流),或者使用 canvas 來實現直播。

簡單實現

首先,判斷瀏覽器是否支持MediaSource:

const supportMediaSource = window.MediaSource &&
            typeof window.MediaSource.isTypeSupported === 'function' &&
            window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42c01f,mp4a.40.2"');

MediaSource支持狀況:
image.png
接下來新建 MediaSource 實例,並使用生成blob url 加到video標籤。而且監聽 sourceOpen 事件來判斷初始化完成。

const mediaSource = new MediaSource();
const video = document.querySelector('#video-box');
video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen',function(){
    // TODO
})

接下來咱們經過websocket獲取原始視頻流,處理後經過 SourceBuffer 餵給 mediaSource

const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
const ws = new WebSocket("wss://xxx.websocket.com");

ws.onopen = function(evt) { 
  console.log("Connection open ..."); 
  ws.send("fetch Data");
};

ws.onmessage = function(evt) {
  // 能夠在灌入數據前進行轉碼等操做
  sourceBuffer.appendBuffer(evt.data);
};

ws.onclose = function(evt) {
  console.log("Connection closed.");
};

經過MSE的方式咱們能夠將接收到的視頻或者音頻流進行端處理,配合WebWorker技術實現快速轉碼、支持多播,給咱們無限的想象空間。

H.265視頻播放

H.265是ITU-T VCEG繼H.264以後所制定的新的視頻編碼標準。H.265標準圍繞着現有的視頻編碼標準H.264,保留原來的某些技術,同時對一些相關的技術加以改進。新技術使用先進的技術用以改善碼流、編碼質量、延時和算法複雜度之間的關係,達到最優化設置。
可是因爲瀏覽器不支持H265格式的流,因此咱們沒法直接播放。這時候可使用MSE的方式在 sourceBuffer.appendBuffer(evt.data) 前將 evt.data 使用 libde265.js  等轉碼庫轉碼後給到sourceBuffer。或者使用業界成熟的播放器進行播放,如淘系的@ali/videox播放器。

總結

愈來愈多的廠商更加偏向於H.265的編碼格式,可是瀏覽器對該格式的支持度不友好的前提下咱們不得不進行轉碼。使用MSE方式在瀏覽器端轉碼,則能借助GPU提升效率和下降延遲。但仍是沒法兼容全部的PC或者移動端瀏覽器,這條路還須要咱們去繼續探索。5G給互聯網帶來的福利不只僅是在視頻、直播的爆發,我相信web端圖像視頻技術也將突破現有的技術瓶頸,WebAssembly、硬件編碼等圖像渲染技術也將愈來愈豐富。

參考

https://baike.baidu.com/item/ffmpeg
https://github.com/Bilibili/flv.js/
https://developer.mozilla.org/zh-CN/docs/Web/API/MediaSource

文章可隨意轉載,但請保留此原文連接。
很是歡迎有激情的你加入 ES2049 Studio,簡歷請發送至 caijun.hcj@alibaba-inc.com 。
相關文章
相關標籤/搜索