ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GB28181视频平台搭建:WVP与ZLMediaKit部署联调

GB28181视频平台搭建:WVP与ZLMediaKit部署联调 GB28181 这套东西第一次接触的人大概都会被国标两个字唬住觉得是运营商的活儿实际上把它拆开看无非是一个 SIP 信令 RTP 媒体流的组合再配一套前端管理和一个流媒体转发服务。我自己第一次在 CentOS 7 上搭 wvp-GB28181-pro 加 ZLMediaKit 的时候前后折腾了两天踩的坑主要不在代码本身而在依赖版本、端口占用和配置文件里几个不起眼的字段。这篇就把整个部署流程从环境准备到联调验收完整走一遍顺带把那些文档里往往一笔带过、但实际会让服务起不来的细节讲清楚。适合有一定 Linux 基础、想自建国标视频接入平台的运维和开发看新手照着做也能跑通老手可以重点看第四章和第五章的配置字段与排查思路。1. 先把组件分工理清为什么是 WVP 加 ZLMediaKit 这套组合很多人上手第一步是把两个项目都 clone 下来结果发现配置文件里到处都是对方的地址互相看不懂。根源在于没弄清这两个服务各自负责什么。国标协议规定了设备怎么注册、目录怎么查询、信令怎么交互但它没规定视频流具体由谁来转发。WVP 负责的是信令大脑ZLMediaKit 负责的是媒体搬运工两者通过 HTTP Hook 和一串约定好的地址通信。1.1 WVP 管信令ZLMediaKit 管流wvp-GB28181-pro 是基于 Spring Boot 的 Java 服务它本身收发 SIP 消息设备向它注册它向设备发起 INVITE 邀约设备把 RTP 流推给它指定的地址。但 WVP 自己并不擅长转发大流量媒体流所以它把收流地址交给 ZLMediaKit。具体流程是这样的设备注册到 WVP 之后用户在网页上点击播放WVP 向设备发送 INVITESDP 里写的接收地址其实是 ZLMediaKit 的 IP 和端口。设备把 RTP 推过来ZLMediaKit 收流并转成 RTSP、HTTP-FLV、HLS、WebRTC 等格式前端播放器再从 ZLMediaKit 拉流。WVP 通过配置的 hook 地址监听 ZLMediaKit 的事件比如流注册成功流无人观看从而知道流什么时候该关。理解这一层之后配置里那些media.ip、media.stream-ip、hook地址就不会填错了——它们指向的都是 ZLMediaKit 那一端而不是 WVP 自己。1.2 部署顺序为什么建议先 ZLMediaKit 后 WVP我试过反过来先起 WVP 再装 ZLMediaKit结果是 WVP 启动时尝试连 hook 地址失败日志里一堆连接拒绝虽然服务不会崩但排查起来干扰很大。ZLM 是底层依赖先把它跑起来并且用curl确认 API 可访问再启动 WVPWVP 一启动就能连上日志干净。这个顺序的好处在于出问题时你能明确知道是哪一层的锅而不是两个服务都没起来互相甩锅。1.3 CentOS 7 上的版本选择要点CentOS 7 自带的软件版本比较老这是后面一堆编译问题的根源。几个关键点先摆出来组件CentOS 7 默认版本建议版本说明GCC4.8.58 及以上ZLM 编译依赖 C17CMake2.8.123.1 以上低于 3.1 无法配置 ZLMJDK通常无8 或 11以 WVP 版本要求为准MySQL无5.7 或 8.0注意字符集配置Redis无5 以上WVP 缓存与状态存储提示ZLM 的编译工具链用devtoolset系列升级最省事不必冒险替换系统 GCC避免影响其他已编译软件。这一章的目的是让你心里有张地图。接下来进入真正的动手环节从系统环境开始收拾。2. CentOS 7 系统层的准备工作把地基打平系统环境这一步最容易被跳过但后面 80% 的服务起不来都能追溯到这里。CentOS 7 默认的防火墙、SELinux、时钟、句柄数都可能成为拦路虎。我一般会花十几分钟把这几项一次性处理掉后面就省心了。2.1 关掉 SELinux 和调整防火墙SELinux 在容器化部署里经常是隐藏的坑尤其是在 /usr/local 下自建目录、或者让 Nginx 反代本地端口的时候会出现权限明明对但就是访问不了的诡异现象。图省事的做法是直接设成 permissive 模式# 临时生效 setenforce 0 # 永久生效 sed -i s/^SELINUXenforcing/SELINUXpermissive/ /etc/selinux/config防火墙方面国标部署涉及的端口挺多与其一个个记不如先统一放开内网或者按下面这张表逐条放行。生产环境当然要精细化测试环境可以先把 firewalld 停掉减少干扰systemctl stop firewalld systemctl disable firewalld如果必须保留防火墙需要放行的端口大致如下端口协议用途8116UDP/TCPWVP 的 SIP 端口5060UDP/TCP部分场景下的标准 SIP 端口18080TCPWVP 的 Web 与 API80TCPZLM 的 HTTP 与 FLV/HLS554TCPZLM 的 RTSP1935TCPZLM 的 RTMP10000 起UDPZLM 收 RTP 流的端口段30000 起UDP发送 RTP 流的端口段注意RTP 收流端口段和发流端口段一定要和后面配置文件里的port-range对得上范围对不上设备推流会直接超时这是非常隐蔽的一类故障。2.2 时钟同步与句柄数调优国标信令里带时间戳如果服务器时间和设备时间偏差太大个别设备会拒绝注册或者注册后立刻掉线。CentOS 7 装好后先确认时间timedatectl status # 若未同步启用时间同步 timedatectl set-timezone Asia/Shanghai句柄数这块媒体服务在高并发收流时打开的文件描述符相当可观默认的 1024 往往不够。修改/etc/security/limits.conf追加* soft nofile 65535 * hard nofile 65535改完之后要重新登录终端才生效用ulimit -n确认。这一项在做压测或者接入几十路以上设备时尤其重要否则会看到 ZLM 报 too many open files 然后无故断流。2.3 编译工具链的安装ZLM 需要 CMake 3.1 以上和较新的 GCC。CentOS 7 上装 devtoolset-8 是常用做法yum install -y centos-release-scl yum install -y devtoolset-8-gcc devtoolset-8-gcc-c scl enable devtoolset-8 bashscl enable只在当前会话生效装完编译完就可以了。如果嫌每次都要敲可以写进/etc/profile.d/里自动加载。CMake 版本不够的话直接从官网下个二进制包解压即可不用编译cd /usr/local wget https://cmake.org/files/v3.20/cmake-3.20.0-linux-x86_64.tar.gz tar -zxvf cmake-3.20.0-linux-x86_64.tar.gz ln -s /usr/local/cmake-3.20.0-linux-x86_64/bin/cmake /usr/bin/cmake这些准备工作看着琐碎但每一项都对应后面一个潜在的坑。地基打平之后编译和部署就顺多了。3. 让 ZLMediaKit 先跑起来编译、配置与自检ZLMediaKit 是整个平台的媒体中枢它的状态直接决定了画面能不能出来。这一章我会把编译方式的选择、配置文件里必须改的项、以及如何确认它真的健康都讲一遍。跑通这一章后面 WVP 的联调会轻松很多。3.1 编译方式怎么选ZLM 官方提供了源码编译和预编译包两条路。我的经验是如果只是测试可以直接用带linux-x86_64字样的预编译包解压就能跑但生产环境还是建议源码编译一来方便后续加功能二来能避开预编译包对某些系统库版本的隐性依赖。源码编译的大致流程git clone --depth 1 https://github.com/ZLMediaKit/ZLMediaKit.git cd ZLMediaKit git submodule update --init mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease make -j4编译耗时不短四核机器大概十几分钟。完成后release/linux/Release/目录下会有MediaServer可执行文件。有个细节值得说cmake如果不带任何参数默认会尝试构建测试用例可能因为缺少一些可选依赖报错。加-DENABLE_TESTSOFF能规避这类问题。编译失败时先看错误发生在哪个模块多半是某个子模块没拉全重新git submodule update --init再编译即可。3.2 config.ini 里必须改的几项ZLM 第一次运行会在当前目录生成config.ini。这个文件很长但真正需要动的不多。下面这几项不改WVP 大概率连不上[api] # API 的密钥WVP 里要填一致 secret你的随机密钥 [general] # 媒体服务器唯一标识WVP 靠它区分实例 mediaServerId你的标识 [http] # HTTP 端口前端拉 FLV/HLS 用 port80 # 允许跨域前端播放器常需要 allow_cross_domains1 [rtp] # RTP 收流端口段必须与 WVP 配置对应 port10000 # 收流超时设备迟迟不推流就释放 timeoutSec15 [hook] # 开启 hook 才能让 WVP 感知流事件 enable1 # 指向 WVP 的地址 on_publishhttp://127.0.0.1:18080/index/hook/on_publish on_playhttp://127.0.0.1:18080/index/hook/on_play on_stream_changedhttp://127.0.0.1:18080/index/hook/on_stream_changed # hook 鉴权参数要与 WVP 端一致 admin_paramssecret你的hook密钥secret和admin_params这两处是重灾区。很多人改了secret忘了改 hook 里的admin_params导致 ZLM 调 WVP 的 hook 时被拒绝表现为流上了但 WVP 显示离线排查半天。提示port段和send-port-range段落要一起规划。收流和发流用不同的端口段可以避免端口冲突方便在 iptables 里分别做策略。3.3 用 API 自检确认服务真的活着服务启动后别急着配 WVP先用 API 确认 ZLM 本身没问题。启动命令cd release/linux/Release ./MediaServer -d 带-d是后台运行。然后 curl 一下curl http://127.0.0.1/index/api/getServerConfig?secret你的随机密钥能返回一大段 JSON说明 API 正常。再查一下线程和媒体列表curl http://127.0.0.1/index/api/getStatistic?secret你的随机密钥如果 API 报 secret 错误说明密钥不对如果直接连不上检查端口是否被占用、进程是否真的起来了。这一步确认通过之后再进入 WVP 的部署心里就有底了。4. WVP-GB28181-pro 落地数据库、配置字段与启动WVP 是 Java 服务配置项多但真正需要改的字段集中在application.yml里。这一章我会把数据库准备、关键字段逐个拆解以及启动时怎么通过日志判断成败。DS 层配置错了WVP 根本起不来SIP 层配错了设备注册不上media 层配错了画面出不来。三个层面的问题定位方式完全不同。4.1 数据库与缓存的准备WVP 需要 MySQL 和 Redis。MySQL 建库时字符集务必用utf8mb4否则设备名称里的特殊字符会出问题CREATE DATABASE wvp CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;建好库之后WVP 启动时通常会自动建表部分版本通过 Flyway 执行迁移脚本。Redis 主要用来存 SIP 会话状态和临时缓存默认连本机 6379 即可如果有密码记得在第 4.2 节的配置里填。一个容易忽略的点是 MySQL 8 的驱动和时区。CentOS 7 上如果用 MySQL 8连接串里要带时区参数否则 WVP 启动时会报时区识别失败url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicodetruecharacterEncodingUTF8serverTimezoneAsia/Shanghai4.2 application.yml 关键字段逐个拆这份配置里我把它分成三段来看。第一段是数据库第二段是 SIP第三段是 media。下面只列要点spring: datasource: url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicodetruecharacterEncodingUTF8serverTimezoneAsia/Shanghai username: root password: 你的密码 redis: host: 127.0.0.1 port: 6379 password: sip: # WVP 监听 SIP 的地址公网部署要写内网可达 IP ip: 你的服务器IP port: 8116 # SIP 域一般与设备端配置的 SIP 域一致 domain: 3402000000 # 平台自身国标编号 id: 34020000002000000001 password: 平台注册密码 media: # ZLM 的 ID要和 config.ini 里 mediaServerId 一致 id: 你的标识 # ZLM 的 IP ip: 你的服务器IP # 流媒体对外发布的 IP供前端和外部设备访问 stream-ip: 你的服务器IP # SDP 中告知设备的收流 IP sdp-ip: 你的服务器IP # hook 地址指向 WVP 自己 hook-ip: 127.0.0.1 rtp: enable: true # 收流端口段要和 config.ini 的 rtp.port 对应 port-range: 10000,10500 send-port-range: 30000,30500sip.ip和media.ip是最容易填混的两处。前者是 WVP 自己收 SIP 的地址后者是 ZLM 的地址。如果 WVP 和 ZLM 在同一台机器两者一样如果分开部署就要各填各的。sdp-ip指的是设备推流的目标 IP也就是设备要往哪个地址发 RTP。这个字段如果填成了内网地址而设备在外网设备就会推到一个它无法到达的地址表现为信令成功但一直没画面。4.3 启动顺序与日志判读配置改完后启动顺序是 Redis、MySQL、ZLM、WVP。WVP 的启动用 java 命令或打包后的脚本java -jar wvp-pro-xxx.jar --spring.config.locationapplication.yml启动日志里重点看三行一是 Spring 容器是否正常启动完成二是 SIP 监听端口是否成功绑定三是是否成功连上 ZLM 的 API。看到类似媒体服务器连接成功的字样就说明后端链路通了。如果日志里出现 hook 连接失败八成是 ZLM 没起或者端口不对如果出现数据库连接失败检查账号密码和网络如果 SIP 端口绑定失败多半是端口被占用。这三类问题覆盖了绝大多数启动失败的情况。4.4 前端访问与初始账号WVP 起来了之后浏览器访问http://服务器IP:18080默认账号密码通常是admin/admin以你使用的版本为准。第一次登录建议立刻改密码因为平台管理权限很大。登录后进入平台配置页重点核对媒体服务器列表里是否已经出现 ZLM 记录状态是不是在线。如果显示离线回到第 3.3 节的 API 自检再确认一遍多数是secret或 IP 填错。到这里后台环境就算搭好了接下来是最有成就感的环节让真实设备接进来。5. 联调验收设备注册、点播与常见故障定位环境搭好了但服务能跑和设备能接是两回事。这一章聚焦联调把设备接入的完整链路、点播失败时的排查顺序、以及语音对讲和级联这两个进阶场景讲清楚。这部分是我踩坑最多的地方也是文档里讲得最少的地方。5.1 设备注册链路的排查方法设备注册本质上是一次 SIP REGISTER 交互。设备向 WVP 的 SIP 地址发送注册请求WVP 校验编号和密码后返回响应。判断注册成功与否最直接的是看 WVP 的设备管理列表里设备状态是否在线。如果设备一直不在线按这个顺序查设备端配置的 SIP 服务器地址是不是 WVP 所在服务器的可达 IP。设备端的 SIP 端口是不是 8116或你配置的端口传输协议 UDP 还是 TCP 要和 WVP 一致。设备端的 SIP 域、编号、密码是不是和 WVP 里添加的设备信息完全一致注意编号位数。服务器防火墙有没有放行 8116。WVP 日志里有没有收到 REGISTER 消息。我遇到过一次设备端填的 SIP 域少了一位导致 WVP 收到注册请求但校验失败日志里能看到请求进来但被拒绝。这种问题不看日志很难定位所以在排查注册问题时养成先看 WVP 日志的习惯。5.2 点播失败时按这个顺序查点播失败的表现是页面黑屏或者一直转圈原因可能出现在链路的任何一环。我总结的排查顺序是从后往前先看 ZLM 有没有收到流再看 WVP 有没有发出 INVITE最后看设备有没有响应。排查点观察方式常见原因ZLM 是否收流查 ZLM API 的媒体列表收流端口段不对WVP 是否发 INVITE看 WVP 日志设备编号或域配置错设备是否响应抓包或看设备日志设备不支持该编码前端能否拉流直接访问 ZLM 的流地址跨域或端口未放行一个很典型的坑是编码协商。有些设备默认推 H.265而浏览器播放器只支持 H.264结果就是信令全成功ZLM 也收到了流但前端播不出来。这时候要么在设备端把编码改成 H.264要么在前端使用支持 H.265 的播放方案。定位这类问题直接拿ffplay或 VLC 去拉 ZLM 的 RTSP 地址能播说明是前端问题不能播说明是流本身的问题。注意拉流地址里通常带stream参数格式随 WVP 版本变化最稳妥的方法是打开浏览器开发者工具看播放器实际请求的 URL照着它去用 ffplay 验证。5.3 语音对讲与级联场景的注意点语音对讲broadcast/talk和级联是国标平台常见的进阶需求但它们的信令流程比点播复杂出问题时也更隐蔽。语音对讲的方向和点播相反点播是平台拉设备的流对讲是平台把音频推给设备。它需要 ZLM 的 RTP 发流端口段可用同时设备要支持对应的音频编码通常是 G.711。如果对讲按下去没声音先确认设备的对讲功能是否开启再检查发流端口段有没有被防火墙挡住。级联方面常见的需求是下级平台向上级平台注册然后上级平台向下级查询目录、拉取资源。要注意的是上级主动向下级拉取资源这种能力在不同版本上的支持程度不一样。有些版本需要下级平台主动上报目录上级才能看到资源。如果你在做这种场景建议先确认两端平台的版本和级联配置把catalog订阅和响应的日志都打开看目录请求是否发出、响应是否返回。这类问题的排查基本靠日志光看界面状态是不够的。联调通过之后平台就算能用了。但要让它稳定跑下去还有几件运维上的事要做。6. 上线之后的稳定性维护那些跑一段时间才暴露的问题很多人搭好之后觉得万事大吉结果运行一两周开始出现断流、内存上涨、注册掉线。这一章讲讲长期运行的维护经验这部分内容基本不会写在部署文档里但恰恰是生产环境的真实痛点。6.1 内存、句柄与端口回收ZLM 长时间运行如果收流句柄没有及时释放内存会缓慢上涨。config.ini 里的timeoutSec和流无人观看自动关闭的策略很关键。建议开启无人观看自动关流避免僵尸流占着资源[hook] # 流无人观看时通知并关闭减轻服务器负担 on_stream_none_readerhttp://127.0.0.1:18080/index/hook/on_stream_none_readerWVP 端也要配置对应的无人观看处理逻辑。另外RTP 收流端口是有限的如果某个流异常退出而端口没释放后续流就会因为端口被占而收不到。定期检查 ZLM 的媒体列表清理那些没有读者的僵尸流是个好习惯。句柄方面前面调过nofile之后还要配合监控。用一条简单的命令就能看进程打开了多少描述符ls /proc/$(pgrep MediaServer)/fd | wc -l如果这个数字持续增长不降说明有资源没释放需要进一步排查是哪个模块的问题。6.2 升级与配置备份策略WVP 和 ZLM 都在活跃迭代升级是免不了的。我的做法是升级前先把配置文件单独备份因为版本更新经常会调整配置字段直接覆盖新包可能把配置带跑。备份至少包括application.yml、config.ini和数据库。数据库可以用mysqldumpmysqldump -uroot -p wvp wvp_backup_$(date %F).sql升级 ZLM 时编译产物和配置文件分开管理用软链接指向当前版本回滚时改个软链接就行不用重新编译。这套方式在多实例部署时尤其好用。6.3 日常巡检的几个检查项最后列几个我日常会看的项形成习惯之后能提前发现大部分问题ZLM 的 API 是否正常响应媒体列表是否出现异常增多的流。WVP 的日志里是否有大量注册失败或者 hook 超时。磁盘空间尤其是 HLS 切片和日志目录容易被写满。Redis 内存占用会话状态堆积会导致内存上涨。服务器时间是否仍然同步时钟漂移会引发信令异常。把这些做成一个简单的巡检脚本每天跑一次比出事之后再救火从容得多。我在实际运维中最大的体会就是国标平台这类服务真正难的从来不是第一次搭起来而是让它连续几个月不出幺蛾子——而后者靠的就是这些看似不起眼的日常维护动作。
返回列表