解决RTSP推流前端切换视频导致播放黑屏频闪问题
背景
供应商那边设备类似于摄像头,推送的视频流格式是rtsp
格式,需要进行转换到前端播放。
实现效果是摄像头在前端页面展示类似实时视频直播,问题是一个页面有多个视频源,在多个源进行切换时会导致视频画面黑屏频闪
。
复现
前提条件
- 两个视频文件
*.mp4
- nodejs
- ffmpeg及配置环境变量
客户端web页面
1.依赖准备
前端播放视频流需要导入jsmpeg-player
packages.json
...
"dependencies": {
"axios": "^1.4.0",
"element-plus": "^2.3.5",
"jsmpeg": "^1.0.0",
"jsmpeg-player": "^3.0.3",
"vue": "^3.2.47"
},
...
App.vue
<script setup>
import { ref, watch, getCurrentInstance } from "vue";
import JsMpeg from "jsmpeg-player";
const ws = ref(null);
const { proxy } = getCurrentInstance();
const videoObject = ref({}); // 用于存储当前正在播放的视频数据
/**
* 视频的url构成规则为: rtsp://本机IP/自定义地址标识,后续将通过ffmpeg将对应视频转换为RTSP流,并通过TCP传输于该地址。
* 视频的port意义为: 不同的端口对应不同的视频,RTSP流通过TCP传输的地址前端不能直接对接,会将url发送给服务端,服务端进行接入后再于该端口进行ws推送。
*/
const videoList = [
{
label: "视频1-一人之下",
name: "sp1",
url: "rtsp://192.168.0.107/test",
port: 8834,
},
{
label: "视频2-小猫咪",
name: "sp2",
url: "rtsp://192.168.0.107/test2",
port: 8812,
},
];
// ...
</script>
2.页面准备
重要:视频推流的展示是需要canvas标签,但是一个canvas标签多次复用就会导致黑屏频闪问题!!!
所以将dom中的canvas标签移除,修改为每次点击按钮播放都动态创建一个canvas标签
<template>
<el-button
v-for="item in videoList"
:key="item.name"
@click="playerVideo(item)"
>{{ item.label }}</el-button
>
</template>
<style scoped></style>
3.播放实现
const useWs = (data) => {
// 建立一个新的ws视频流播放时先对旧的ws视频流进行释放
if (ws.value) ws.value.close();
// 移除所有canvas
const canvasList = document.querySelectorAll("canvas");
canvasList.forEach((item) => {
item.remove();
});
// 追加一个canvas#sp
const sp = document.createElement("canvas");
sp.setAttribute("id", "sp");
document.body.appendChild(sp);
// 与服务端建立ws通信,并未开始播放
ws.value = new WebSocket("ws://localhost:5001");
videoObject.value = data;
};
// 向服务端发送信息是通过watch监听实现,当videoObject发生变化时调用,即当前视频对象切换
watch(
() => videoObject.value,
(newV, oldV) => {
// 当ws连接打开时回调
ws.value.onopen = function () {
// 向服务端发送欲播放的视频数据,服务端接收后会进行推流
ws.value.send(JSON.stringify(newV));
// 使用框架 建立ws视频流播放,不同的端口对应不同的视频。
new JsMpeg.Player(`ws://localhost:${newV.port}`, {
canvas: document.getElementById('sp'),
});
};
}
);
const playerVideo = (e) => {
useWs(e);
};
服务端node实现
重要:ffmpeg环境变量的配置+运行目录放一个ffmpeg.exe
1.依赖准备
packages.json
"dependencies": {
"express": "^4.18.2",
"node-ffmpeg-stream": "^1.1.0",
"node-rtsp-stream": "^0.0.9",
"node-rtsp-stream-jsmpeg": "^0.0.2",
"ws": "^8.13.0"
},
index.js
const Stream = require('node-ffmpeg-stream').Stream;
const WebSocket = require('ws');
const ws = new WebSocket.Server({ port: 5001 });
const streams = new Map(); // 存储视频流的 Map
2.端口推流
ws.on('connection', (client) => {
client.on('message', (msg) => {
const data = JSON.parse(msg);
console.log('开始播放');
// 下面固定格式
const stream = new Stream({
name: data.name,
url: data.url, // eg: rtsp://192.168.0.107/test
wsPort: data.port, // eg: 8834
options: {
'-stats': '', // 没有必要值的选项使用空字符串
'-r': 30, // 具有必需值的选项指定键后面的值<br>
}
});
streams.set(data.name, stream);
// 前端视频流切换时 + 页面刷新或关闭时触发,通知服务端停止推送当前流
client.on('close', () => {
if (streams.has(data.name)) {
const stream = streams.get(data.name);
stream.stopStream();
streams.delete(data.name);
console.log('连接已关闭');
}
});
});
});
ffmpeg转换流并进行传输
这段代码使用 ffmpeg
工具来将本地的视频文件(test.mp4
)转换为 RTSP 流,并将其通过 TCP 传输。
让我逐行解释这段代码的含义:
ffmpeg -stream_loop -1 -re -i "C:\Users\Administrator\Downloads\Video\test.mp4" -rtsp_transport tcp -vcodec h264 -f rtsp rtsp://localhost/test
ffmpeg
: 这是命令行中调用ffmpeg
工具的命令。-stream_loop -1
: 这个选项告诉ffmpeg
无限循环输入文件。即使视频文件结束,它也会重新开始播放。-re
: 这个选项告诉ffmpeg
使用实时模式,以原始速度读取输入文件。在实时模式下,ffmpeg
将尽力按照视频的实际帧率发送流数据。-i "C:\Users\Administrator\Downloads\Video\test.mp4"
: 这是输入文件的路径。ffmpeg
将读取该文件作为输入。-rtsp_transport tcp
: 这个选项指定了 RTSP 流的传输协议为 TCP。通过 TCP 传输可以提供更稳定的连接。-vcodec h264
: 这个选项指定了视频编解码器为 H.264(AVC)。它将使用 H.264 编码视频流。-f rtsp
: 这个选项指定了输出格式为 RTSP。rtsp://localhost/test
: 这是输出的 RTSP 流的地址。ffmpeg
将流式传输的视频流发布到该地址。
综上所述,这段代码的作用是使用 ffmpeg
将本地的视频文件转换为 RTSP 流,并通过 TCP 传输发布到 rtsp://localhost/test
地址上。这样其他支持 RTSP 协议的设备或应用程序就可以通过该地址来接收和播放该视频流
输入命令如果卡着不动的话需要配合EasyDarwin
流媒体服务,直接启动EasyDarwin
后就可以了。
EasyDarwin
EasyDarwin 是一个开源的流媒体服务器软件,用于实现音视频流的传输和处理。它提供了一套完整的流媒体解决方案,包括流媒体推流、录制、转发、播放等功能。
EasyDarwin 可以用于搭建自己的流媒体服务器,支持常见的音视频编码格式和传输协议,如 RTSP、RTMP、HLS 等。它具有跨平台的特性,可以在 Windows、Linux、macOS 等操作系统上运行。
使用 EasyDarwin,您可以搭建一个可靠的流媒体服务器,从摄像头、音频设备或其他音视频源推送实时流,并将其传输到支持的客户端应用程序或播放器上进行播放。它也可以用于构建视频监控系统、直播平台、音视频会议等应用场景。
EasyDarwin 的开源性质使得它具有灵活性和可定制性,您可以根据自己的需求进行定制和扩展。同时,它还提供了一些管理工具和 Web 控制台,方便用户进行配置和管理流媒体服务器。
总的来说,EasyDarwin 是一个功能强大的开源流媒体服务器软件,可以帮助用户快速搭建自己的流媒体平台,并实现高质量的音视频流传输和处理。
引用
1.node-ffmpeg-stream:https://www.npmjs.com/package/node-ffmpeg-stream
2.ffmpeg实现将视频文件转换成rtsp流:https://blog.csdn.net/weixin_44591652/article/details/123004247
评论 (0)