App下載

如何實(shí)現(xiàn) RTSP 視頻播放?HTML5 播放 RTSP 視頻案例分享!

猿友 2021-08-06 15:51:44 瀏覽數(shù) (7190)
反饋

根據(jù)目前大多數(shù)網(wǎng)絡(luò)攝像頭都是通過 RTSP 協(xié)議傳輸視頻流的,對(duì)于這個(gè)內(nèi)容小編進(jìn)行了相關(guān)內(nèi)容的搜索和整理發(fā)現(xiàn),在 HTML中 并不標(biāo)準(zhǔn)支持 RTSP 流,只有除了 Firefox 瀏覽器可以直接播放 RTSP 流之外,幾乎沒有其他瀏覽器可以直接播放 RTSP 流。那么今天小編就來(lái)和大家講講有關(guān)于:“如何實(shí)現(xiàn) RTSP 視頻播放?”這個(gè)問題吧!

Electron 應(yīng)用是基于 Chromium 內(nèi)核的,因此也不能直接播放 RTSP 流。在借助一定工具的情況下,可以實(shí)現(xiàn)在 Web 頁(yè)面上播放 RTSP 流。本文介紹的方法可以應(yīng)用于傳統(tǒng) Web 應(yīng)用和 Electron 應(yīng)用中,唯一的區(qū)別是將 Electron 應(yīng)用的主進(jìn)程當(dāng)作傳統(tǒng) Web 應(yīng)用的服務(wù)器。

目前已有 RTSP 播放方案的對(duì)比

既然是做直播,就需要延遲較低。當(dāng)攝像頭掉線時(shí),也應(yīng)當(dāng)有一定的事件提示。處于這兩點(diǎn),對(duì)目前已有的已經(jīng)實(shí)現(xiàn)、無(wú)需購(gòu)買許可證的 RTSP 播放方案進(jìn)行對(duì)比(處于原理階段的暫時(shí)不分析)。

我對(duì)這四種方式都進(jìn)行了實(shí)現(xiàn),整體效果最好的還是第4種方案,占用端口少,延遲低,渲染速度快,而且離線事件易于處理。

基于 flv.js 的 RTSP 播放方案

flv.js 是 Bilibili 開源的一款 HTML5 瀏覽器。依賴于 Media Source Extension 進(jìn)行視頻播放,視頻通過 HTTP-FLV 或 WebSocket-FLV 協(xié)議傳輸,視頻格式需要為 FLV 格式。

服務(wù)器端(主進(jìn)程)

服務(wù)器端采用 express + express-ws 框架進(jìn)行編寫,當(dāng)有 HTTP 請(qǐng)求發(fā)送到指定的地址時(shí),啟動(dòng) ffmpeg 串流程序,直接將 RTSP 流封裝成 FLV 格式的視頻流,推送到指定的 WebSocket 響應(yīng)流中。

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 優(yōu)化的參數(shù)
            .on("start", function () {
                console.log(url, "Stream started.");
            })
            .on("codecData", function () {
                console.log(url, "Stream codecData.")
             // 攝像機(jī)在線處理
            })
            .on("error", function (err) {
                console.log(url, "An error occured: ", err.message);
            })
            .on("end", function () {
                console.log(url, "Stream end!");
             // 攝像機(jī)斷線的處理
            })
            .outputFormat("flv").videoCodec("copy").noAudio().pipe(stream);
    } catch (error) {
        console.log(error);
    }
}

為了實(shí)現(xiàn)較低的加載時(shí)間,可以為 ffmpeg 添加如下參數(shù):

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

當(dāng)然這個(gè)實(shí)現(xiàn)還比較粗糙。當(dāng)有多個(gè)相同地址的請(qǐng)求時(shí),應(yīng)當(dāng)增加 ffmpeg 的輸出,而不是啟動(dòng)一個(gè)新的 ffmpeg 進(jìn)程串流。

瀏覽器端(渲染進(jìn)程)

示例使用 Vue 框架進(jìn)行頁(yè)面設(shè)計(jì)。

<template>
    <div>
        <video class="demo-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>

效果展示

用 Electron 頁(yè)面展示了 7 個(gè) Hikvison NVR 的攝像頭,可以實(shí)現(xiàn)低延遲,低 CPU 占用,無(wú)花屏現(xiàn)象。由于涉及保密,這里就不放截圖了。

同樣的方法我播放了 9 個(gè)本地 1080p 的視頻《白鹿原》,可以看一下這個(gè)效果。

播放效果非常好,完全沒有卡頓和花屏,CPU 占用率也不高。

示例代碼倉(cāng)庫(kù): WhuRS-FGis/html5-rtsp 示例代碼倉(cāng)庫(kù):

總結(jié)

那么在這篇文章中我們就可以發(fā)現(xiàn),對(duì)于“如何實(shí)現(xiàn) RTSP 視頻播放?”這個(gè)問題的解決還是比較簡(jiǎn)單的,那么今天有關(guān)于這方面的內(nèi)容分享就到這里的!更多的內(nèi)容都可以在W3Cschool中進(jìn)行學(xué)習(xí)! 

0 人點(diǎn)贊