做了这么多年安防项目,最烦的一件事就是:甲方手里全是海康、大华的摄像头,却非要你搭一个"统一平台"。摄像头厂家自己的平台只能管自家设备,想跨品牌、把视频流集中到一个Web页面里播放,就得走GB28181。所谓GB28181,简单说就是一套国标协议,让不同厂家的摄像头和平台可以互相注册、取流、对讲。它本身不收费,却承载了安防行业90%以上的设备接入需求。
我最近刚帮一个本地运输企业搭完一套免费GB28181平台,用的就是smarteye,接入的设备里既有海康的球机也有枪机,一路折腾下来踩了四五个典型的坑。这篇文章不聊PPT,直接把我从选型到部署、从设备接入到告警运维的完整过程写出来,希望能帮想自己动手搭平台的人少走几趟弯路。
1. 选型纠结:免费GB28181平台哪来的"免费午餐"
1.1 商业平台与开源平台的一次真实对比
接这个需求之前,我先让商务打听了一圈商业GB28181平台的价格。按接入路数收费的模式下,一家运输企业如果接200路摄像头,年费轻轻松松破万,这还没算流媒体服务器和网关的授权费用。对很多中小项目来说,这笔钱不算小数目,而且平台本身的功能不一定比开源方案强到哪里去。
排除了商业平台之后,我把目光锁定在开源方案上。市面上能跑GB28181的开源项目不算少,wvp-GB28181-pro、smarteye、以及一些基于FFmpeg自研的技术方案,各有各的取舍。我当时的核心诉求是三点:一是免费且社区要活跃,遇到问题能搜到答案;二是部署不能太复杂,毕竟项目工期卡得死;三是管理界面要够用,甲方需要自己添加设备、看状态,不能全靠命令行。
1.2 smarteye的技术栈和取舍
smarteye吸引我的地方在于它把信令服务和媒体服务做在了一套体系里,用Docker编排之后,一条命令跑起来,管理后台自带Web界面。简单来说,它的工作流程是这样的:
- 启动SIP信令服务,在5060端口监听,接收摄像头的注册和心跳
- 设备上线后通过目录请求上报自己的通道信息
- 页面点击实时预览时,平台向设备发起INVITE会话,协商媒体传输地址
- 摄像头把RTP/PS流推到媒体服务端口,再由媒体服务转封装成浏览器能播放的HTTP-FLV或者HLS
- 平台把收到的视频流转存或者分发给Web前端
这整套链路里,信令负责"找谁",媒体服务负责"搬运",各司其职。和wvp那种需要额外搭一套ZLMediaKit作为媒体流服务的思路相比,smarteye的一体化设计在初期部署阶段确实省了不少事,拓扑简单,排查问题时不用同时开三四个服务的日志。
1.3 "免费"背后的隐性成本
但"免费"不是零成本,这是所有开源平台使用者都必须心里有数的事。服务器得自己买,域名或者公网IP得自己准备,出了问题没人给你开工单,只能自己看日志。更现实的是,免费平台的上游依赖,比如FFmpeg、Netty、数据库这些组件,一旦某个版本出现安全漏洞,你得自己跟进升级。
我给这台平台选了台2核4G的云服务器,带宽5M起步,先跑100路以内的接入。存储方面,如果要做录像回放,还得额外挂一块数据盘。这些开销和商业平台年费比起来确实不高,但如果项目负责人没算清楚这笔账,进场之后再临时扩容,就会很狼狈。
2. 读懂GB28181:20位设备编码和SIP信令的几件要命事
2.1 20位国标编码到底是什么
很多人第一次接触GB28181,上来就填SIP服务器ID,填完发现设备死活注册不上,后台日志里全是401或者超时。问题的根源往往不是IP填错,而是ID编码不符合规则。
国标ID统一是20位数字,从左到右依次是:中心编码(8位,前2位省级、中间2位市级、后4位行业编码)、设备类型编码(2位,比如111代表中心服务器,131代表摄像机,132代表NVR)、设备序号(7位,自己编,保证唯一)、校验位(1位,由前19位计算出来)。
举个例子,一个SIP服务器ID可以是34020000002000000001,前8位34020000代表省份和城市,中间2位00代表行业,接着2位20是类型编码十位2百位0,具体含义可以先不管,关键是必须符合20位的长度和编码规则。海康摄像头的Web配置页面通常会把校验位自动计算好,但如果你在smarteye后台手动注册设备,ID就得按这个规则仔细填,一位都不能错。
2.2 注册、心跳、Invite:三步搞懂信令
要理解后续的踩坑,必须先搞懂GB28181的SIP信令流程,其实记好三步就行。
第一步是注册。摄像头向平台SIP服务器发送REGISTER请求,平台回401要求认证,摄像头再带着用户名密码重发REGISTER,平台认证通过后设备显示在线。这个流程和打电话先拨号、对方接听前先问一句"你哪位"的道理一模一样。
第二步是心跳。设备注册成功后会周期性地向平台发送MESSAGE消息,告诉平台"我还活着"。心跳周期通常15到60秒可配,平台在心跳超时后会把设备标记为离线。
第三步是INVITE。当你在平台的Web界面点开一路摄像头预览时,平台会向设备发送INVITE请求,里面带着一个SDP描述,写着平台希望接收媒体流的IP、端口、音视频编码信息。设备收到后开始往这个地址推RTP流。
2.3 媒体传输为什么要用PS流
这里有个初学者容易忽略的点:GB28181传视频流用的不是裸H.264,也不是RTSP里的RTP直接打包,而是把H.264/H.265数据封装成PS流之后再放进RTP包里。PS流是Program Stream,相当于把视频和音频的时间戳信息打包在一个容器里。
为什么要多此一举?因为国标场景下要兼容录像回放、语音对讲、多种码流切换,PS流能更好地承载系统层的同步信息。我们在部署时不需要自己去实现PS封装,smarteye的媒体服务已经做了处理,但理解这一点对排查黑屏问题很有帮助。比如设备推流的时候只推了视频没推音频,PS流里就不会有音频PES包,表现就是画面正常、没有声音,这种问题在代码里调试不出来,只能抓包看PS流结构。
2.4 海康设备提示"未授权"的常见根因
海康摄像头接入国标时经常提示"401 Unauthorized",很多新手第一反应是密码不对。实际上密码只是其中一个很小的原因,我排过最多的根因是这几种:
第一,密码为空。海康设备接入GB28181时,平台接入密码默认是空的,需要手动设置至少8位。如果设备端没有设置密码,平台端却配置了密码,必然401。反过来,设备端设置了密码,平台端没写,也400系列报错。
第二,设备时间与服务器时间差得太多。SIP摘要认证里带了时间戳,设备和平台时间相差超过5分钟,认证就会失败。解决办法是把摄像头和服务器都配置NTP时间同步,这一步很多人会漏掉。
第三,平台侧没留对设备的认证信息。smarteye在添加设备时要登记一个SIP用户ID和密码,和摄像头里配置的必须完全一致,注意是SIP密码,不是摄像头的登录密码。我遇到过客户把摄像头Web登录密码填进去的,结果当然注册失败。
3. 服务器落地部署:从一台裸机到smarteye跑起来
3.1 服务器配置与网络要求
部署前先把服务器需求明确清楚,免得后期被动。我选的是Ubuntu 22.04 LTS系统,2核4G内存起步,硬盘至少40G。这样的配置跑一台smarteye服务加配套的MySQL数据库,接入50路以下基本够用,CPU占用在视频流转发时会明显上去,4G内存也还算从容。
网络方面,几个关键的端口要提前确认没有被占用,最好画一张端口规划表:
| 用途 | 端口 | 协议 |
|---|---|---|
| SIP信令 | 5060 | UDP/TCP |
| HTTP管理后台 | 8080 | TCP |
| 流媒体服务 | 10000-20000 | UDP/TCP |
| 数据库(如独立部署) | 3306 | TCP |
如果你的服务器在云上,记得在安全组规则里把这些端口全放开,尤其不要只开了TCP而漏掉UDP。GB28181的信令和媒体传输默认走UDP,这也是后面踩坑的大头。
3.2 Docker编排与一键部署
smarteye项目里自带docker-compose.yaml,和很多开源平台一样,安装步骤其实可以概括成三步:下载代码或镜像、改配置、启动。
我的操作流程是这样的:
# 克隆项目代码 git clone https://github.com/smarteye/smarteye-server-docker.git # 进入部署目录 cd smarteye-server-docker # 用项目自带的一键部署脚本启动 ./deploy.shdeploy.sh里做的事情,说白了就是依次启动MySQL、Redis、信令服务和媒体服务,并通过合理的镜像依赖确保顺序。实际跑起来之后,可以确认一下容器状态:
docker ps看到信令服务容器和媒体服务容器都是Up状态,就说明最基础的流程跑通了。之后打开http://服务器IP:8080,进入Web管理页面,用初始化配置里的默认账号登录。
注意:deploy.sh里如果用了
--network host模式,容器会直接复用宿主机网络,这种情况下端口映射问题就会少很多,但要注意宿主机的防火墙仍然需要放行相应端口。
3.3 必须改的几个配置文件参数
部署完之后,启动脚本生成的配置文件里有几项是无论如何都要检查的,分别是:
- SIP服务器ID:默认值通常是一串符合国标的20位数字,按项目地区编好即可,但必须保证和后面摄像头里填的一致。
- SIP服务器域:和ID的前10位通常一致,海康设备要求域和ID匹配,否则注册不了。
- 媒体端口范围:注意和宿主机防火墙端口放行范围保持一致,比如10000-20000,别代码里写10000到20000,防火墙却只放行了30000到40000。
- 外部IP地址:这点最容易忽略。如果服务器有多个网卡或者用了云服务器的私网IP,信令SDP里携带的媒体接收地址可能是内网IP,局域网里的设备能找到你,公网设备就找不到。需要显式配置成服务器的公网IP,这就是GB28181环境中最经典的"能注册不能预览"问题的根源。
这些参数在管理后台通常可以直接配置,也可以在配置文件中手动改。我个人的习惯是先改配置文件再启动服务,避免后台配置热更新没生效导致的二次排查。
4. 海康设备接入实录:四个坑每个都让摄像头"消失"
4.1 海康Web管理页面的GB28181配置
海康摄像头的国标接入配置入口一般藏在"网络-高级设置-平台接入"里,选择协议类型为GB28181,然后会看到一整个页面的参数需要填写。我把每项和smarteye后台的对应关系整理成了一张表,照着填基本不会错:
| 海康设备端参数 | 填写内容 | 对应平台参数 |
|---|---|---|
| SIP服务器ID | smarteye的SIP服务器ID | SIP ID |
| SIP服务器域 | smarteye的SIP服务器域 | SIP域 |
| SIP服务器地址 | 服务器的公网IP | 服务器地址 |
| SIP服务器端口 | 5060 | 服务器端口 |
| SIP用户名 | 设备在平台上的注册ID | 设备国标ID |
| SIP密码 | 设备接入密码 | 接入密码 |
| 通道ID | 摄像头的国标编码 | 通道编号 |
填报界面里通常还会有一个"注册有效期"和"心跳周期",默认3600秒和60秒。这两个值其实够用,但别和平台端的超时设置冲突。
4.2 坑一:设备ID和通道ID随意填写
我接第二路球机时,顺手把设备SIP用户名填成了设备的序列号,结果摄像头一直在线,但平台端就是获取不到视频通道列表,目录查询状态始终是"未响应"。
排查了半天,最后发现是设备ID不符合国标编码规则。平台端添加设备时用的国标ID,和摄像头里SIP用户名填的ID,必须完全是同一个值,而且通道ID也不能乱填,得按"中心编码+131类型码+序号+校验位"的20位规则来。海康设备有个特性:如果你在SIP用户名里填了非20位数字,它不会报错,但平台解析时接收到的设备信息就会变成乱数据。
解决办法很简单:在平台上手动添加这路设备时,直接复用摄像头"SIP用户名"那一栏的值作为设备国标ID,通道ID则用平台自动生成的通道编码,不建议手工乱编。
4.3 坑二:H.265编码导致页面黑屏
平台和设备都注册成功,心跳正常,通道也在线,但点开预览就是一片黑。这个坑我在部署第一批海康摄像头时踩得最狠。
原因是海康摄像头默认的"视频编码"是H.265,也就是HEVC。smarteye的管理后台如果用浏览器播放HTTP-FLV,而浏览器本身不支持HEVC解码,画面自然黑屏,平台日志里却看不到任何错误,因为视频流已经推上来了,只是浏览器解不了。
解决办法就两条路,最简单的就是把摄像头主码流和子码流的视频编码改成H.264,换成H.264之后预览秒出图。如果你确实要保留H.265,那就得给播放器配一个支持HEVC的插件或者换用支持H.265的Web播放器,但这会引入额外的分发和转码开销,对免费方案来说有点不值。实际项目中,为了兼容性,我都直接统一成H.264。
4.4 坑三:UDP端口被防火墙拦掉
第三个坑发生在给外网设备做接入时。内网测试的几路摄像头接入正常,但一台在营业部网点、通过公网转发接入的摄像头,始终注册不上,信令日志里连REGISTER包都看不到。
抓包分析之后发现,设备发出SYN包到达服务器之后就没有回包了,这是典型的防火墙拦截特征。回头看云安全组,才发现只放行了TCP 5060,UDP 5060完全没有放开。GB28181信令默认走UDP,这种情况注册包到不了应用层,平台日志自然一片空白。
调整安全组规则,把UDP 5060、UDP 10000-20000全部加上白名单,改完配置后重新启动摄像头注册流程,设备秒上线。这个坑可以说是外网接入GB28181最容易踩的,没有之一。部署前我已经做了端口规划表,实际配置时还是漏掉了UDP方向,足以说明这类细节有多容易被忽视。
4.5 坑四:心跳周期和注册有效期不匹配
有一路摄像头接入后运行得很稳,但每隔几个小时就会被平台标记为离线,过一会儿又自动恢复在线,反复横跳。看设备端和平台端日志,发现设备报的是"注册过期,正在重新注册"。
问题出在参数匹配上。海康设备端如果设置注册有效期为3600秒,心跳周期为60秒,但smarteye平台端配置的会话超时时间是180秒,就会导致这样一种尴尬局面:平台以为设备已经超时了,把会话清掉,但设备还觉得自己注册着,直到下一个心跳周期到来才会触发重新注册。表现就是设备反复离线、在线。
解决办法不是非此即彼,而是统一两端的参数逻辑。最简单的做法是把平台端的SIP会话超时时间调成大于设备的注册有效期,比如设备注册有效期3600秒,平台超时时间改成7200秒,留足余量。这样设备确实掉线了,平台才能在预期的时间窗口内正确捕捉到。这个参数在smarteye的配置文件里叫expireTime,不同版本的名称略有差异,但逻辑都是一样的。
5. 语音对讲和实时预览:真接通了才明白的那些细节
5.1 GB28181语音对讲的完整过程
项目做到一半,甲方突然提了个新需求:要在监控中心直接和司机喊话。我一开始以为不就是双向对讲嘛,后来发现GB28181的语音对讲和普通IP电话不是一回事。
国标语音对讲的流程简单来说是这样的:平台先通过SIP控制信令向设备发起对讲请求,让设备把自己采集到的音频流推送到平台指定的媒体端口;平台同时也可以把中心的麦克风采集的音频流推送给设备,让设备通过扬声器播放出来。这个过程中音频封装成PS流,走RTP传输。
设备端的海康摄像头如果要支持对讲,本身需要带音频输入接口或者内置麦克风,而且平台的Web播放器也需要支持采集麦克风音频。smarteye后台的对讲按钮会同时触发两个方向的IMU消息控制。
5.2 对讲卡顿的排查思路
在调通对讲功能时,遇到的最大问题是平台到设备的音频推流一直失败,设备端能听到中心说话,但中心听不到设备端的一丁点声音。
排查链路是这样的:先看平台日志,信令正常,音频流也确实在往设备的媒体端口推送。再用抓包工具看RTP包,发现设备并没有回应任何音频RTP包。问题基本上锁定在音频编码协商环节。
海康的一些设备对音频编码格式有严格要求,只支持PCMA(即G.711 A律),不支持G.722。而我在平台端默认配置的是G.722,导致SDP协商结果设备不接受。把音频编码强制改成PCMA之后,对讲立即通了。
建议:接海康设备做对讲时,音频编码直接选PCMA,别犹豫。G.722虽然音质理论上更好,但兼容性差一截,耗时耗力未必值得。
5.3 实时预览延迟怎么压到一秒内
实时预览是整个过程里最直观的体验。用HTTP-FLV播放时,本地局域网内延迟能控制在1秒之内;但如果走公网,延迟往往会飙到3秒以上,体验很差。
要压延迟,无非是几个点:一是前端播放协议优先选HTTP-FLV,HLS切片本身就带来几秒的延迟,只适合录像回放,不适合实时指挥;二是确认设备编码参数里I帧间隔设置合理,不要设置成100帧,25帧就够,过长的I帧间隔会让播放器等待下一个关键帧才能出画面;三是媒体服务器的缓冲时间调短。smarteye的配置里有一个媒体拉流缓冲时长,默认可能在200到500毫秒,改成100毫秒之后,公网环境下预览延迟能压到1.5秒左右,局域网在0.5秒以内。
需要注意的是,缓冲时间不是越小越好,调得太短,网络抖动时画面会出现卡顿。100到150毫秒是一个比较均衡的区间。
6. 平台上线后别撒手:Prometheus盯住资源与离线告警
6.1 GB28181平台到底吃多少资源
free方案的好处是省了授权费,坏处是没有商业平台的监控团队替你盯着。平台上线后要是把服务器跑挂了,甲方不会知道这是因为免费,只会觉得是你能力不够。所以运维监控必须自己搭。
先搞清楚平台吃饱饭的量级。100路以内的摄像头接入,如果只做实时预览和按需转发,2核4G的服务器CPU总体占用在30%到50%之间浮动,其中媒体服务转封装是最大的开销。如果开启录像存储功能,磁盘吞吐和带宽占用会明显上升,100路全天录像,数据量百G级别是常态,提前规划磁盘扩容。
还有就是连接数。每一路在线预览都会保持一个到设备的长连接和一个到前端播放器的长连接,2G内存的服务器撑到200路左右时容易出现句柄耗尽或者内存不足,所以监控内存和句柄数是必须做的事。
6.2 node_exporter采集与Grafana展示
我在这台GB28181服务器上用Prometheus加node_exporter做了最基础的资源监控,整体流程是:node_exporter负责把服务器的CPU、内存、磁盘、网络指标暴露成一个HTTP接口,Prometheus定时来抓取数据,最后通过Grafana展示成仪表盘。
部署非常顺滑,两条命令就能起node_exporter:
docker run -d -p 9100:9100 --name node_exporter prom/node-exporter然后在Prometheus的配置文件里加一个抓取目标:
scrape_configs: - job_name: 'gb28181-server' static_configs: - targets: ['你的服务器IP:9100']Grafana里导入一个node_exporter的官方仪表盘模板,CPU、内存、磁盘、网络、打开文件数就全有图形了。这套方案对没有监控基础的人来说也很友好。
6.3 设备离线告警的另一种思路
Prometheus能解决的只是"服务器活着"的问题,但GB28181平台最核心的监控指标其实是"摄像头有没有掉线"。这一指标真正关系到业务可用性,视频设备因为断电、网络抖动而离线,在运输企业里几乎是每天都有的事。
我们的做法是写了一个简单的巡检脚本,定时调用smarteye的管理API,统计离线设备列表,如果离线数量超过阈值就通过企业微信机器人推送告警消息。脚本本身不复杂,核心就两步:先登录后台拿Token,再查设备状态列表。
这个思路比在Prometheus里自定义exporter要省事得多,而且贴近业务。如果以后接入路数增长,再考虑把离线事件写成自定义export指标,把数据接到Prometheus统一管理。设备离线和服务器资源监控两条腿走路,才算是真正把平台看住了。
说回到整体体验,用smarteye搭这套免费GB28181平台,最深的感受是"免费"两个字背后需要你自己去填平的坑并不少,但也正因为有这些坑,你才会真正搞懂SIP信令、国标编码、端口规划这些底层逻辑。我后来再接手任何品牌摄像头的国标接入任务,基本不用查文档,只需要看一眼设备参数页面的几项配置,就知道问题大概出在哪。
最后再分享一个实际项目里的小技巧:把所有摄像头和平台端的GB28181参数做成一张统一的表格,贴到项目的运维共享文档里。这个表格能省下后续无数次远程指导别人改配置的时间。摄像头接入这件事,只要参数能对上,其他都是小事。