1. 程式人生 > 其它 >html5 播放 rtsp

html5 播放 rtsp

目前大多數網路攝像頭都是通過 RTSP 協議傳輸視訊流的,但是html並不標準支援 RTSP 流。除了 Firefox瀏覽器可以直接播放 RTSP 流之外,幾乎沒有其他瀏覽器可以直接播放 RTSP 流。Electron 應用是基於 Chromium 核心的,因此也不能直接播放 RTSP 流。

在藉助一定工具的情況下,可以實現在 Web 頁面上播放 RTSP 流。本文介紹的方法可以應用於傳統 Web 應用和 Electron 應用中,唯一的區別是將 Electron 應用的主程序當作傳統 Web 應用的伺服器。

目前已有 RTSP 播放方案的對比

既然是做直播,就需要延遲較低。當攝像頭掉線時,也應當有一定的事件提示。處於這兩點,對目前已有的已經實現、無需購買許可證的 RTSP 播放方案進行對比(處於原理階段的暫時不分析)。

基於 flv.js的 RTSP 播放方案

flv.js是 Bilibili 開源的一款html5 瀏覽器。依賴於 Media Source Extension 進行視訊播放,視訊通過 HTTP-FLV 或 WebSocket-FLV 協議傳輸,視訊格式需要為 FLV 格式。

伺服器端(主程序)

伺服器端採用 express + express-ws框架進行編寫,當有 HTTP 請求傳送到指定的地址時,啟動 ffmpeg 串流程式,直接將 RTSP 流封裝成 FLV 格式的視訊流,推送到指定的 WebSocket 響應流中。

import * as express from "express";
import * as expressWebSocket from "express-ws";
import ffmpeg from "fluent-ffmpeg";
import webSocketStream from "websocket-stream/stream";
import WebSocket from "websocket-stream";
import * as http from "http";

function localServer() {
    let app = express();
    app.use(express.static(__dirname));
    expressWebSocket(app, null, {
        perMessageDeflate: true
    });
    app.ws("/rtsp/:id/", rtspRequestHandle)
    app.listen(8888);
    console.log("express listened")
}

function rtspRequestHandle(ws, req) {
    console.log("rtsp request handle");
    const
stream = webSocketStream(ws, { binary: true, browserBufferTimeout: 1000000 }, { browserBufferTimeout: 1000000 }); let url = req.query.url; console.log("rtsp url:", url); console.log("rtsp params:", req.params); try { ffmpeg(url) .addInputOption("-rtsp_transport", "tcp", "-buffer_size", "102400") // 這裡可以新增一些 RTSP 優化的引數
.on("start", function () { console.log(url, "Stream started."); }) .on("codecData", function () { console.log(url, "Stream codecData.") // 攝像機線上處理 }) .on("error", function (err) { console.log(url, "An error occured: ", err.message); }) .on("end", function () { console.log(url, "Stream end!"); // 攝像機斷線的處理 }) .outputFormat("flv").videoCodec("copy").noAudio().pipe(stream); } catch (error) { console.log(error); } }

為了實現較低的載入時間,可以為 ffmpeg 新增如下引數:

  • analyzeduration 可以降低解析碼流所需要的時間
  • max_delay 資料上寫的具體作用不太記得了,效果沒有 analyzeduration 明顯

當然這個實現還比較粗糙。當有多個相同地址的請求時,應當增加 ffmpeg 的輸出,而不是啟動一個新的 ffmpeg 程序串流。

https://www.51220.cn 51220網站目錄

瀏覽器端(渲染程序)

示例使用vue框架進行頁面設計。

<template>
    <div>
        <video ref="player"></video>
    </div>
</template>

<script>
import flvjs from "flv.js";
export default {
    props: {
        rtsp: String,
        id: String
    },
    /**
     * @returns {{player: flvjs.Player}}
     */
    data () {
        return {
            player: null
        }
    },
    mounted () {
        if (flvjs.isSupported()) {
            let video = this.$refs.player;
            if (video) {
                this.player = flvjs.createPlayer({
                    type: "flv",
                    isLive: true,
                    url: `ws://localhost:8888/rtsp/${this.id}/?url=${this.rtsp}`
                });
                this.player.attachMediaElement(video);
                try {
                    this.player.load();
                    this.player.play();
                } catch (error) {
                    console.log(error);
                };
            }
        }
    },
    beforeDestroy () {
        this.player.destory();
    }
}
</script>

<style>
    .demo-video {
        max-width: 480px; 
        max-height: 360px;
    }
</style>