ZMS:为边缘而生的超低延迟流媒体路由服务

ZMS:为边缘而生的超低延迟流媒体路由服务

在视频监控、边缘智能和嵌入式媒体处理场景中,我们常常苦恼于“如何在资源极度受限的设备上,把一路视频流同时分发给多个消费者”,又或者需要把 DMA 采集的原始画面,实时转换成标准 RTSP 流供本地播放与云端录制。传统的媒体服务器体积庞大、延迟难以控制,而简单的管道脚本又缺少协议适配和容错能力。

为此,我们开发并开源了 ZMS——一款专门面向边缘与嵌入式环境的轻量级流媒体路由引擎。它的核心使命简单而纯粹:在异构的媒体源和目标之间充当高效、低开销的桥梁,并且在这个角色上做到了极致性能——经实测,从收到数据包到转发出去,用户态耗时仅 0.1~0.2 ms

为什么需要 ZMS?

边缘网关、设备侧流汇聚节点、NVR 前端的协议适配层……这些场景有几个共同痛点:

  • 资源拮据:ARM / MIPS 芯片,内存通常只有几十到几百 MB,无法运行大型流媒体框架。
  • 延迟敏感:本地预览、实时分析要求亚秒甚至毫秒级延迟,任何多余的缓冲都是灾难。
  • 协议混杂:上游可能来自 DMA 环形缓冲区、RTSP 推流/拉流;下游可能需要同时输出给多个 RTSP 客户端或远程服务器。
  • 容错需求:DMA 源可能热插拔,网络可能波动,要求无缝切换和自动重连。

ZMS 正是为填补这一空白而设计,它不追求大而全,而是极度专注在 RTSP + DMA 管道 上,把最核心的事情做精、做快、做稳。

架构一览:清晰的模块化管道

ZMS 采用分层管道模型,数据从输入到输出一路单向流动,配合显式的路由绑定实现一对多分发:

  1. 输入层
  • DmaInput:共享内存 DMA 采集,支持主/备环形缓冲区,带看门狗健康监控和自动故障恢复。
  • RtspPullInput:主动拉流客户端,从上游摄像头或服务器获取流。
  • RtspPushInput:内建 RTSP 服务端接收推流,配合 ANNOUNCE/RECORD 语义实现发布者接入。
  1. 路由层
    StreamRouter 负责输入与输出的注册,并根据配置进行显式路由绑定。它支持一路输入向多路输出的扇出,并且在转发时保持编解码器的上下文感知。
  2. 输出层
  • RtspServerOutput:将流暴露为本地 RTSP 服务,供局域网播放器拉流。
  • RtspPushOutput:将流转发(推流)到远程 RTSP 服务器,完成边缘到中心的汇聚。
  1. 协议与编解码层
    完整的 RTSP 控制面实现(OPTIONS / DESCRIBE / SETUP / PLAY / ANNOUNCE / RECORD / TEARDOWN),以及 H.264 / H.265 的 RTP 打包/解包、SPS/PPS/VPS 提取与缓存、FU 分片重组等能力。

链路全解析:四个典型业务场景

ZMS 的设计足够通用,下面几个典型链路可以覆盖绝大多数边缘流媒体部署需求:

场景 A:DMA 摄入 → 本地 RTSP 服务

DmaInput → StreamRouter → RtspServerOutput → 播放器
嵌入式设备的 DMA 帧以 Annex.B 格式到达,ZMS 提取并缓存参数集,生成 SDP 供播放器 DESCRIBE 后,将编码帧打包为 RTP 分发给各个客户端。支持 UDP 和 TCP 交错传输。

场景 B:上游 RTSP 拉流 → 本地重分发

RtspPullInput → StreamRouter → RtspServerOutput
从远端摄像机拉流,解包 RTP 恢复 NAL 单元,再为每一个本地播放器单独打包(独立序列号和 SSRC),实现轻量级多播代理。

场景 C:接收推流 → 中继到远程服务器

外部发布者 → RtspServer(推流侧) → RtspPushInput → StreamRouter → RtspPushOutput → 远端 RTSP 服务器
承担边缘节点的双向协议转换角色:对内接收 ANNOUNCE/RECORD 推流,对外执行 ANNOUNCE → SETUP → RECORD 转发,并处理 401 认证挑战。

场景 D:一份输入多份输出(扇出)

一个摄入源通过 StreamRouter 同时驱动多个输出实例,例如本地播放 + 两路远程推流。各输出之间完全解耦,独立维护自己的 RTP 状态,互不干扰。

挑战 0.1ms 级延迟

在我们的Orange Pi 5 4G板子测试环境中(DMA 输入 → RTSP 服务端输出),关闭非必要调试,push_nalu() 从被调用到 send 系统调用返回的用户态处理耗时P50 稳定在 130 µs 左右,P95 不超过 180 µs,折算即 0.13~0.18 ms。这个数字排除了网络传输抖动和播放器缓冲,真实反映了 ZMS 本身的转发开销。

如此之低的延迟,主要得益于:

  • 零拷贝意识:DMA 使用共享内存,数据不经过应用层多余拷贝。
  • 精简路径:转发路径上几乎没有锁竞争,路由层直接指针传递。
  • 缓存友好型内存布局:参数集和会话状态紧凑排列,减少 cache miss。

此外,ZMS 还提供了可选的延迟统计功能(环境变量 ZMS_LATENCY_STATS=1 开启),周期性输出 P50/P95/P99 延迟,方便现场调优和长稳测试观察。

快速上手

ZMS 采用 CMake 构建,依赖简洁(基础网络库 + 可选 PTP 时间同步)。克隆代码后只需:

mkdir build && cd build
cmake ..
cmake --build . -j
./ZMS -c ../configs/zms_example.json

配置文件清晰描述了各类输入输出及其路由关系,DMA 相关的看门狗、重连间隔、故障恢复策略都有详细推荐值,可按需微调。

结语

如果你正在为嵌入式设备寻找一个低延迟、低内存、协议可靠的流媒体路由器,或者厌倦了将多个脚本拼凑出来的脆弱管道,不妨试试 ZMS。它足够小,也足够快 —— 0.2 毫秒的转发代价,换取的是架构的清晰和业务的稳定

ZMS 由 hddvison 开发维护,源自 Chengdu Huade Dingsheng Technology