Vue3+TS 前端调用海康摄像头视频流实践(RTSP → WS-FLV)
在物联网/安防监控项目中,前端经常需要接入摄像头实时视频流。以海康威视摄像头为例,它默认输出的是 RTSP 协议,但前端浏览器并不直接支持 RTSP。常见的做法是:
-
后端转码/转协议:将 RTSP 转成浏览器支持的格式(如 FLV/HLS/WebRTC)。
-
前端播放:通过 Video.js、flv.js 等播放器加载流媒体。
本文记录了一个基于 Vue3 + TypeScript 前端 + Node.js 后端 的实践过程。
一、整体架构
-
摄像头输出 :RTSP 流(如
rtsp://username:password@ip:554/Streaming/Channels/101
)。 -
后端转码 :使用
ffmpeg
将 RTSP 转换为 FLV 格式,并通过 WebSocket 推流。 -
前端播放 :使用
flv.js
在 Vue3 中播放 WebSocket-FLV 视频流。
架构图如下:
海康摄像头(RTSP) → Node.js(FFmpeg转码+WebSocket) → 前端Vue3(FLV.js播放器)
二、后端实现(Node.js)
1. 安装依赖
javascript
npm init -y
npm install express ws
- Node.js 转发服务
javascript
// server.ts
import express from "express";
import { WebSocketServer } from "ws";
import { spawn } from "child_process";
const app = express();
const port = 3000;
// WebSocket 服务
const wss = new WebSocketServer({ port: 9999 });
wss.on("connection", (ws) => {
console.log("客户端已连接");
const rtspUrl =
"rtsp://username:password@192.168.1.100:554/Streaming/Channels/101";
// ffmpeg 拉流并输出 FLV 格式到 stdout
const ffmpeg = spawn("ffmpeg", [
"-rtsp_transport",
"tcp",
"-i",
rtspUrl,
"-f",
"flv",
"-an", // 不要音频
"pipe:1", // 输出到 stdout
]);
ffmpeg.stdout.on("data", (chunk) => {
ws.send(chunk);
});
ffmpeg.stderr.on("data", (err) => {
console.error("FFmpeg 错误:", err.toString());
});
ws.on("close", () => {
console.log("客户端断开连接");
ffmpeg.kill("SIGINT");
});
});
app.listen(port, () => {
console.log(`HTTP 服务已启动: http://localhost:${port}`);
});
运行:
javascript
ts-node server.ts
三、前端实现(Vue3 + TS)
1. 安装依赖
javascript
npm install flv.js
- 创建播放器组件
javascript
<!-- CameraPlayer.vue -->
<template>
<div class="video-box">
<video
ref="videoRef"
class="video"
controls
autoplay
muted
style="width: 100%; height: auto;"
></video>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, onBeforeUnmount } from "vue";
import flvjs from "flv.js";
const videoRef = ref<HTMLVideoElement | null>(null);
let flvPlayer: flvjs.Player | null = null;
onMounted(() => {
if (flvjs.isSupported() && videoRef.value) {
flvPlayer = flvjs.createPlayer({
type: "flv",
url: "ws://localhost:9999", // WebSocket 地址
isLive: true,
});
flvPlayer.attachMediaElement(videoRef.value);
flvPlayer.load();
flvPlayer.play();
}
});
onBeforeUnmount(() => {
if (flvPlayer) {
flvPlayer.destroy();
flvPlayer = null;
}
});
</script>
四、常见问题
-
延迟高?
-
RTSP → FLV 转码存在几百毫秒到几秒延迟,可以调节 ffmpeg 参数(如
-tune zerolatency
)。 -
如果对实时性要求极高,可以考虑 WebRTC 方案。
-
-
卡顿/黑屏?
-
检查摄像头 RTSP 地址是否正确。
-
确保 Node.js 服务和前端在同一个网络下。
-
增加
-rtsp_transport tcp
确保走 TCP。
-
-
浏览器兼容性?
-
flv.js
基于 MSE(Media Source Extensions),主流 Chrome/Edge 都支持。 -
Safari 不支持 FLV,苹果设备建议使用 HLS(m3u8)。
-
五、总结
本文介绍了如何用 Node.js + FFmpeg 将海康摄像头的 RTSP 流 转换为 WebSocket-FLV 流 ,并在 Vue3 + TypeScript 前端中通过 flv.js 播放。
这种方式实现成本较低,适合局域网监控、安防平台、物联网视频监控等场景。若对低延迟和移动端兼容性要求高,可以进一步升级到 WebRTC 方案。
FFmpeg 低延迟 RTSP → FLV 配置参数优化
在默认配置下,ffmpeg
从 RTSP 拉流再转码推送到前端会有 1~3 秒延迟。通过合理的参数调整,可以将延迟控制在 500ms 左右,甚至更低。
- 基础命令
javascript
ffmpeg -rtsp_transport tcp -i rtsp://user:pass@192.168.1.100:554/Streaming/Channels/101 \
-preset ultrafast \
-tune zerolatency \
-fflags nobuffer \
-flags low_delay \
-strict experimental \
-an \
-c:v libx264 \
-f flv pipe:1
2. 参数说明(关键优化点)
-
-rtsp_transport tcp
强制走 TCP,避免 UDP 丢包造成花屏。
-
-fflags nobuffer
禁用缓冲,降低延迟。
-
-flags low_delay
设置低延迟模式。
-
-preset ultrafast
x264 编码速度最快的预设,降低延迟(代价是压缩率差一些,文件体积大)。
-
-tune zerolatency
针对实时应用优化,禁用 B 帧,减少缓存。
-
-c:v libx264
使用 H.264 编码(浏览器兼容性最好)。
如果摄像头本身就是 H.264 编码,可以用
-c copy
直接拷贝,进一步减少延迟和 CPU 消耗。 -
-an
去掉音频,减少带宽和处理压力。
-
-f flv
输出为 FLV 格式,方便前端
flv.js
播放。 -
pipe:1
把数据输出到标准输出(stdout),由 Node.js WebSocket 转发给前端。
3. Node.js 集成示例(优化版)
javascript
const ffmpeg = spawn("ffmpeg", [
"-rtsp_transport", "tcp",
"-i", rtspUrl,
"-preset", "ultrafast",
"-tune", "zerolatency",
"-fflags", "nobuffer",
"-flags", "low_delay",
"-an",
"-c:v", "libx264", // 或 "-c", "copy" 直接拷贝
"-f", "flv",
"pipe:1"
]);
4. 进一步优化方向
-
CPU 占用太高?
- 如果摄像头 RTSP 已经是 H.264 编码,建议用
-c copy
(不转码),直接推送:
- 如果摄像头 RTSP 已经是 H.264 编码,建议用
javascript
ffmpeg -rtsp_transport tcp -i rtsp://... -c copy -an -f flv pipe:1
-
延迟还是大?
-
确保网络延迟低,避免跨公网。
-
在前端
flv.js
设置isLive: true
,并控制stashInitialSize
(缓冲大小)。
-
-
兼容 Safari / iOS?
- Safari 不支持 FLV,建议额外推一份 HLS (
.m3u8
) 流。
- Safari 不支持 FLV,建议额外推一份 HLS (
👉 这样配置后,一般延迟可以控制在 300ms~800ms,适合安防监控、实时预览等场景。
既然后端 ffmpeg
已经优化到低延迟模式,那前端 flv.js
也要做对应的参数调整,否则缓冲区过大就会拖慢播放。下面是一个 前端 flv.js 播放器低延迟模式配置示例。
前端 flv.js 播放器参数优化(低延迟模式)
1. 基础配置
在创建播放器时,flv.js.createPlayer
支持传入 config
对象,可以调整缓冲策略:
javascript
flvPlayer = flvjs.createPlayer(
{
type: "flv",
url: "ws://localhost:9999",
isLive: true, // 必须开启直播模式
},
{
enableWorker: true, // 启用分离线程解码,降低卡顿
enableStashBuffer: true, // 是否启用缓冲区
stashInitialSize: 128, // 初始缓冲区大小,默认 384KB,调小可降低延迟
fixAudioTimestampGap: false, // 去掉音频时间戳修复,避免延迟
autoCleanupSourceBuffer: true, // 自动清理 SourceBuffer,防止内存泄漏
}
);
2. 参数解释
-
isLive: true
表示是直播流,不允许拖拽和缓存太多。
-
enableWorker: true
使用 Web Worker 解析流,避免主线程阻塞,提升性能。
-
enableStashBuffer: true
开启缓冲池,防止因网络波动而花屏。
-
stashInitialSize: 128
初始缓冲大小(KB),默认是
384KB
,这会导致 1~3 秒延迟 。调小到
128KB
(甚至64KB
)可以明显降低延迟,但网络不稳定时更容易卡顿。 -
fixAudioTimestampGap: false
不修复音频时间戳(直播通常只关心实时性,禁用该特性可减少延迟)。
-
autoCleanupSourceBuffer: true
当缓存过大时自动清理,避免内存占用过多。
javascript
<template>
<div class="video-box">
<video
ref="videoRef"
class="video"
controls
autoplay
muted
style="width: 100%; height: auto;"
></video>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, onBeforeUnmount } from "vue";
import flvjs from "flv.js";
const videoRef = ref<HTMLVideoElement | null>(null);
let flvPlayer: flvjs.Player | null = null;
onMounted(() => {
if (flvjs.isSupported() && videoRef.value) {
flvPlayer = flvjs.createPlayer(
{
type: "flv",
url: "ws://localhost:9999", // WebSocket 地址
isLive: true,
},
{
enableWorker: true,
enableStashBuffer: true,
stashInitialSize: 128, // KB,调小减少延迟
fixAudioTimestampGap: false,
autoCleanupSourceBuffer: true,
}
);
flvPlayer.attachMediaElement(videoRef.value);
flvPlayer.load();
flvPlayer.play();
}
});
onBeforeUnmount(() => {
if (flvPlayer) {
flvPlayer.destroy();
flvPlayer = null;
}
});
</script>
4. 调优建议
-
超低延迟:
-
stashInitialSize
设置为64
或更小,延迟能控制在 300~500ms。 -
但要注意:网络抖动大时可能卡顿。
-
-
平衡模式:
stashInitialSize
维持128~256
,延迟在 500ms~1s,稳定性更好。
-
移动端兼容:
- iOS/Safari 不支持
flv.js
,需要额外提供 HLS(m3u8)。
- iOS/Safari 不支持
这样前后端都优化后,一般能做到 500ms 内延迟,满足大部分监控、实时视频预览场景。