简介:这是一套面向安防监控开发与运维人员的GB28181国标接入快速部署包,将wvp-GB28181-pro视频平台与ZLMediaKit流媒体服务整合为可直接安装的脚本集合,很好地解决了从零编译、手动配置MySQL、Redis、JDK等依赖组件耗时且易出错的问题。资源共含6个文件,以4个shell脚本为主体,分别覆盖数据库、缓存、Java运行环境及平台核心服务的自动安装;另有1个zip资源包存放配套组件,1份docx版安装教程则对部署步骤和注意事项进行说明。整个包体约765.58MB,下载后按教程修改wvp配置文件中的服务器IP即可对接GB28181摄像头,平台各项功能可正常使用。目前已有2534人学习下载,适合需要快速搭建视频监控平台进行测试或上线的技术人员,也适合希望了解国标设备接入全流程的初学者,借助脚本与文档即可降低部署门槛并提升排错效率。 做安防视频接入这一块的人,应该都绕不开wvp-GB28181-pro和ZLMediaKit这两个名字。前者是Java生态下的国标GB28181信令平台,负责和前端设备做SIP信令交互,处理设备注册、目录查询、云台控制、录像回放这些事;后者是C++写的高性能流媒体服务器,负责收流和转流,设备推上来的RTP流进来,按RTSP、RTMP、HLS、WebRTC这些协议分发给播放端。两个项目配合,基本就是目前开源界做国标视频接入的主流方案。
不过这套方案有个非常实际的痛点:部署起来太折腾。ZLMediaKit需要从源码编译,依赖了一堆库;wvp-GB28181-pro需要JDK、Maven、MySQL、Redis,还有一堆配置文件要改。我去年给一个项目做国标接入,光环境搭建就耗了一整天,后面换服务器又踩了第二轮坑。所以这次我把整个安装过程整理成了脚本,从环境检测到服务启动一条龙跑完,目标是把部署时间从小时级压到分钟级。这篇博文就把脚本的设计思路、核心实现、常见问题完整拆开讲,不管你是第一次碰国标接入的新手,还是想简化部署流程的老手,都能直接用上。
1. 项目思路:为什么要把wvp和ZLMediaKit打包在一起
1.1 wvp-GB28181-pro与ZLMediaKit的分工
在GB28181的协议体系里,设备到平台是两条独立的通道:信令通道走SIP,媒体通道走RTP。wvp-GB28181-pro负责前者,ZLMediaKit负责后者。
wvp这边,本质是一个基于Spring Boot的Java服务,内置了SIP服务器,默认监听UDP 5060端口的信令消息。设备上线时,向平台发送注册请求,wvp校验通过后返回200 OK,设备进入在线状态。后续的实时点播、录像回放,都是wvp通过SIP INVITE请求携带SDP信息下发到设备,告诉设备“往哪个IP的哪个端口推流”。设备收到指令后,开始往ZLMediaKit推RTP流。
ZLMediaKit那边,是一个C++写的流媒体服务,监听RTSP(默认554)、RTMP(默认1935)、HTTP(默认80/443)等端口,同时开启一个配置好的RTP收流端口范围,等设备推流上来。它和wvp是两套独立的系统,通过HTTP API和WebHook回调对接。wvp发指令让ZLMediaKit“从某个设备的某个通道拉流”,ZLMediaKit去拉流后通过回调告诉wvp“流拉到了,播放地址是xxxx”。
我当时做方案选型的时候,其实也对比过直接用wvp自带的媒体能力,但发现wvp的定位非常明确——它就是做信令的,媒体能力必须委托给ZLM,而且wvp官方文档也一直推荐这种组合。所以不用纠结,老老实实装两个服务就好。
1.2 一键安装脚本的价值
如果说wvp和ZLMediaKit是这套方案的两条腿,那部署就是让两条腿站起来的门槛。门槛高在哪?我列几个实际遇到的问题:
- ZLMediaKit的源码编译依赖cmake、gcc、openssl、ffmpeg等库,缺一个编译直接报错
- wvp的构建要用Maven,需要联网下载大量依赖包,网络不好直接超时
- wvp的配置文件application.yml里有数据库、Redis、ZLM地址和密钥等一堆参数要改,手动改容易漏
- 数据库需要手工创建并初始化表结构,很多人第一次跑起来发现报“table不存在”
所以脚本的价值不在于“省几次敲命令的时间”,而在于把整个部署过程标准化、可重复。同一套脚本,开发环境能装,生产环境也能装;一个人能装完,十个人也能装完。配置一致了,后面出问题也好排查,不用猜“他当时改了哪里”。
2. 脚本整体设计:目录结构与环境检测
2.1 脚本目录结构与职责划分
我打包的安装脚本,目录结构是这样的:
wvp-install/ ├── install.sh # 主安装脚本,一键执行 ├── config.ini # 所有可调参数都集中在这里 ├── zlm/ │ └── install_zlm.sh # ZLMediaKit拉取、编译、安装 ├── wvp/ │ └── install_wvp.sh # wvp拉取、编译、配置 ├── sql/ │ └── init_wvp.sql # wvp数据库初始化脚本 └── conf/ └── application.yml # wvp配置文件模板为什么把参数集中放在config.ini里?我当时吃过亏。一开始参数是散在脚本里的,结果客户要改个端口,我得翻半天代码。后来改成所有可调项都放config.ini,脚本里只读取不硬编码,改动就方便多了。
config.ini里主要配置项:
# 服务端口 SIP_PORT=5060 HTTP_PORT=8080 MEDIA_PORT=10000 # 数据库配置 MYSQL_PASSWORD=123456 WVP_DATABASE=wvp # ZLMediaKit密钥 MEDIA_SECRET=035c73f7-bb6b-4889-a715-d9eb2d192cc8 # 安装目录 INSTALL_DIR=/opt/wvp-install2.2 环境检测与依赖安装
脚本第一步是检测操作系统。因为整个方案跑在Linux上,我主要适配了CentOS 7/8和Ubuntu 18.04/20.04。检测方法是读/etc/os-release,根据ID字段判断是CentOS还是Ubuntu,然后走不同的安装逻辑:
if [ -f /etc/os-release ]; then . /etc/os-release OS=$ID else echo "无法识别操作系统" exit 1 fi case $OS in centos|rhel) yum install -y gcc gcc-c++ make cmake git openssl-devel ;; ubuntu|debian) apt update apt install -y build-essential cmake git libssl-dev ;; esac这一步看起来简单,但很关键。ZLMediaKit的编译对gcc和cmake版本有要求,CentOS 7系统自带的cmake版本才2.8,而ZLM需要3.10以上。所以脚本里还要做一个版本检查,如果cmake版本太低,就用源码编译一个新版cmake装到/usr/local,然后PATH里优先用新版。这个坑我踩过,不升级cmake直接编译ZLMediaKit,报错能让人怀疑人生。
JDK这边,wvp官方推荐JDK 8,我脚本里默认装的是OpenJDK 8。Maven用3.6以上版本,配置好阿里云镜像源,这样下载依赖会快很多,不然Maven中央仓库的下载速度能把人急死。
3. 核心安装流程与关键配置
3.1 ZLMediaKit的编译与安装流程
ZLMediaKit的安装脚本核心流程是:拉代码 -> 拉子模块 -> cmake生成构建文件 -> make编译 -> 拷贝可执行文件。
cd $INSTALL_DIR git clone https://gitee.com/xia-chu/ZLMediaKit.git cd ZLMediaKit git submodule update --init mkdir -p build cd build cmake .. make -j$(nproc)这里有几个容易出错的地方,我特别在脚本里做了处理:
第一,一定要执行git submodule update --init。ZLM依赖了一些第三方库,比如zltoolkit,是以子模块形式引入的。不拉子模块,编译的时候直接报找不到头文件。
第二,make -j后面的参数根据CPU核数动态生成,这样多核服务器上编译速度能快不少。我实测在一个4核8G的云服务器上,全量编译大概需要10到15分钟,如果机器配置低,这个时间可能翻倍。
第三,编译完的可执行文件在release/linux/Debug/MediaServer目录下,配置文件是release/linux/Debug/config.ini。启动前需要把config.ini里的相关参数改成实际值:
[general] mediaServerId=your_media_server_id [rtsp] port=554 [rtmp] port=1935 [hook] enable=1 # 回调地址 hookUrl=http://127.0.0.1:8080/index/hookmediaServerId要注意,wvp的配置文件里也有一个mediaServerId,两个地方必须保持一致,否则wvp调用ZLM的API时校验失败,报404或401错误。在脚本里我用同一个随机UUID同时写入wvp的application.yml和ZLM的config.ini,这样两边永远一致,不会出现手动配置时改了这头忘了那头的情况。手动部署的同志,建议把这里的值复制到记事本里,改哪边都对照着来。
3.2 wvp-GB28181-pro的编译与配置
wvp的构建相对简单,因为它是纯Java项目,用Maven打包:
cd $INSTALL_DIR git clone https://gitee.com/panjialin/wvp-GB28181-pro.git cd wvp-GB28181-pro mvn -DskipTests package -P prod打包完在target目录下生成wvp-pro-*.jar。但这里有个问题,wvp的官方代码默认配置是连本地的MySQL和Redis,你要是直接跑,大概率连不上数据库。所以脚本里要用我准备的application.yml模板替换原来的配置文件,把数据库密码、Redis地址、ZLM的IP和密钥都写进去。
以下是关键配置项:
server: port: 8080 sip: ip: 0.0.0.0 port: 5060 media: ip: 127.0.0.1 port: 10000 secret: 035c73f7-bb6b-4889-a715-d9eb2d192cc8 mysql: ip: 127.0.0.1 port: 3306 database: wvp username: root password: 123456 redis: ip: 127.0.0.1 port: 6379这里我遇到过一个大坑:wvp和ZLM的通信走的是HTTP的10000端口,如果ZLM和wvp不在同一台机器上,media.ip就要填ZLM所在机器的IP,而且ZLM的HTTP端口默认是10000,不是官方文档里某些示例写的8080。我第一次配置时把这个搞混了,结果平台界面上设备是注册上了,但视频流一直黑屏,查了半天才发现是wvp调ZLM API时地址错了。
3.3 数据库初始化与Redis处理
wvp首次启动前,需要先创建数据库并导入初始化SQL。wvp源码的sql目录下有初始化脚本,我的安装脚本里也放了一份:
mysql -uroot -p$MYSQL_PASSWORD -e "CREATE DATABASE IF NOT EXISTS wvp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -uroot -p$MYSQL_PASSWORD wvp < $INSTALL_DIR/sql/init_wvp.sql数据库字符集选utf8mb4这个细节值得一说。GB28181平台里会存很多中文通道名、厂商信息,如果用默认的latin1或者utf8,遇到生僻字或者特殊符号可能存不进去,而utf8mb4是MySQL下对UTF-8支持最完整的字符集,能覆盖所有Unicode字符。
Redis这边,wvp用Redis做缓存、存储设备列表等数据,启动前必须确认Redis可用。脚本里会先启动Redis服务,然后用redis-cli ping检查返回PONG,再继续后面的流程。别小看这个检查,我遇到过Redis没配密码或者密码不对的情况,wvp启动日志里满屏的Connection refused,根本定位不到问题。
3.4 服务启动与验证
所有组件安装配置完成后,按依赖顺序启动服务:先MySQL,再Redis,然后ZLMediaKit,最后wvp。
# 启动MySQL和Redis systemctl start mysqld redis # 启动ZLMediaKit cd $INSTALL_DIR/ZLMediaKit/release/linux/Debug nohup ./MediaServer -c ./config.ini >/dev/null 2>&1 & # 启动wvp cd $INSTALL_DIR/wvp-GB28181-pro/target nohup java -jar wvp-pro-*.jar >/dev/null 2>&1 &脚本里我还内置了一个简单的验证流程,检查三个关键端口是否在监听:
netstat -tlnp | grep 8080 netstat -tlnp | grep 5060 netstat -tlnp | grep 10000如果三个端口都在监听,基本可以确定服务正常了。然后浏览器访问http://IP:8080,默认管理员账号密码是admin/admin,登录后就能看到设备管理界面。
这里我也做了一个细节处理:wvp和ZLM用nohup启动时,日志都重定向到固定的日志文件,方便后面排查。wvp日志在target目录下的logs里,ZLM日志在启动目录下的MediaServer.log——不是./log/目录,我当时找日志找了好一会儿。
4. 安装部署常见问题与排查技巧实录
4.1 设备注册不上怎么办
这是国标接入里最常遇到的问题。设备侧填的SIP服务器地址、端口、用户名密码都没错,但平台上就是看不到设备上线。
排查第一步,确认SIP端口是否可达。从设备所在的网络环境,用nc测试5060端口:
nc -uz 192.168.1.100 5060UDP端口测试如果没反应,先看防火墙:
firewall-cmd --list-ports # 或者 iptables -L -n很多情况下,部署平台的服务器安全组或iptables只放行了TCP端口,UDP 5060没放行,设备注册请求根本到不了wvp。
还有个容易被忽略的点:GB28181设备的国标ID。设备注册时用的国标ID必须和wvp里配置的平台国标ID在同一域内。比如wvp的SIP服务器域是3402000000,那设备ID也必须是3402000000开头的20位数字。这个不匹配,注册请求会被wvp直接拒绝,日志里会有sip server 401之类的提示。
4.2 视频流黑屏
设备注册上了,点播放按钮,界面上一片黑。这个问题排查起来要有点耐心。
第一步,看wvp的日志,确认点播时有没有向ZLM发起拉流请求。正常流程是wvp先调ZLM的openRtpServer接口开一个RTP接收端口,然后向设备下发INVITE指令。如果日志里没有调ZLM的痕迹,大概率是wvp和ZLM的API通信失败了,检查media.ip和secret配置。
第二步,看ZLM的日志,确认设备有没有推流上来。ZLM日志里有“收到RTP包”这种打印就说明推流成功。如果设备没有推流,可能是设备侧流媒体地址配置错误。很多设备的RTP推流地址要和SIP服务器保持一致,但端口是ZLM收流端口范围的某个值,通常设备会自动计算,但有些老设备需要手动指定。
第三步,如果ZLM收到了流但还是黑屏,可能是编解码或协议转换的问题。检查ZLM配置里是否开启了所需的协议支持,比如WebRTC播放需要额外编译支持,没编译的话播放页可能就白屏了。
4.3 ZLMediaKit编译失败
编译失败大部分是依赖问题。最常见的报错是找不到openssl头文件,或者cmake版本太低。
我脚本里对cmake版本做了升级处理,但如果你是自己手动编译,建议先用cmake --version确认版本不低于3.10。CentOS 7默认的2.8肯定不行。openssl-devel也要装,不然ZLM编译时会报SSL相关错误。
还有一个小概率问题:拉取ZLM子模块失败。国内网络环境下,git submodule update可能超时。脚本里我用了gitee的镜像地址,会好很多。如果还有问题,可以考虑在git clone时添加--recurse-submodules参数,让子模块一起拉取。
4.4 wvp启动时报数据库连接失败
这个一般是MySQL没起来或者密码不对。检查两件事:MySQL服务是否在运行,application.yml里的mysql配置和实际是否一致。
有个细节:我脚本里生成的随机密码会同时写入MySQL和application.yml,确保两边一致。手动部署时经常有人改了SQL密码忘了改配置文件,结果一脸懵地看报错。
5. 实操心得与扩展建议
5.1 脚本迭代中的三个教训
整套脚本我前后改了三个版本,说几个实际体会。
第一,安装脚本要尽量模拟“从头开始”的场景。我一开始测试脚本是在已经装好环境的机器上跑的,自然什么问题都没有。后来找了一台全新机器跑,才发现各种依赖缺失、端口冲突问题。现在每改一版脚本,我都会在干净的服务器上完整跑一遍,确认无误再发布。
第二,别把脚本写得太死。配置文件模板化、参数集中化,是我改到第二版才想明白的。早期脚本里全是硬编码,客户要换个MySQL密码就得改脚本。现在config.ini统一管理,客户自己改一行就行,省了我好多售后时间。
第三,日志是排查问题的第一手段,但也别全指望看服务输出。wvp的日志在logs目录下,ZLM的日志在启动目录下,如果服务没起来,可以先检查日志文件是否存在。如果连日志文件都没有,说明进程根本没起来,去查Java版本、内存占用这些更基础的问题。
5.2 部署后的维护建议
最后再分享一个实用维护技巧:ZLMediaKit和wvp都支持热切换,部署完以后如果发现端口或密钥要改,不用重装,直接改配置文件、重启服务就行。关键是两个服务之间的联动配置要保持一致,我建议在config.ini里统一维护一份,别在两边的配置文件里各改各的,否则排查问题的时候你会怀疑人生的。
另外,线上环境建议把wvp和ZLM都注册成systemd服务,这样服务异常退出后可以自动拉起,服务器重启也能自动恢复。脚本里目前用nohup是为了演示方便,生产环境用systemd管理才是正路。这个扩展方向留给接下来要写的第二篇,如果这篇反响可以,我再把systemd服务模板和监控告警的配置整理出来。
本文还有配套的精品资源,点击获取