Skip to content
在线演示下载安装包

接自己的 ZLMediaKit:绿色安装包怎么换成外部流媒体 ​

绿色安装包里带了一个 ZLMediaKit,端口占 51004–51013 加 51014–51063 的 RTP 段,secret 随包固定,配置文件在 vendor/zlm/config.ini。单机部署时它和平台在同一台机器上,装完即用。

换自己的 ZLM,理由通常更实际:

  • 已有 ZLM 集群在跑,不想再多一套
  • 流媒体要单独一台机器,甚至单独一个网段/机房
  • 媒体并发高,内置节点扛不住,要加节点做调度
  • 单位要求媒体组件统一版本、统一运维

平台本来就支持多节点、按权重调度、按设备指定节点。外部 ZLM 不用改造,登记进来就能用。麻烦的地方在于它是双向的:平台调 ZLM 是一个方向,ZLM 回调平台是另一个方向,一个方向配通不代表另一个通。

示意图:平台调用 ZLM 的 HTTP API、ZLM 回调平台的 hook 地址、设备向 ZLM 推 RTP、浏览器从 ZLM 拉流,四条链路必须分别打通
图 1 四条链路要分别通:① 平台 → ZLM 的 HTTP API(下指令、查状态);② ZLM → 平台的 hook 回调(通知流事件);③ 设备 → ZLM 的 RTP 端口(推流);④ 浏览器 → ZLM 的播放端口(拉流)。任何一条不通,症状都不一样,别用同一套办法试。

一、四条链路,各自的判据 ​

链路方向端口(绿色包默认)不通的表现
平台 → ZLM API平台主机 → ZLM51004/tcp新增节点时「连接失败」,点播全挂,页面提示服务未装配
ZLM → 平台 hookZLM 主机 → 平台51002/tcp(后端 HTTP)点播能出流但状态不动、录像不出、无人观看不断流
设备 → ZLM RTP设备 → ZLM51014–51063/udpSIP 返回成功,但画面一直黑,平台侧「收流超时」
浏览器 → ZLM浏览器 → ZLM51004(http-flv/ws-flv/HLS)后端一切正常,播放器转圈或报跨域/连接失败

先手工验一遍,再去动平台配置。四条命令对应上面四行:

bash
# ① 平台主机上:能不能调通 ZLM 的 API
curl -s "http://192.168.10.220:51004/index/api/getServerConfig?secret=你的secret" | head -c 200

# ② 在 ZLM 主机上:能不能打到平台的 hook 端口
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.10.106:51002/index/hook

# ③ 设备侧:平台点播一台设备后,看 ZLM 有没有收到 RTP
#    在 ZLM 主机上抓包,端口段按自己的配置改
tcpdump -i any -n udp portrange 51014-51063 -c 20

# ④ 浏览器所在机器:直接打开拉流地址
#    http://192.168.10.220:51004/live/<流ID>.live.flv

四条都通过再接节点,能省掉一大半来回。

二、两种接法,先选一种 ​

接法 A:还没启动过,首启就用外部 ZLM ​

绿色包首次启动时,如果节点表是空的,会按 config.yml 的 gb28181.zlm 段登记一个默认节点。把这一段直接改成你的 ZLM,首启出来的就是你的节点,不需要事后删内置节点。

yaml
gb28181:
  zlm:
    host: "192.168.10.220"        # 平台访问 ZLM 的地址
    sdpip: "192.168.10.220"       # 写进 SDP 的 c= 行,设备往这里推 RTP
    playbackhost: "192.168.10.220" # 浏览器拉流地址,NAT 时填公网地址
    httpport: 51004               # ZLM 的 HTTP API 端口
    secret: "你在 ZLM config.ini 里配的 api.secret"
    rtpport: 51014                # 单端口收流时的端口
    mediaserverid: "uvp-node-1"   # 节点身份标识,建议给固定值

同时把 hook 回调地址指对:

yaml
gb28181:
  media:
    # 推荐写完整基址:ZLM 在另一台机器时,127.0.0.1 是它自己,不是平台
    hookbaseurl: "http://192.168.10.106:51002/index/hook"
    hookhost: "192.168.10.106"    # 不写 hookbaseurl 时才用这两项拼
    hookport: 51002

⛔ 跨机时 hookhost 必须是平台的地址,不能留 127.0.0.1。留着的后果很典型:ZLM 把事件回调给自己,连不上;平台这边只表现为流状态不更新,日志里一条报错都没有,因为请求根本没到平台。

