视联网综合管理平台:视频流与智能交互复盘
项目概述
平台面向 安防/物联 场景,统一纳管摄像头资产,提供 实时/准实时预览、多路分屏、设备健康与告警、以及语音驱动的数字人指令入口。前端 Vue 3 + Ant Design Vue;后端 Spring Boot 负责设备元数据、信令转发、权限与对接第三方流媒体能力。
视频播放方案选型
业务上需在 延迟、服务端成本、浏览器兼容性 之间权衡。
| 方案 | 协议路径 | 延迟量级 | 服务端成本 | 适用场景 |
|---|---|---|---|---|
| RTSP → WebSocket + MSE/JSMpeg | 拉流后转码/封装为浏览器可解格式 | 低(常 <500ms 量级,视链路而定) | CPU/带宽 占用高 | 指挥调度、需近实时操作 |
| HLS(m3u8 + ts/fMP4) | CDN/边缘分发,浏览器 hls.js/播放器 | 较高(数秒~十余秒 常见) | 边缘缓存友好 | 回放、对延迟不敏感监控 |
RTSP → WS:前端可用 JSMpeg 等在 Canvas 上绘制 MPEG-TS 流;服务端需稳定转码/推流进程,并做好 并发路数与 CPU 容量规划。可参考站内整理:前端视频流播放实现;开源流媒体可参考 SRS。
HLS:优先选成熟播放器(hls.js、Video.js、西瓜等);若需轻量封装可评估 EasyPlayer.js 等。无需自建转码时运维简单,但要接受 GOP 与分片 带来的固有延迟。
示例:hls.js 绑定 <video>(Vue3 中在 onMounted 里初始化)
import Hls from 'hls.js';
import { onMounted, onUnmounted, ref, type Ref } from 'vue';
export function useHlsPlayer(videoRef: Ref<HTMLVideoElement | null>, src: string) {
let hls: Hls | null = null;
onMounted(() => {
const el = videoRef.value;
if (!el) return;
if (Hls.isSupported()) {
hls = new Hls({ enableWorker: true, lowLatencyMode: false });
hls.loadSource(src);
hls.attachMedia(el);
} else if (el.canPlayType('application/vnd.apple.mpegurl')) {
el.src = src; // Safari 原生 HLS
}
});
onUnmounted(() => {
hls?.destroy();
hls = null;
});
}示例:JSMpeg + WebSocket(低延迟链路示意;URL 为后端转码后的 ws 地址)
// npm包名一般为 jsmpeg,具体以项目依赖为准
import JSMpeg from 'jsmpeg';
export function openLowLatencyStream(canvas: HTMLCanvasElement, wsUrl: string) {
return new JSMpeg.Player(wsUrl, { canvas });
}数字人语音交互链路
将需求拆解为 采集 → 识别 → 语义/指令 → 执行与反馈(含视频):
音频采集
浏览器侧使用 Recorder 等完成 录音、格式封装(mp3/wav)与可视化;注意 HTTPS 权限、采样率与码率 对识别准确率的影响。语音识别(ASR)
录音上传至后端或直接调用云厂商 一句话识别 / 实时识别 API,输出 稳定文本;需处理 噪声、方言、专有名词(摄像头编号、预置位名等)——可通过 热词/定制语言模型 提升命中率。指令解析与执行
文本进入 规则引擎或 LLM(视项目阶段),映射为 平台内可执行操作(如:打开某路流、切换分屏布局、查询告警)。关键约束:权限校验、操作幂等、危险指令二次确认。反馈返回 TTS 音频 / 数字人视频流 / 页面状态变更;与现有 设备控制 API、播放器状态机 打通,保证 UI 与真实设备状态一致。
工程要点:全链路 超时、重试与降级(ASR 失败时提示重录;识别歧义时列出候选操作);日志 关联 traceId,便于联调排障。
示例:Recorder 录音并上传后触发识别(流程骨架)
// 伪代码:具体 API 以 Recorder 文档为准
async function recordAndRecognize() {
const rec = new Recorder({ type: 'mp3', sampleRate: 16000 });
rec.open(() => rec.start());
// 实际由 UI「停止录音」回调触发 stop,此处省略等待逻辑
rec.stop(
async (blob: Blob) => {
const form = new FormData();
form.append('file', blob, 'voice.mp3');
const { data } = await api.post('/asr/upload', form);
await executeIntent(data.text); // 映射为打开通道、切换分屏等
},
(err: unknown) => console.error(err),
);
}示例:指令落库前做权限校验(Spring 控制器片段)
@PostMapping("/voice/intent")
public Result<?> intent(@RequestBody IntentCmd cmd, @AuthenticationPrincipal UserPrincipal me) {
if (!permissionService.canControlCamera(me.getId(), cmd.getCameraId())) {
return Result.fail(403, "无该路视频操作权限");
}
return deviceFacade.apply(cmd); // 内部再保证幂等 / 限流
}其他核心能力(摘要)
- 设备主数据:多字段 CRUD、分组与区域维度检索。
- 分屏布局:1/4/9 宫格等模板,与 路数授权、码率预算 联动。
- 告警中心:告警列表、详情、确认与统计;可与 订阅推送 扩展。
示例:四分屏网格与播放器槽位(Vue 模板骨架)
<script setup lang="ts">
import { ref } from 'vue';
const layout = ref<'1' | '4' | '9'>('4');
const slots = ref<{ id: string; streamUrl: string }[]>([]);
function setCell(i: number, cam: { id: string; streamUrl: string }) {
slots.value[i] = cam;
}
</script>
<template>
<div class="grid" :class="`grid-${layout}`">
<div v-for="i in layout === '4' ? 4 : 9" :key="i" class="cell">
<video v-if="slots[i - 1]" :src="slots[i - 1].streamUrl" controls muted />
</div>
</div>
</template>实际工程里 streamUrl 多为 HLS 地址 或 封装好的 Player 组件,并需处理 自动播放策略(静音、用户手势)。
复盘小结
视联网类项目的难度集中在 流媒体协议与资源消耗、多端播放器差异、以及「语音→可靠控制」的闭环。在材料中突出 量化指标(支持并发路数、P95 延迟、告警处理 SLA)会显著增强 资深参与感。本文档可按实际上线数据补全一节 性能与容量。