根据目前大多数网络摄像头都是通过 RTSP 协议传输视频流的,对于这个内容小编进行了相关内容的搜索和整理发现,在 HTML中 并不标准支持 RTSP 流,只有除了 Firefox 浏览器可以直接播放 RTSP 流之外,几乎没有其他浏览器可以直接播放 RTSP 流。那么今天小编就来和大家讲讲有关于:“如何实现 RTSP 视频播放?”这个问题吧!
Electron 应用是基于 Chromium 内核的,因此也不能直接播放 RTSP 流。在借助一定工具的情况下,可以实现在 Web 页面上播放 RTSP 流。本文介绍的方法可以应用于传统 Web 应用和 Electron 应用中,唯一的区别是将 Electron 应用的主进程当作传统 Web 应用的服务器。
目前已有 RTSP 播放方案的对比
既然是做直播,就需要延迟较低。当摄像头掉线时,也应当有一定的事件提示。处于这两点,对目前已有的已经实现、无需购买许可证的 RTSP 播放方案进行对比(处于原理阶段的暂时不分析)。
我对这四种方式都进行了实现,整体效果最好的还是第4种方案,占用端口少,延迟低,渲染速度快,而且离线事件易于处理。
基于 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 进程串流。
浏览器端(渲染进程)
示例使用 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 的摄像头,可以实现低延迟,低 CPU 占用,无花屏现象。由于涉及保密,这里就不放截图了。
同样的方法我播放了 9 个本地 1080p 的视频《白鹿原》,可以看一下这个效果。
播放效果非常好,完全没有卡顿和花屏,CPU 占用率也不高。
示例代码仓库: WhuRS-FGis/html5-rtsp 示例代码仓库:
总结
那么在这篇文章中我们就可以发现,对于“如何实现 RTSP 视频播放?”这个问题的解决还是比较简单的,那么今天有关于这方面的内容分享就到这里的!更多的内容都可以在W3Cschool中进行学习!