gb28181.zlm 段只在节点表为空时生效。已经启动过的实例改它没用,节点已经在 meta_node 表里了,得走接法 B。

接法 B:已经在跑,事后加节点 ​

登录平台,进 流媒体管理 → 节点管理 → 节点列表,点「新增节点」。表单分两步。

第一步填连接信息:

字段填什么
节点别名只用于平台内展示,不会写进 ZLM;留空显示「IP:端口」
IP 地址后端能访问到的 ZLM 地址(不是浏览器的地址)
API 端口ZLM 的 [http] port
API SecretZLM 的 [api] secret,只写不回显

点「连接并读取」,平台会实时去读一遍 ZLM 的真实配置,然后回显:

  • 各协议端口(HTTP / HTTPS / RTSP / RTMP / RTC / ONVIF)与开关状态
  • RTP 单端口,以及 [rtp_proxy] port_range 的实际范围
  • ZLM 自己的 general.mediaServerId(没有则显示「登记后由平台生成」)

端口以 ZLM 实测值为准,不以你填的为准。RTP 端口范围在表单里是只读的,真源在 ZLM 的 config.ini,平台这边只是镜像。

第二步确认后点「确认添加」,平台会做两件事:

  1. 通过 ZLM 的 setServerConfig 写入 general.mediaServerId,让 ZLM 后续的每次回调都带上这个身份;
  2. 下发 hook:把平台该管的那些事件回调地址逐条写成 http://平台/index/hook/<事件>?node=<节点UUID>&cap=<凭据>,并打开 hook.enable。

所以你不需要手工在 ZLM 的 config.ini 里配 hook。手工配也行,不过平台的规则是:

  • 只刷新「带本节点凭据」或「路径就是本平台 hook 端点」的那些回调;
  • 其他回调视为你在用,不覆盖;
  • hook.enable = 0 被视为你的显式选择,平台不会强行打开。
流程图:新增节点先填 IP、API 端口和 secret,点连接并读取拿到 ZLM 实测端口,确认添加后平台写入 mediaServerId 并下发带凭据的 hook 回调
图 2 「连接并读取」不只是探测——它拿回的是 ZLM 的真实端口与协议状态,平台据此登记端口容量;「确认添加」才是写动作:写 mediaServerId、下发带 node 与 cap 的 hook 回调。

添加完成后,还有三个地址要按需确认(新建第二步或事后的「编辑」里都能填):

  • 设备推流地址(sdpIp):设备往哪推 RTP。跨网段、平台在 NAT 后面时必填,不能填 127.0.0.1
  • 播放地址(playbackHost):浏览器从哪拉流。经过 NAT 时填公网地址或域名
  • 平台回调地址(hookIp):ZLM 回调平台时连的地址,跨机时必填

这三个地址配错的表现各不相同:sdpIp 错 → 信令成功、没画面;playbackHost 错 → 平台里能看到流,播放器打不开;hookIp 错 → 能出流,但状态与录像不对。

三、内置那个 ZLM 怎么办 ​

启动脚本不管你接没接外部节点,每次 start 都会把包内 ZLM 拉起来,它不知道你在用别人的。两种处置:

方案一(省事):让它空转。 什么都不用改。包内 ZLM 在 51004–51013 上跑着,平台不用它,只是多占一份内存。缺点是两套流媒体同时在跑,运维看着会疑惑。

方案二(干净):把内置的端口挪开,或者干脆停掉它。 如果你的 ZLM 也要用 51004,不挪端口会直接启动失败——脚本会报「ZLM 端口 51004 已被其他进程占用」,然后整个 start 中止。改 config/config.env 让内置的让开:

ini
UVP_ZLM_HTTP_PORT=52004
UVP_ZLM_SSL_PORT=52007
UVP_ZLM_RTSP_PORT=52005
UVP_ZLM_RTMP_PORT=52006
UVP_ZLM_RTC_PORT=52008
UVP_ZLM_SIGNALING_PORT=52009
UVP_ZLM_SIGNALING_SSL_PORT=52010
UVP_ZLM_SRT_PORT=52011
UVP_ZLM_ONVIF_PORT=52012
UVP_ZLM_ICE_PORT=52013
UVP_ZLM_RTP_PROXY_PORT=52014
UVP_ZLM_RTP_RANGE=52014-52063

改完 restart。UVP_ZLM_RTP_RANGE 和 UVP_ZLM_RTP_PROXY_PORT 必须同一起点,两个都改又互相矛盾时脚本会拒绝启动。

