使用flv.js做直播

發表於2017-06-12

為什麼要在這個時候探索flv.js做直播呢?原因在於各大瀏覽器廠商已經預設禁用Flash,之前常見的Flash直播方案需要使用者同意使用Flash後才可以正常使用直播功能,這樣的使用者體驗很致命。

在介紹flv.js之前先介紹下常見的直播協議以及給出我對它們的延遲與效能所做的測試得出的資料。
如果你看的很吃力可以先了解下音視訊技術的一些基礎概念

常見直播協議

  • RTMP: 底層基於TCP,在瀏覽器端依賴Flash。
  • HTTP-FLV: 基於HTTP流式IO傳輸FLV,依賴瀏覽器支援播放FLV。
  • WebSocket-FLV: 基於WebSocket傳輸FLV,依賴瀏覽器支援播放FLV。WebSocket建立在HTTP之上,建立WebSocket連線前還要先建立HTTP連線。
  • HLS: Http Live Streaming,蘋果提出基於HTTP的流媒體傳輸協議。HTML5可以直接開啟播放。
  • RTP: 基於UDP,延遲1秒,瀏覽器不支援。

常見直播協議延遲與效能資料以下資料只做對比參考

傳輸協議 播放器 延遲 記憶體 CPU
RTMP Flash 1s 430M 11%
HTTP-FLV Video 1s 310M 4.4%
HLS Video 20s 205M 3%

在支援瀏覽器的協議裡,延遲排序是:
RTMP = HTTP-FLV = WebSocket-FLV
而效能排序恰好相反:
RTMP > HTTP-FLV = WebSocket-FLV > HLS
也就是說延遲小的效能不好。

可以看出在瀏覽器裡做直播,使用HTTP-FLV協議是不錯的,效能優於RTMP+Flash,延遲可以做到和RTMP+Flash一樣甚至更好。

flv.js 簡介

flv.js是來自Bilibli的開源專案。它解析FLV檔案餵給原生HTML5 Video標籤播放音視訊資料,使瀏覽器在不借助Flash的情況下播放FLV成為可能。

flv.js 優勢

  • 由於瀏覽器對原生Video標籤採用了硬體加速,效能很好,支援高清。
  • 同時支援錄播和直播
  • 去掉對Flash的依賴

flv.js 限制

  • FLV裡所包含的視訊編碼必須是H.264,音訊編碼必須是AACMP3, IE11和Edge瀏覽器不支援MP3音訊編碼,所以FLV裡採用的編碼最好是H.264+AAC,這個讓音視訊服務相容不是問題。
  • 對於錄播,依賴 原生HTML5 Video標籤Media Source Extensions API
  • 對於直播,依賴錄播所需要的播放技術,同時依賴 HTTP FLV 或者 WebSocket 中的一種協議來傳輸FLV。其中HTTP FLV需通過流式IO去拉取資料,支援流式IO的有fetch或者stream
  • flv.min.js 檔案大小 164Kb,gzip後 35.5Kb,flash播放器gzip後差不多也是這麼大。
  • 由於依賴Media Source Extensions,目前所有iOS和Android4.4.4以下里的瀏覽器都不支援,也就是說目前對於移動端flv.js基本是不能用的。

flv.js依賴的瀏覽器特性相容列表

flv.js 原理

flv.js只做了一件事,在獲取到FLV格式的音視訊資料後通過原生的JS去解碼FLV資料,再通過Media Source Extensions API 餵給原生HTML5 Video標籤。(HTML5 原生僅支援播放 mp4/webm 格式,不支援 FLV)

flv.js 為什麼要繞一圈,從伺服器獲取FLV再解碼轉換後再餵給Video標籤呢?原因如下:

  1. 相容目前的直播方案:目前大多數直播方案的音視訊服務都是採用FLV容器格式傳輸音視訊資料。
  2. FLV容器格式相比於MP4格式更加簡單,解析起來更快更方便。

flv.js相容方案

由於目前flv.js相容性還不是很好,要用在產品中必要要兼顧到不支援flv.js的瀏覽器。相容方案如下:

PC端

  1. 優先使用 HTTP-FLV,因為它延遲小,效能也不差1080P都很流暢。
  2. 不支援 flv.js 就使用 Flash播放器播 RTMP 流。Flash相容性很好,但是效能差預設被很多瀏覽器禁用。
  3. 不想用Flash相容也可以用HLS,但是PC端只有Safari支援HLS

移動端

  1. 優先使用 HTTP-FLV,因為它延遲小,支援HTTP-FLV的裝置效能執行 flv.js 足夠了。
  2. 不支援 flv.js 就使用 HLS,但是 HLS延遲非常大。
  3. HLS 也不支援就沒法直播了,因為移動端都不支援Flash。

flv.js實戰

說了這麼多介紹與原理,接下來教大家如何用flv.js搭建一個完整的直播系統。
我已經搭建好了一個demo可以供大家體驗。

搭建音視訊服務

主播推流到音視訊服務,音視訊服務再轉發給所有連線的客戶端。為了讓你快速搭建服務推薦我用go語言實現的livego,因為它可以執行在任何作業系統上。

  1. 下載livego,注意選對你的作業系統和位數。
  2. 解壓,執行livego,服務就啟動好了。它會啟動RTMP(1935埠)服務用於主播推流,以及HTTP-FLV(7001埠)服務用於播放。

實現播放頁

在react體系裡使用react flv.js 元件reflv 快速實現。
先安裝npm i reflv,再寫程式碼:

讓以上程式碼在瀏覽器裡執行。這是你還看不到直播,是因為還沒有主播推流。

  • 你可以使用OBS來推流,注意要配置好OBS:
  • 也可以使用ffmpeg來推流,推流命令ffmpeg -f avfoundation -i "0" -vcodec h264 -acodec aac -f flv rtmp://localhost/live/test

flv.js延遲優化

按照上面的教程執行起來的直播延遲大概有3秒,經過優化可以到1秒。在教你怎麼優化前先要介紹下直播執行流程:

  1. 主播端在採集到一段時間的音視訊原資料後,因為音視訊原資料龐大需要先壓縮資料:
    • 通過H264視訊編碼壓縮資料資料
    • 通過PCM音訊編碼壓縮音訊AAC資料
  2. 壓縮完後再通過FLV容器格式封裝壓縮後的資料,封裝成一個FLV TAG
  3. 再把FLV TAG通過RTMP協議推流到音視訊伺服器,音視訊伺服器再從RTMP協議裡解析出FLV TAG。
  4. 音視訊伺服器再通過HTTP協議通過和瀏覽器建立的長連結流式把FLV TAG傳給瀏覽器。
  5. flv.js 獲取FLV TAG後解析出壓縮後的音視訊資料餵給Video播放。

知道流程後我們就知道從哪入手優化了:

  • 主播端採集時收集了一段時間的音視訊原資料,它專業的叫法是GOP。縮短這個收集時間(也就是減少GOP長度)可以優化延遲,但這樣做的壞處是導致視訊壓縮率不高,傳輸效率低。
  • 關閉音視訊伺服器的I楨快取可以優化延遲,壞處是使用者看到直播首屏的時間變大。
  • 減少音視訊伺服器的buffer可以優化延遲,壞處是音視訊伺服器處理效率降低。
  • 減少瀏覽器端flv.js的buffer可以優化延遲,壞處是瀏覽器端處理效率降低。
  • 瀏覽器端開啟flv.js的Worker,多程式執行flv.js提升解析速度可以優化延遲,這樣做的flv.js配置程式碼是:

這裡是優化後的完整程式碼

相關文章