在angular框架下使用flv.js播放http-flv實時流直播視頻

目錄

說明

總體思路

FFmpeg

Nginx

flv.js

效果展示

總結


  • 說明

前段時間,我寫了一篇在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-nginx-Http-flv總體方案
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主機的鏈接地址:

  1. rtmp:固定的前置格式;
  2. 127.0.0.1:IP地址,由於是測試環境,我的Nginx也部署在windows的本機,故用本地地址,這個地址根據實際情況進行修改,FFmpeg推流也通過這個IP地址以及下面的Mylive應用名稱進行nginx主機尋址來推給Nginx主機;
  3. Mylive:應用名稱;
  4. 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;  
        }  
    }
}

整個配置文件我們最關心的是這幾個參數:

  1. rtmp -> server -> listen 1935 #rtmp監聽端口,後面的flvjs需要該參數進行連接;
  2. rtmp -> server -> application Mylive #這個和上面的FFmpeg輸入輸出參數進行對應,後面的flvjs需要該參數進行連接;
  3. 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

參數說明:

  1. 127.0.0.1:IP地址,由於Nginx運行在本地計算機上,故採用該IP;
  2. 8080:端口,該端口和Nginx主機中的http -> server -> listen端口一致;
  3. live?:固定直播格式;
  4. port=1935:端口,該端口和Nginx中的rtmp -> server -> listen端口一致;
  5. app=Mylive:該參數名稱和Nginx中的rtmp -> server -> application一致;
  6. stream=text:流名稱,該參數和FFmpeg推流中的test名稱一致。

上述參數除第3個外均可根據實際情況進行修改,但注意和FFmpeg、Nginx主機的對應。如果搭建完成無法顯示圖像,請首先檢查參數是否正確和一一對應。

  • 效果展示

效果如下圖所示:

在windows環境下運行Nginx,延遲在3~4秒左右,並注意到有丟包的現象,這個可以通過後期參數進行優化;如果是在linux環境下運行Nginx,延遲會壓縮到1~2秒。該延時也和nginx-http-flv-module官方介紹的延時一致。

  • 總結

本文介紹了FFmpeg-nginx-Http-flv的組合實現直播的方案,並將幾個“獨立的輪子”組裝在了一起,讓大家對這種比較主流的直播方案有一個比較直觀的認識,方便以後的定製和優化。

完整資源地址

希望這篇文章對你有所幫助。也感謝這幾位造這幾個“輪子”的大神。同時也歡迎大家給我指正文中不正確的地方,謝謝。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章