根據(jù)目前大多數(shù)網(wǎng)絡攝像頭都是通過 RTSP 協(xié)議傳輸視頻流的,對于這個內(nèi)容小編進行了相關內(nèi)容的搜索和整理發(fā)現(xiàn),在 HTML中 并不標準支持 RTSP 流,只有除了 Firefox 瀏覽器可以直接播放 RTSP 流之外,幾乎沒有其他瀏覽器可以直接播放 RTSP 流。那么今天小編就來和大家講講有關于:“如何實現(xiàn) RTSP 視頻播放?”這個問題吧!
Electron 應用是基于 Chromium 內(nèi)核的,因此也不能直接播放 RTSP 流。在借助一定工具的情況下,可以實現(xiàn)在 Web 頁面上播放 RTSP 流。本文介紹的方法可以應用于傳統(tǒng) Web 應用和 Electron 應用中,唯一的區(qū)別是將 Electron 應用的主進程當作傳統(tǒng) Web 應用的服務器。
目前已有 RTSP 播放方案的對比
既然是做直播,就需要延遲較低。當攝像頭掉線時,也應當有一定的事件提示。處于這兩點,對目前已有的已經(jīng)實現(xiàn)、無需購買許可證的 RTSP 播放方案進行對比(處于原理階段的暫時不分析)。
我對這四種方式都進行了實現(xiàn),整體效果最好的還是第4種方案,占用端口少,延遲低,渲染速度快,而且離線事件易于處理。
基于 flv.js 的 RTSP 播放方案
flv.js 是 Bilibili 開源的一款 HTML5 瀏覽器。依賴于 Media Source Extension 進行視頻播放,視頻通過 HTTP-FLV 或 WebSocket-FLV 協(xié)議傳輸,視頻格式需要為 FLV 格式。
服務器端(主進程)
服務器端采用 express + express-ws 框架進行編寫,當有 HTTP 請求發(fā)送到指定的地址時,啟動 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 優(yōu)化的參數(shù)
.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);
}
}
為了實現(xiàn)較低的加載時間,可以為 ffmpeg 添加如下參數(shù):
- analyzeduration 可以降低解析碼流所需要的時間
- max_delay 資料上寫的具體作用不太記得了,效果沒有 analyzeduration 明顯
當然這個實現(xiàn)還比較粗糙。當有多個相同地址的請求時,應當增加 ffmpeg 的輸出,而不是啟動一個新的 ffmpeg 進程串流。
瀏覽器端(渲染進程)
示例使用 Vue 框架進行頁面設計。
<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 頁面展示了 7 個 Hikvison NVR 的攝像頭,可以實現(xiàn)低延遲,低 CPU 占用,無花屏現(xiàn)象。由于涉及保密,這里就不放截圖了。
同樣的方法我播放了 9 個本地 1080p 的視頻《白鹿原》,可以看一下這個效果。
播放效果非常好,完全沒有卡頓和花屏,CPU 占用率也不高。
示例代碼倉庫: WhuRS-FGis/html5-rtsp 示例代碼倉庫:
總結
那么在這篇文章中我們就可以發(fā)現(xiàn),對于“如何實現(xiàn) RTSP 視頻播放?”這個問題的解決還是比較簡單的,那么今天有關于這方面的內(nèi)容分享就到這里的!更多的內(nèi)容都可以在W3Cschool中進行學習!