1. 程式人生 > 其它 >web無外掛播放視訊之rtsp

web無外掛播放視訊之rtsp

前言:

作為一個從未接觸過實時流(直播流)的人,我之前對實時視訊一直沒有概念,而最近參與的專案剛好有視訊監控的需求,因此我對webs無外掛實時流的展示進行了學習及研究,以下案例均經過實踐(不足之處望指教)。

概念:

視訊有一個流的概念,所以稱流媒體。實時視訊的流很好理解,因為視訊是實時的,需要有一個地方不停地輸出視訊出來,所以整個視訊可以用流來稱呼。可惜視訊並不能直接輸出至web,如果可以的話,也就沒有我這篇文章了。現在攝像頭的實時視訊流普遍採用的是 RTSP 協議(普奧視,海康,大華),而web並不能直接播放 RTSP 的視訊流

1.RTSP知識:

RTSP是 TCP/UDP 協議體系中的一個應用層協議,跟 HTTP 處在同一層。RTSP 在體系結構上位於 RTP 和RTCP 之上,它使用 TCP 或者 RTP 完成資料傳輸。RTSP 實時效果非常好,適合視訊聊天、視訊監控等方向。所以我們就需要一層中間層,來將 RTSP 流轉成前端可以支援的協議,這也引申出了目前實時流技術的幾種方向:

RTSP -> RTMP

RTMP是屬於 Adobe 的一套視訊協議,這套方案需要專門的 RTMP 流媒體,並且如果想要在瀏覽器上播放,只能使用 Flash 播放器,無法直接使用 HTML5 的 video 標籤。它的實時性在幾種方案中是最好的,但是由於只能使用 Flash 的方案,所以在移動端和PC端就直接 GG 了(因為瀏覽器不在支援外掛是大勢所趨)。 這裡就大概展示一下 RTSP 流如何轉換成 RTMP ,我們使用 ffmpeg+Nginx+nginx-rtmp-module :

// 在 http 同一層配置 rtmp 協議的相關欄位
rtmp {
    server {
            
// listen 1935; //路徑 application test { //開啟實時流模式 live on; record off; } } }
//bash 上執行 ffmpeg 把 rtsp 轉成 rtmp,並推到 1935 這個埠上
ffmpeg -i "rtsp://xxx.xxx.xxx:xxx/1" -vcodec copy -acodec copy -f flv "rtmp://127.0.0.1:1935/live/"

這樣就得到了一個 RTMP 的流,我們可以直接用 VLC 或者 IINA 來播放這個流

RTSP -> HLS

HLS是蘋果公司提出的基於 HTTP 協議的的流媒體網路傳輸協議,它的工作原理是把整個流分成一個個小的基於 HTTP 的檔案來下載,每次只下載一些。HLS支援 iOS/Android/瀏覽器,通用性強。但是它的實時性差:蘋果官方建議是請求到3個片之後才開始播放。所以一般很少用 HLS 做為網際網路直播的傳輸協議。假設列表裡面的包含5個 ts 檔案,每個 TS 檔案包含5秒的視訊內容,那麼整體的延遲就是25秒。蘋果官方推薦的小檔案時長是 10s,所以這樣就會有30s(n x 10)的延遲,所以此方案就先不嘗試了

RTSP -> RTMP -> HTTP-FLV

HTTP-FLV 它集合了 HLS 的通用性和 RTMP 的實時性,可以做到在瀏覽器上用 HTML5 的 video 標籤,以較低的延時播放實時流。HTTP-FLV 依靠 MIME 的特性,根據協議中的 Content-Type 來選擇相應的程式去處理相應的內容,使得流媒體可以通過 HTTP 傳輸。除此之外,它可以通過 HTTP 302 跳轉靈活排程,支援使用 HTTPS 加密傳輸,也能夠相容支援 Android,iOS 等移動端。HTTP-FLV 本質上是將流轉成 HTTP 協議下的 flv 檔案,在 Nginx 上我們可以使用 nginx-http-flv-module 來將 RTMP 流轉成 HTTP 流。其實 flv 格式還是 Adobe 家的格式,原生 Video 標籤無法直接播放,不過我們有 bilibili 家的 flv.js,它可以將 FLV 檔案流轉碼複用成 ISO BMFF(MP4 碎片)片段,然後通過 Media Source Extensions 將 MP4 片段喂進瀏覽器。 在支援瀏覽器的協議裡,延遲排序是這樣的:RTMP = HTTP-FLV = WebSocket-FLV < HLS 而效能排序是這樣的:RTMP > HTTP-FLV = WebSocket-FLV > HLS,展示:

1.首先需要一個nginx 外掛:nginx-http-flv-module

2.在 nginx.conf 中進行一些新的配置:

// rtmp server
application myvideo {
      live on;
      gop_cache: on; #減少首屏等待時間
}

// http server
location /live {
      flv_live on;
}

3.使用ffmpeg 來推流,就是上面 RTMP 的命令

4.web使用 import flv.js 來播放

//web使用 flv.js,開啟實時模式,然後訪問這個 nginx 地址下的路徑即可
import flvJs from 'flv.js';

export function playVideo(elementId, src) {
  const videoElement = document.getElementById(elementId);
  const flvPlayer = flvJs.createPlayer({
    isLive: true,
    type: 'flv',
    url: src,
  });
  flvPlayer.attachMediaElement(videoElement);
  flvPlayer.load();
}

playVideo('#video', 'http://localhost:8080/live?port=1985&app=myvideo&stream=streamname')
如果如果對延遲有更高的要求,可以嘗試下面的操作:
1.可以可以配置 flv.js 的 enableStashBuffer 欄位,它是 flv.js 用於控制快取 buffer 的開關,關閉了之後可以做到最小延遲,但由於沒有快取,可能會看到網路抖動帶來的視訊卡頓。
2.可以嘗試關閉 nginx 的 http 配置裡的 gop_cachegop_cache 又稱關鍵幀快取,其意義是控制視訊的關鍵幀之間的快取是否開啟。