vue3+TS 前端调用海康摄像头视频流,后端用 Node.js 做 RTSP 转 WebSocket-FLV 转发,并且前后端优化延迟方案

Vue3+TS 前端调用海康摄像头视频流实践(RTSP → WS-FLV)

在物联网/安防监控项目中,前端经常需要接入摄像头实时视频流。以海康威视摄像头为例,它默认输出的是 RTSP 协议,但前端浏览器并不直接支持 RTSP。常见的做法是:

  • 后端转码/转协议:将 RTSP 转成浏览器支持的格式(如 FLV/HLS/WebRTC)。

  • 前端播放:通过 Video.js、flv.js 等播放器加载流媒体。

本文记录了一个基于 Vue3 + TypeScript 前端 + Node.js 后端 的实践过程。


一、整体架构

  1. 摄像头输出 :RTSP 流(如 rtsp://username:password@ip:554/Streaming/Channels/101)。

  2. 后端转码 :使用 ffmpeg 将 RTSP 转换为 FLV 格式,并通过 WebSocket 推流。

  3. 前端播放 :使用 flv.js 在 Vue3 中播放 WebSocket-FLV 视频流。

架构图如下:

海康摄像头(RTSP) → Node.js(FFmpeg转码+WebSocket) → 前端Vue3(FLV.js播放器)

二、后端实现(Node.js)

1. 安装依赖

javascript 复制代码
npm init -y
npm install express ws
  1. 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
  1. 创建播放器组件
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>

四、常见问题

  1. 延迟高?

    • RTSP → FLV 转码存在几百毫秒到几秒延迟,可以调节 ffmpeg 参数(如 -tune zerolatency)。

    • 如果对实时性要求极高,可以考虑 WebRTC 方案。

  2. 卡顿/黑屏?

    • 检查摄像头 RTSP 地址是否正确。

    • 确保 Node.js 服务和前端在同一个网络下。

    • 增加 -rtsp_transport tcp 确保走 TCP。

  3. 浏览器兼容性?

    • 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 左右,甚至更低。

  1. 基础命令
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. 进一步优化方向

  1. CPU 占用太高?

    • 如果摄像头 RTSP 已经是 H.264 编码,建议用 -c copy(不转码),直接推送:
javascript 复制代码
ffmpeg -rtsp_transport tcp -i rtsp://... -c copy -an -f flv pipe:1
  1. 延迟还是大?

    • 确保网络延迟低,避免跨公网。

    • 在前端 flv.js 设置 isLive: true,并控制 stashInitialSize(缓冲大小)。

  2. 兼容 Safari / iOS?

    • Safari 不支持 FLV,建议额外推一份 HLS (.m3u8) 流。

👉 这样配置后,一般延迟可以控制在 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. 调优建议

  1. 超低延迟

    • stashInitialSize 设置为 64 或更小,延迟能控制在 300~500ms。

    • 但要注意:网络抖动大时可能卡顿。

  2. 平衡模式

    • stashInitialSize 维持 128~256,延迟在 500ms~1s,稳定性更好。
  3. 移动端兼容

    • iOS/Safari 不支持 flv.js,需要额外提供 HLS(m3u8)。

这样前后端都优化后,一般能做到 500ms 内延迟,满足大部分监控、实时视频预览场景。

相关推荐
崔庆才丨静觅1 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax