使用flv.js做直播

為什麼要在這個時候探索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秒,瀏覽器不支持。

常見直播協議延遲與性能數據

以下數據只做對比參考

在支持瀏覽器的協議里,延遲排序是:

RTMP = HTTP-FLV = WebSocket-FLV < HLS

而性能排序恰好相反:

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,音頻編碼必須是AAC或MP3, 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依賴的瀏覽器特性兼容列表

    HTML5 VideoMedia Source ExtensionsWebSocket

  • HTTP FLV: fetch 或 stream

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,再寫代碼:

import React, { PureComponent } from react;import Reflv from reflv;export class HttpFlv extends PureComponent { render() { return ( <Reflv url={`http://localhost:7001/live/test.flv`} type="flv" isLive cors /> ) }}

讓以上代碼在瀏覽器里運行。這是你還看不到直播,是因為還沒有主播推流。

  • 你可以使用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配置代碼是:

{ enableWorker: true, enableStashBuffer: false, stashInitialSize: 128,}

這裡是優化後的完整代碼

閱讀原文
推薦閱讀:

為何直播越來越受青睞?
來瘋直播新高度:20億砸出互動綜藝——公會警句言猶在耳:只有三類直播平台能倖存!
我在嗶哩嗶哩直播3個月了,直播卻只有35粉,且能說是完全沒收入,而我很喜歡做這個,我改怎麼辦?
直播風口下的CDN行業,原快播技術團隊能否再造一個Uber?
花椒再入10億融資,直播行業進入「官子局」

TAG:音視頻 | flv | 直播 |