爲何要在這個時候探索flv.js作直播呢?緣由在於各大瀏覽器廠商已經默認禁用Flash,以前常見的Flash直播方案須要用戶贊成使用Flash後才能夠正常使用直播功能,這樣的用戶體驗很致命。html
在介紹flv.js以前先介紹下常見的直播協議以及給出我對它們的延遲與性能所作的測試得出的數據。
若是你看的很吃力能夠先了解下音視頻技術的一些基礎概念。react
RTMP: 底層基於TCP
,在瀏覽器端依賴Flash。git
HTTP-FLV: 基於HTTP
流式IO傳輸FLV,依賴瀏覽器支持播放FLV。github
WebSocket-FLV: 基於WebSocket
傳輸FLV,依賴瀏覽器支持播放FLV。WebSocket
創建在HTTP
之上,創建WebSocket
鏈接前還要先創建HTTP
鏈接。web
HLS: Http Live Streaming,蘋果提出基於HTTP
的流媒體傳輸協議。HTML5
能夠直接打開播放。npm
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 < HLS
而性能排序剛好相反:
RTMP > HTTP-FLV = WebSocket-FLV > HLS
也就是說延遲小的性能很差。緩存
能夠看出在瀏覽器裏作直播,使用HTTP-FLV協議是不錯的,性能優於RTMP+Flash,延遲能夠作到和RTMP+Flash同樣甚至更好。服務器
flv.js是來自Bilibli的開源項目。它解析FLV文件餵給原生HTML5 Video標籤播放音視頻數據,使瀏覽器在不借助Flash的狀況下播放FLV成爲可能。websocket
因爲瀏覽器對原生Video標籤採用了硬件加速,性能很好,支持高清。
同時支持錄播和直播
去掉對Flash的依賴
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只作了一件事,在獲取到FLV格式的音視頻數據後經過原生的JS去解碼FLV數據,再經過Media Source Extensions API 餵給原生HTML5 Video標籤。(HTML5 原生僅支持播放 mp4/webm 格式,不支持 FLV)
flv.js 爲何要繞一圈,從服務器獲取FLV再解碼轉換後再餵給Video標籤呢?緣由以下:
兼容目前的直播方案:目前大多數直播方案的音視頻服務都是採用FLV容器格式傳輸音視頻數據。
FLV容器格式相比於MP4格式更加簡單,解析起來更快更方便。
因爲目前flv.js兼容性還不是很好,要用在產品中必要要兼顧到不支持flv.js的瀏覽器。兼容方案以下:
優先使用 HTTP-FLV,由於它延遲小,性能也不差1080P都很流暢。
不支持 flv.js 就使用 Flash播放器播 RTMP 流。Flash兼容性很好,可是性能差默認被不少瀏覽器禁用。
不想用Flash兼容也能夠用HLS,可是PC端只有Safari支持HLS
優先使用 HTTP-FLV,由於它延遲小,支持HTTP-FLV的設備性能運行 flv.js 足夠了。
不支持 flv.js 就使用 HLS,可是 HLS延遲很是大。
HLS 也不支持就無法直播了,由於移動端都不支持Flash。
說了這麼多介紹與原理,接下來教你們如何用flv.js搭建一個完整的直播系統。
我已經搭建好了一個demo能夠供你們體驗。
主播推流到音視頻服務,音視頻服務再轉發給全部鏈接的客戶端。爲了讓你快速搭建服務推薦我用go語言實現的livego,由於它能夠運行在任何操做系統上。
下載livego,注意選對你的操做系統和位數。
解壓,執行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:
<img width="961" alt="screen shot 2017-06-07 at 5 41 32 pm" src="https://user-images.githubuse...
也可使用ffmpeg來推流,推流命令ffmpeg -f avfoundation -i "0" -vcodec h264 -acodec aac -f flv rtmp://localhost/live/test
按照上面的教程運行起來的直播延遲大概有3秒,通過優化能夠到1秒。在教你怎麼優化前先要介紹下直播運行流程:
主播端在採集到一段時間的音視頻原數據後,由於音視頻原數據龐大須要先壓縮數據:
經過H264視頻編碼壓縮數據數據
經過PCM音頻編碼壓縮音頻AAC數據
壓縮完後再經過FLV容器格式封裝壓縮後的數據,封裝成一個FLV TAG
再把FLV TAG經過RTMP協議推流到音視頻服務器,音視頻服務器再從RTMP協議裏解析出FLV TAG。
音視頻服務器再經過HTTP協議經過和瀏覽器創建的長連接流式把FLV TAG傳給瀏覽器。
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, }
這裏是優化後的完整代碼