目錄
-
說明
前段時間,我寫了一篇在angular框架下使用videojs播放RTMP視頻流的文章,雖然播放起來流暢度較好,但仍然有一個缺陷:
由於RTMP協議本身屬於Adobe公司且未開源,因而必須調用Flash才能播放並得到最好的支持,即使引入了video.js以及videojs-flash兩個庫作爲兼容並使用了HTML5中的<video>標籤,但實質仍然使用的是Flash播放器。在合併入項目過程當中帶來了一個問題,即angular框架屬於單頁應用程序(SPA),在瀏覽器端有很多微服務且大幅減少了網頁刷新(用戶按下F5)的頻率,所有的內容基本都在一個網頁當中進行展示,實際項目中由於使用了angular的RouterLink功能切換頁面,當有視頻播放且從有Flash播放器的組件(component)頁切換到其他組件頁後,再切回Flash的組件頁,會出現flash加載失敗的情況,必須進行網頁刷新(F5)才能正常重新加載Flash插件,這極大地降低了用戶體驗。我也沒有找到其他的解決方案。
同時,由於Flash本身的設計缺陷,Adobe公司和各大主流瀏覽器對Flash的支持也在減少甚至是直接移除了Flash插件,並趨向於採用原生HTML5標準中的<video>標籤進行替換來進行音視頻的播放。
因而,本着提高用戶體驗和便於後期維護的方針,通過查閱資料,我採用了當下比較流行的直播方案進行改造,該方案爲FFmpeg-nginx-Http-flv的組合。
-
總體思路
如下圖所示:
具體爲由FFmpeg拉取海康相機的RTSP流,通過轉換推出RTMP流,接着nginx主機模塊拉取這個RTMP流,通過轉換推出Http-flv流給瀏覽器中的flv.js包進行拉取播放。
下面我對這個方案的各個部分進行逐一的描述:
-
FFmpeg
FFmpeg拉取海康相機的RTSP流,只需要遵循海康相機的RTSP流拉取規範,即對於FFmpeg來說需要輸入輸出參數,一條完整的FFmpeg輸入輸出參數如下所示:
ffmpeg -i rtsp://admin:[email protected]:554/h264/ch1/main/av_stream -vcodec copy -acodec aac -ar 44100 -strict -2 -ac 1 -f flv -s 1280x720 -q 10 -f flv rtmp://127.0.0.1/Mylive/test
調出控制檯,轉到ffmpeg.exe程序所在的文件夾,輸入或貼入上述參數即可,admin改爲海康相機的登陸賬號,密碼改爲海康相機的登陸密碼。
對參數命令的部分解釋,其他參數設置可以參考FFmpeg官方參數說明:
參數 |
解釋 |
-i filename |
輸入文件 |
-f fmt |
強制採用格式fmt |
-vcodec (codec) (copy) |
-vcodec codec 強制使用codec格式編解碼方式,如-vcodec xvid 使用xvid壓縮 如果用copy表示原始編解碼數據必須被拷貝。 |
-acodec (codec) (copy) |
使用codec編解碼 如:-acodec AAC 使用AAC音頻編碼 |
-ar rate int |
設置音頻採樣率(單位:Hz),PSP只認24000 |
-strict strictness int |
遵循的嚴格標準等級(from INT_MIN to INT_MAX) |
-ac channels int |
設置聲道數,1就是單聲道,2就是立體聲,轉換單聲道的TVrip可以用1(節省一半容量),高品質的DVDrip就可以用2 |
-s size 1280x720 |
制定分辨率 |
-qscale int |
使用固定的視頻量化標度(VBR) 以<q>質量爲基礎的VBR,取值0.01-255,約小質量越好,即qscale 4和-qscale 6,4的質量比6高 。此參數使用次數較多,實際使用時發現,qscale是種固定量化因子,設置qscale之後,前面設置的-b好像就無效了,而是自動調整了比特率。 |
ffmpeg進入推流狀態:
-
Nginx
Nginx我使用的是未央千城大神的模塊方案——基於nginx-rtmp-module模塊實現的HTTP-FLV直播模塊nginx-http-flv-module,相較於已有的nginx-rtmp-module方案,其具有不少優勢,具體可以參閱他的博文,這裏是github地址。
在上面的FFmpeg環節已經對完整的FFmpeg輸入輸出參數進行了一個簡單的介紹。我們再來看看這條參數,紅色部分我未在上面作說明:
ffmpeg -i rtsp://admin:[email protected]:554/h264/ch1/main/av_stream -vcodec copy -acodec aac -ar 44100 -strict -2 -ac 1 -f flv -s 1280x720 -q 10 -f flv rtmp://127.0.0.1/Mylive/test
這部分是推給nginx主機的鏈接地址:
- rtmp:固定的前置格式;
- 127.0.0.1:IP地址,由於是測試環境,我的Nginx也部署在windows的本機,故用本地地址,這個地址根據實際情況進行修改,FFmpeg推流也通過這個IP地址以及下面的Mylive應用名稱進行nginx主機尋址來推給Nginx主機;
- Mylive:應用名稱;
- test:流名稱。
對應Nginx主機配置文件的幾個部分,用記事本打開nginx.conf進行文件:
worker_processes 4;
error_log logs/error.log error;
events {
worker_connections 1024;
}
rtmp_auto_push on;
rtmp_auto_push_reconnect 1s;
rtmp_socket_dir /tmp;
rtmp {
out_queue 4096;
out_cork 8;
max_streams 128;
timeout 10s;
server {
listen 1935;
#chunk_size 4096;
application Mylive {
live on;
gop_cache on;
}
application hls {
live on;
allow publish all;
allow play all;
hls on;
hls_path temp/hls;
hls_fragment 8s;
}
}
}
http {
server {
listen 8080;
location / {
root html;
}
location /live {
flv_live on;
chunked_transfer_encoding on; #支持'Transfer-Encoding: chunked'方式回覆
add_header 'Access-Control-Allow-Origin' '*'; #添加額外的HTTP頭
add_header 'Access-Control-Allow-Credentials' 'true';
}
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root html;
}
location /hls {
#server hls fragments
types{
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias temp/hls;
expires -1;
}
}
}
整個配置文件我們最關心的是這幾個參數:
- rtmp -> server -> listen 1935 #rtmp監聽端口,後面的flvjs需要該參數進行連接;
- rtmp -> server -> application Mylive #這個和上面的FFmpeg輸入輸出參數進行對應,後面的flvjs需要該參數進行連接;
- http -> server -> listen 8080 #http監聽端口,後面的flvjs需要該參數進行連接。
其他參數可以根據官方文檔自行調整。
-
flv.js
完成了前面FFmpeg和Nginx主機的搭建,我們就可以進行前端的呈現了,這裏我選擇的是由bilibili開源的flv.js庫:Github地址。
建立一個angular項目,在項目中引入flv.js庫:
npm install --save flv.js
在組件component中:
Html中加入video標籤:
<div style=" width: 1280px; height: 720px">
<video #videoelement id="videoElement" controls="controls" x5-video-player-fullscreen="true" x5-video-orientation="landscape" width="1280" height="720">Your browser is too old to support HTML5 video.</video>
</div>
<br/>
<div class="controls">
<button (click)="start()">開始</button> |
<button (click)="pause()">暫停</button> |
<button (click)="stop()">停止</button>
</div>
Typescript中引入flvjs對象並使用,值得注意的是flv.js已經對Typescript進行了適配,故直接引入即可:
import * as flvjs from 'flv.js';
title = 'app';
player: any;
flvPlayer: any;
ngOnInit(): void {
// 獲取DOM對象
this.player = document.getElementById('videoElement');
if (flvjs.default.isSupported()) {
// 創建flvjs對象
this.flvPlayer = flvjs.default.createPlayer({
type: 'flv', // 指定視頻類型
isLive: true, // 開啓直播
hasAudio: false, // 關閉聲音
cors: true, // 開啓跨域訪問
url: 'http://127.0.0.1:8080/live?port=1935&app=Mylive&stream=test', // 指定流鏈接
});
// 將flvjs對象和DOM對象綁定
this.flvPlayer.attachMediaElement(this.player);
// 加載視頻
this.flvPlayer.load();
// 播放視頻
this.flvPlayer.play();
}
console.log(flvjs.default.getFeatureList());
}
start(): void {
this.flvPlayer.play();
}
pause(): void {
this.flvPlayer.pause();
}
stop(): void {
this.flvPlayer.pause();
this.flvPlayer.unload();
// 卸載DOM對象
this.flvPlayer.detachMediaElement();
// 銷燬flvjs對象
this.flvPlayer.destroy();
}
這裏要特別說明的是在創建flvjs對象時的url連接,爲了能夠順利播放視頻,因此鏈接必須正確,這裏對鏈接中的參數進行說明:
完整鏈接:http://127.0.0.1:8080/live?port=1935&app=Mylive&stream=test
參數說明:
- 127.0.0.1:IP地址,由於Nginx運行在本地計算機上,故採用該IP;
- 8080:端口,該端口和Nginx主機中的http -> server -> listen端口一致;
- live?:固定直播格式;
- port=1935:端口,該端口和Nginx中的rtmp -> server -> listen端口一致;
- app=Mylive:該參數名稱和Nginx中的rtmp -> server -> application一致;
- stream=text:流名稱,該參數和FFmpeg推流中的test名稱一致。
上述參數除第3個外均可根據實際情況進行修改,但注意和FFmpeg、Nginx主機的對應。如果搭建完成無法顯示圖像,請首先檢查參數是否正確和一一對應。
-
效果展示
效果如下圖所示:
在windows環境下運行Nginx,延遲在3~4秒左右,並注意到有丟包的現象,這個可以通過後期參數進行優化;如果是在linux環境下運行Nginx,延遲會壓縮到1~2秒。該延時也和nginx-http-flv-module官方介紹的延時一致。
-
總結
本文介紹了FFmpeg-nginx-Http-flv的組合實現直播的方案,並將幾個“獨立的輪子”組裝在了一起,讓大家對這種比較主流的直播方案有一個比較直觀的認識,方便以後的定製和優化。
希望這篇文章對你有所幫助。也感謝這幾位造這幾個“輪子”的大神。同時也歡迎大家給我指正文中不正確的地方,謝謝。