如果连节点列表里的内置节点都不想要:先把它切到「维护态」,确认上面没有流和会话,再删除。删除会走影响预检,有流、有会话、有录像时会被拒绝,这是预检在拦你,不是坏了。

四、三个容易卡住的地方 ​

节点删不掉:先看是哪一种 ​

平台的删除有四道关卡:权限、影响预检(实时读一次该节点的流/会话/录像)、必须处于维护态、影响必须为空。所以:

  • 提示「节点影响预检失败」= 连不上这个节点(ZLM 挂了、IP 变了、secret 错了)
  • 提示「请先把节点切到维护态」= 状态还是 active/offline
  • 提示「节点仍有活动影响」= 上面真的还有流或会话

第一种最难受:ZLM 已经不可达,预检读不通,既切不了维护态也删不掉,死锁。这时用强制移除(purge=unreachable)。平台会先真探一次,如果发现节点其实可达,直接拒绝(409),所以它当不了绕过前两道关卡的万能删除键。强制移除只给真的够不着的节点用。

删节点是单向的,对端不知道 ​

平台删掉节点之后不会通知那台 ZLM。ZLM 继续按自己的周期往平台回调,平台已经不认识它了,日志里就持续出现 node_unknown 的拒绝记录。on_server_keepalive 这类事件每 10 秒一条,很快能刷满日志。

现在的版本在退役节点时会尝试把平台自己写过的 hook 逐条撤掉,带退避重试,撤不掉会留一条显式的失配记录。但你要是手工在 ZLM 侧配过 hook,那部分平台不碰,得自己去清。

mediaServerId 不要随手改 ​

它不只是个名字。平台靠它判断这条回调是哪个节点发来的,而 ZLM 会把 setServerConfig 的结果持久化回自己的 config.ini。一旦改成和平台登记不一致的值,hook 归属校验就永远对不上,症状是节点在线、设备也能点播,但状态和录像全乱。

要么让平台写,要么在登记前就固定好(接法 A 里的 mediaserverid),别中途手工改。

五、多节点时怎么用 ​

节点登记好以后,平台按权重把新流分到各节点,也可以给单台设备指定节点(zlm_node_id)。用起来有三个约定:

  • 状态三值:active 参与调度;maintenance 不接新流、旧流自然结束;offline 是心跳超时后的判定。把一个活着的节点手工改成 offline 没有意义,下一轮心跳会把它翻回 active。
  • 权重 0 表示不参与加权调度,适合「备用节点」。
  • 端口容量按登记的 RTP 段算。登记段比 ZLM 实际段大时,调度会一直以为这个节点很空,直到端口真的耗尽、推流开始失败。所以新增节点时让平台去读实测值,别手填。

六、验收清单 ​

接完按这张表走一遍,比「感觉能播了」可靠:

  • [ ] curl 能拿到 ZLM 的 getServerConfig(说明 API 通、secret 对)
  • [ ] 节点列表状态是 active,且持续超过 1 分钟(心跳正常)
  • [ ] ZLM 的 config.ini 里 general.mediaServerId 与平台登记的一致
  • [ ] ZLM 的 hook 回调地址里带 node= 与 cap=(说明是平台下发的,不是手写的死 hook)
  • [ ] 点播一台设备:有画面、ZLM 侧能看到会话、平台侧状态变为播放中
  • [ ] 停止点播:会话按预期回收(无人观看超时能断流)
  • [ ] 录一段像:录像文件落在预期的位置,能在平台里回放
  • [ ] 拔掉 ZLM 网线 30 秒:节点变离线;恢复后自动回来

七、回退 ​

把外部节点切维护态、确认无流后删除,然后:

  • 如果内置 ZLM 只是被挪了端口,把 config.env 里的 UVP_ZLM_* 改回 51004 段,restart
  • 如果内置节点已经被删了,节点表空了以后平台会重新按 gb28181.zlm seed 一个默认节点——把这段改回 127.0.0.1 与包内 secret 即可

包内 ZLM 的 config.ini 和证书一直都在 vendor/zlm/ 与 data/secrets/,没有被动过,回退不涉及重新初始化。


三篇走下来,三个内置组件都能换。真正花时间的从来不是填写配置项,而是搞清两件事:启动的时候谁在改写你的配置,以及这两个组件之间是不是每个方向都能通。想明白这两点,剩下的照着表查就行。