概念介绍
国标监控概述
国标监控(VMS)把符合 GB/T 28181-2016 的视频设备接入到 BladeX 多租户体系,与 IoT 设备 / 告警 / 工作流 / 规则引擎共用同一套基础设施。
核心价值:
- 国标合规:按 GB/T 28181-2016 实现 SIP 信令、SDP 协商、MANSCDP+XML 报文,覆盖核心监控所需的强制消息类型,并兼容主流厂商私有扩展
- 多租户原生:平台级 SIP 配置 + 设备级租户绑定,跨租户全链路隔离
- 协议解耦:协议层不感知业务表,业务层不感知 SIP 细节,通过 SPI 单向依赖
- 资源安全:SSRC 黑名单防串台、CLOSE_PENDING 状态机防 ZLM 端口泄漏、订阅自动续约防中断
- 可观测:结构化日志 + 进程内 Spring 事件
- 存储抽象:抓图/录像走 OSS,支持 MinIO / 阿里云 / 腾讯云 / 华为云 / 七牛云
一、基础概念
国标监控围绕「设备接入」与「媒体转换」两条主线展开:以 GB/T 28181 信令规范统一接入各厂商视频设备,再由流媒体服务(ZLM)把设备的 RTP/PS 流转封装为浏览器可播放的格式。下表先厘清贯穿全篇的核心术语。
| 术语 | 说明 |
|---|---|
| 国标 / GB28181 | GB/T 28181-2016,基于 SIP 的视频监控联网信令规范,统一各厂商(海康 / 大华 / 宇视等)设备的注册、点播、控制与目录交互 |
| SIP | RFC 3261 会话信令协议,国标信令的承载层,承担注册(REGISTER)、点播建立(INVITE)、挂断(BYE)等控制交互 |
| ZLMediaKit(ZLM) | 开源流媒体服务,接收设备 RTP/PS 流并转封装为 WS-FLV / HLS / RTMP / WebRTC 后分发给观看端 |
| 推流(push) | 设备把音视频 RTP/PS 流主动发送至 ZLM 的收流端口 |
| 拉流(pull) | 观看端从 ZLM 获取已转封装的流进行播放(如浏览器拉 WS-FLV) |
| RTP / PS | 设备侧的裸封装格式,浏览器无法直接播放,须经 ZLM 转封装 |
| 通道(Channel) | 设备下的一路视频。一台 NVR 可挂多路摄像头,即一个设备对应多个通道;点播、回放、云台等操作均以 channelId 为对象,详见 核心概念 |
信令面与媒体面
国标监控的数据分为互不混用的两条路径:
- 信令面(SIP):传输控制指令与元数据——设备上下线、点播 / 挂断、云台控制、目录同步、告警上报等,数据量小。
- 媒体面(ZLM):传输音视频流本身——设备推流进入、观看端拉流播放。
平台是两条路径的编排方:对设备下发 SIP 信令,对 ZLM 下发 REST 指令并接收其 Webhook 回调。
一次直播的完整链路
浏览器请求播放某通道后,平台向设备下发 INVITE 信令、使其将 RTP/PS 流推送至 ZLM;ZLM 把裸流转封装为 WS-FLV 等格式,平台再将对应拉流地址返回浏览器完成播放。整条链路中,设备负责推流、浏览器负责拉流、ZLM 负责转封装与分发,平台通过 SIP 与 REST 两侧编排。
二、技术选型
| 维度 | 选型 |
|---|---|
| SIP 信令栈 | jain-sip(RFC 3261 完整实现,UDP + TCP 双栈 5060) |
| 流媒体服务 | ZLMediaKit(收 RTP/PS 流 + 转 WS-FLV / HLS / RTMP / WebRTC 分发);支持租户级多节点、按并发自动负载 |
三、整体架构
国标监控模块在 BladeX-Links 平台中以「协议层 / 业务层 / 前端层」三层架构组织,通过 SPI 单向依赖隔离协议细节与业务编排。
| 角色 | 职责 |
|---|---|
| 前端 | 通道树导航 + 直播/回放播放器 + PTZ 控件 + 抓图/录像/告警面板 |
| 平台业务层 | 接入编排 + 多租户隔离 + 异步任务调度 + OSS 上传 |
| 国标设备 | 主动 REGISTER + Keepalive 心跳 + 响应 INVITE/Catalog/PTZ + 主动上报告警/GPS/目录变更 |
| 流媒体服务 | 接收设备 RTP 流 + Hook 通知平台 + 转 WS-FLV/HLS/RTMP/WebRTC 分发 |
| 上级平台 | (可选)接收本平台作为下级注册 + Keepalive + Catalog 查询 |
信令面可多实例分片
上图「平台业务层」可水平扩展为多个 blade-server 信令实例。每个实例启动时自注册为一个信令节点,设备按其「上级 SIP 地址」注册到某个实例、该实例即此设备属主;点播 / 回放 / 云台等控制请求经属主路由(本地执行或实例间内部 HTTP 转发到属主)下发,设备归属存 Redis、随心跳续期。媒体面(ZLM)本就按租户多节点负载,两者各自独立扩展。单实例部署零配置即工作,多实例的部署方式、配置与完整原理详见 分片部署。
四、核心能力
| 类别 | 能力描述 |
|---|---|
| 设备接入 | 自动接入(AUTO)/ 手动注册(MANUAL 白名单,未登记设备 403)双模式 + 设备独立密码覆盖平台默认 + REGISTER + Digest 鉴权(RFC 2069 与 qop=auth 自动适配)+ Keepalive 心跳超时下线 + 设备信息/状态/参数三件套异步查询 |
| 媒体节点 | 租户级 ZLM 节点增删改 + 按并发最低全自动选节点(配置 N 个即构成 N 节点集群)+ on_server_keepalive 心跳在线状态 + 默认节点启动幂等植入(升级平滑) |
| 目录同步 | Catalog 主动查询分批 SN 聚合 + Catalog Subscribe 订阅式增量推送 + 行政区划自动建分组树 |
| PTZ 控制 | 8 方向(含对角)+ 变倍 + 聚焦/光圈(FI)+ 巡航/扫描/辅助开关(雨刷)+ 看守位 + 拉框缩放(3D 定位)+ 预置位 set/call/remove + 远程预置位列表同步 |
| 告警上行 | Alarm Notify 解析(报警方式 + 类型 + 子事件三段成对传递) + 异步落库国标报警表 iot_vms_alarm + Alarm Subscribe 订阅(支持优先级/类型/时段过滤) + 60s 去重 |
| 实时点播 | INVITE/ACK/BYE in-dialog + Subject 头按国标 §9.6.1 构造 + 主/子码流切换(SDP 多厂商兼容字段) + WS-FLV/HLS/RTMP/WebRTC 拉流 URL |
| 视频墙看板 | 多格分屏(1/4/9/16)实时监控 + 看板布局(分屏 + 各格通道绑定)以 JSON 持久化 iot_vms_live、按用户私有保存/加载 |
| 历史回放 | INVITE Playback + INFO MANSRTSP 控制(播放/暂停/倍速/拖动) |
| 设备控制 | 远程重启 + 本地录像启停 + 校时(强制 UTC+8 北京时间) |
| 抓图 | 有流直抓 / 无流自动开流 + 等流就绪二次校验 + OSS 存储 |
| 录像下载 | INVITE Download(s=Download + downloadspeed 加速取流)+ 流媒体录制 → OSS 异步搬运,轮询流下线判完成 + 状态机驱动 |
| 录像计划 | Cron 调度 + 两阶段异步执行(同步启动 + 定时回调收尾) + OSS 归档 + 自动过期清理 |
| 设备分组 | 行政区划自动建树 + 业务分组多对多 |
| GPS 上报 | MobilePosition 订阅 + Notify 解析 + WGS84 合理性校验 |
| 设备地图 | 设备人工地图打点定位 + Redis GEO 按租户隔离 + 半径/近邻范围检索(与 iot/device 地图同源) |
| 国标级联 | 作为下级:主动注册 + 401 二次鉴权(双 Digest 模式自动切换,Call-ID 按 RFC 3261 §22.4 复用)+ Keepalive + 响应上级 Catalog 查询 / SUBSCRIBE / INVITE 被点播 / Control 转发 / BYE,三路收敛(上级 BYE / 下级断流 / ACK 超时 + GC 兜底)保证级联 session 生命周期闭环 |
| 多租户隔离 | 全链路 tenant_id + 协议入站反查 + 跨租户结果缓存校验 |
| 可观测 | 进程内 Spring 事件(VmsAlarmReceivedEvent / DeviceOnline·OfflineEvent) |
| 资源管理 | SSRC 黑名单防串台 + 流会话状态机自愈 + 订阅自动续约 + 设备重连恢复 |
五、多租户隔离原理
平台与设备之间有三条独立入站路径,每条都必须在进入业务逻辑前完成租户上下文注入。
| 入站路径 | 租户来源 | 防越权措施 |
|---|---|---|
| 前端 REST | JWT 解析 | BladeX 框架租户拦截器自动注入 SQL 条件 |
| 设备 SIP | deviceId → platform → tenantId 反查(Caffeine 缓存) | 反查失败的设备整条报文丢弃 |
| 流媒体 Hook | SSRC → 会话.tenantId 直接读 | 会话不存在时 hook 直接忽略 |
异步查询响应(设备查询/抓图/录像下载等)的中间结果都绑定写入时的租户 ID, 读取时校验当前请求租户一致才返回,跨租户读取一律返回 null。
