ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

GB28181协议实战:从异构设备互联到点播回放全解析

2026/9/25 12:00:21 拓冰建站 浏览量
GB28181协议实战:从异构设备互联到点播回放全解析 1. 从一次对接失败说起GB28181到底在解决什么问题我第一次接触GB28181是在一个园区安防改造项目上。甲方手里有海康、大华、宇视三个品牌的摄像机还有一套老旧的监控客户端要求把所有视频统一汇到一个平台上还要能上墙、能录像、能语音喊话。当时我第一反应是各品牌SDK挨个对接结果光是海康一家的SDK就把我折腾了两天换个大华又要重写一遍。后来一位做安防的老哥点了我一句你为什么不走国标这才有了后面这段GB28181的学习和踩坑经历。GB28181的全称是《公共安全视频监控联网系统信息传输、交换、控制技术要求》它本质上是一套信令加媒体的联网规范。信令部分用SIP媒体部分用RTP/RTCP设备控制用MANSCDP回放控制用MANSRTSP。你可以把它理解成安防界的普通话不管你是海康、大华还是宇视只要都说普通话平台就能听懂。它解决的核心问题就是异构设备互联互通让不同厂商、不同型号的摄像机、NVR、平台之间能互相注册、点播、控制、回放。这套东西适合谁学如果你是做安防平台开发的、做流媒体服务的、做物联网视频接入的或者你手里有一堆摄像机想自己搭个平台那GB28181是绕不过去的。哪怕你只是用Python写个小服务把家里的摄像头接进来理解这套协议也能让你少走很多弯路。下面我按自己实际学习和落地的顺序把GB28181拆开讲一遍尽量说人话把那些文档里不写、但实际会卡住你的地方都点出来。2. 协议整体架构与核心角色拆解2.1 SIP、RTP、MANSCDP、MANSRTSP各自管什么刚看GB28181文档的时候最容易懵的就是一堆缩写。我当时的做法是先把它们按职责分堆分完就清楚多了。SIP是信令通道负责“说话”。设备注册、心跳、目录查询、点播请求、云台控制指令这些都是SIP消息在传。你可以把SIP理解成打电话时的拨号和通话控制它不传视频画面只传“我要干什么”。RTP是媒体通道负责“传画面”。真正的一帧帧视频、一段段音频都是打包成RTP包发出去的。RTCP是它的搭档负责统计丢包、抖动这些质量信息。这里有个新手常踩的坑SIP和RTP走的是不同的端口SIP通常是5060RTP是动态协商的别以为通了SIP就能看到画面。MANSCDP是设备控制协议基于XML跑在SIP消息体里。比如你查设备目录、查设备状态、发起录像回放用的就是MANSCDP。它规定了XML的格式和字段设备按这个格式回你。MANSRTSP是回放控制协议也是基于SIP消息体专门管录像回放的暂停、快进、拖拽。实时点播用不到它但你要做录像回放功能就必须把它搞明白。协议职责承载方式典型场景SIP信令控制UDP/TCP 5060注册、心跳、点播、云台RTP/RTCP媒体传输UDP 动态端口视频流、音频流MANSCDP设备控制SIP消息体XML目录查询、状态查询、回放MANSRTSP回放控制SIP消息体暂停、快进、拖拽2.2 平台、设备、客户端三种角色的关系GB28181里角色分得很清楚。平台是上级负责接收注册、下发指令设备是下级摄像机、NVR、编码器都算客户端是操作端可以理解为看画面、发指令的那一端。实际部署里平台和设备是必须的客户端可以是平台的一部分也可以是独立的一套。我见过很多人把“平台”和“客户端”混在一起说结果对接的时候双方理解不一致一个以为你要注册一个以为你要点播白白浪费半天。所以对接前一定要先确认谁是平台谁是设备谁主动发起注册。GB28181默认是设备主动向平台注册平台被动接收。如果双方都等着对方注册那就永远通不了。2.3 一次完整点播的信令流程我把一次实时点播的流程简化成下面几步实际抓包也是这个顺序设备向平台注册平台回200 OK。平台向设备发INVITE消息体里带SDP告诉设备我要收流的IP和端口。设备回200 OK消息体里带自己的SDP告诉平台我往哪个IP和端口发流。平台回ACK确认。设备开始往协商好的端口发RTP流。平台发BYE结束会话设备停止发流。这里面第2步和第3步的SDP协商是重点。SDP里会写媒体类型、编码格式、端口、SSRC。SSRC是流的唯一标识平台靠它区分不同设备的流。我遇到过设备回的SSRC和平台预期不一致导致平台收流后不知道是谁的画面出不来。所以对接时一定要把SSRC对齐。3. 核心细节解析与实操要点3.1 注册与心跳别小看这两步注册是设备上线第一步。设备发REGISTER平台回401要求鉴权设备带鉴权信息再发REGISTER平台回200 OK。鉴权用的是MD5用户名、密码、realm、nonce这些字段都要对。我踩过的坑是密码里带特殊字符设备端和平台端对特殊字符的处理不一致导致鉴权一直失败。后来把密码改成纯字母数字就通了。所以对接初期密码尽量简单通了再改复杂。心跳是设备定期告诉平台“我还活着”。默认是60秒一次用MESSAGE消息发Keepalive。平台如果连续几个心跳没收到就认为设备离线。这里有个细节心跳超时时间要设得比心跳间隔大比如心跳60秒超时设180秒否则网络稍微抖一下设备就掉线了。我见过有人把超时设成60秒结果设备频繁上下线排查半天才发现是超时太短。3.2 目录查询设备到底有哪些通道目录查询用MANSCDP平台发Catalog查询设备回Catalog响应里面列出所有通道。每个通道有设备ID、名称、状态、类型。这里要注意一个NVR可能带多个通道每个通道有自己的ID点播时要按通道ID点不能按NVR的ID点。我一开始没注意点播NVR的ID结果设备回错误后来改成通道ID才通。目录查询还分全量和增量。全量是查所有增量是查变化的。实际对接时平台一般先全量查一次之后定期增量查。增量查询的SN字段要递增设备靠SN区分请求。如果SN不递增设备可能不响应。3.3 实时点播SDP协商里的门道实时点播是核心功能也是最容易出问题的地方。INVITE消息里的SDP平台要写清楚自己收流的IP、端口、媒体类型。设备回的SDP里要写清楚它发流的IP、端口、编码格式、SSRC。我总结几个关键点收流IP平台如果有多网卡一定要写对IP否则设备往错误的IP发流平台收不到。端口平台要提前开好端口别等设备发流了才开那样流就丢了。编码格式平台要声明自己支持哪些编码设备选一个它支持的。如果平台只声明H265设备只支持H264那就协商失败。SSRC平台可以指定SSRC也可以让设备自己生成。如果平台指定设备要按平台的来如果设备自己生成平台要能接受任意SSRC。提示对接初期建议平台把收流端口范围开大一点比如从30000到40000避免端口冲突。同时把防火墙对应端口放行否则SIP通了RTP不通画面就是黑的。3.4 语音对讲容易被忽略的双向流语音对讲是很多项目的刚需但GB28181文档里写得比较简略。它本质上是平台向设备发一个INVITESDP里声明是音频设备回SDP然后平台往设备发RTP音频流设备播放。同时设备也可以往平台发音频流实现双向对讲。我踩过的坑是音频编码格式不匹配。平台用G711A设备只支持G711U结果对讲没声音。后来统一成G711A才通。另外对讲对延迟敏感RTP包要小发送间隔要短否则听起来一顿一顿的。3.5 录像回放MANSRTSP控制流录像回放比实时点播多了一步平台先发INVITESDP里声明是回放设备回SDP然后平台发MANSRTSP指令控制播放。MANSRTSP指令包括PLAY、PAUSE、TEARDOWN还有快进、慢放、拖拽。这里的关键是时间戳。回放请求里要带开始时间和结束时间设备按这个时间段发流。如果时间格式不对设备可能不响应。GB28181用的是ISO8601格式比如2024-01-01T00:00:00。我见过有人用Unix时间戳设备直接忽略。4. 实操过程与核心环节实现4.1 环境准备与工具选型我搭测试环境用的是一台Linux服务器跑平台一台海康摄像机做设备中间用交换机连。工具方面抓包用WiresharkSIP消息看得很清楚测试SIP用SIPp可以模拟设备注册和点播流媒体服务用ZLMediaKit它自带GB28181支持省了很多事。如果你不想用现成的想自己写Python可以用pjsua或者aiosip做SIP用aiortc或者直接socket收RTP。但说实话自己写SIP栈工作量不小建议先用现成库跑通再考虑自己实现。4.2 平台侧收流端口规划平台侧要规划好端口。SIP用5060RTP用30000到40000。每个点播会话分配一个RTP端口会话结束后回收。我一般用端口池管理分配时从池里取释放时还回去。这样避免端口冲突也方便防火墙配置。# 简单的端口池实现 import threading class PortPool: def __init__(self, start, end): self.ports list(range(start, end 1)) self.lock threading.Lock() def acquire(self): with self.lock: if self.ports: return self.ports.pop(0) return None def release(self, port): with self.lock: if port not in self.ports: self.ports.append(port) self.ports.sort()这个端口池很简单但够用。实际生产环境要考虑端口回收超时避免会话异常结束后端口不释放。4.3 设备侧注册配置海康摄像机的GB28181配置在“网络-高级配置-平台接入”里。要填平台IP、端口、设备ID、密码。设备ID是20位前8位是行政区划中间8位是行业编码后4位是设备序号。这个ID要和平台侧配置一致否则注册失败。配置完保存设备会主动向平台注册。如果平台没收到注册先检查网络通不通再检查端口对不对最后检查ID和密码。我一般用Wireshark抓包看设备有没有发REGISTER平台有没有回401设备有没有再发带鉴权的REGISTER。这三步一看就知道卡在哪。4.4 点播流程的代码实现下面是一个简化的点播流程用Python模拟平台向设备发INVITE。实际代码要复杂得多但核心逻辑就这些。import socket def send_invite(device_ip, device_port, platform_ip, rtp_port, ssrc): invite fINVITE sip:{device_id}{device_ip}:{device_port} SIP/2.0 Via: SIP/2.0/UDP {platform_ip}:5060 From: sip:platform{platform_ip};tag12345 To: sip:{device_id}{device_ip} Call-ID: 123456789 CSeq: 1 INVITE Content-Type: application/sdp v0 o{platform_ip} 0 0 IN IP4 {platform_ip} sPlay cIN IP4 {platform_ip} t0 0 mvideo {rtp_port} RTP/AVP 96 artpmap:96 PS/90000 assrc:{ssrc} sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.sendto(invite.encode(), (device_ip, device_port))这段代码只是示意实际要处理鉴权、重传、超时。但你可以看到INVITE里带了SDP声明了收流IP、端口、编码、SSRC。设备收到后回200 OK带它自己的SDP然后平台回ACK设备开始发流。4.5 收流与解码收流用socket监听RTP端口收到包后解析RTP头取出payload按编码格式解码。如果是PS流要先解PS再解H264/H265。ZLMediaKit这些流媒体服务已经帮你做好了你只需要把流推给它它负责解码和分发。我一般用FFmpeg收流命令很简单ffmpeg -i rtp://192.168.1.100:30000 -c copy output.mp4但要注意FFmpeg收RTP需要SDP文件或者你直接指定编码格式。如果流是PS封装的FFmpeg也能处理但有时候需要加-f mpegts参数。5. 常见问题与排查技巧实录5.1 注册失败从抓包开始注册失败是最常见的问题。我的排查顺序是先ping设备确认网络通再telnet设备5060端口确认SIP端口开然后Wireshark抓包看REGISTER有没有发出来平台有没有回401设备有没有再发REGISTER。如果设备发了REGISTER但平台没回可能是平台没监听5060或者防火墙拦了。如果平台回了401但设备没再发可能是设备鉴权配置不对。注意有些设备默认用TCP发SIP平台如果只监听UDP就收不到。对接前确认双方传输协议一致。5.2 点播无画面SIP通了RTP不通SIP通了但画面黑说明信令没问题媒体有问题。排查步骤先看平台有没有收到RTP包用tcpdump抓包如果有包但画面黑可能是编码不匹配检查SDP里的编码格式如果没包可能是设备往错误的IP或端口发流检查INVITE里的收流IP和端口。我遇到过一种情况平台有多网卡INVITE里写的收流IP是A网卡但设备只能通B网卡结果设备往A网卡发流平台收不到。后来把收流IP改成B网卡就通了。所以多网卡环境一定要确认路由。5.3 语音对讲没声音编码和方向都要查语音对讲没声音先查编码格式平台和设备要一致。再查方向平台要往设备发RTP设备也要往平台发RTP如果只配了一个方向就是单向对讲。最后查音量有些设备默认音量是0要手动调。5.4 回放卡顿时间戳和关键帧回放卡顿先查时间戳设备发流的时间戳要连续如果跳变播放器会卡。再查关键帧如果关键帧间隔太长拖拽后会等很久才出画面。我一般把关键帧间隔设成1秒拖拽响应快。5.5 常见问题速查表问题可能原因排查方法注册失败网络不通、端口不对、鉴权失败ping、telnet、抓包点播无画面收流IP错、端口未开、编码不匹配tcpdump、检查SDP语音没声音编码不一致、方向不对、音量为0检查SDP、调音量回放卡顿时间戳跳变、关键帧间隔长检查时间戳、调关键帧设备频繁离线心跳超时太短调大超时时间5.6 几个独家避坑技巧第一对接初期用最简单的配置。密码用纯数字编码用H264传输用UDP端口用默认。通了再改复杂这样出问题容易定位。第二抓包是王道。SIP和RTP的问题抓包一看就清楚。Wireshark有SIP解析功能能直接看消息内容。RTP包也能看序列号和时间戳丢包和乱序一目了然。第三SSRC要对齐。平台指定SSRC时设备要按平台的来设备自己生成时平台要能接受。我见过平台只接受指定SSRC设备自己生成结果平台收流后丢弃画面出不来。第四端口范围要开够。一个平台可能同时点播几十路端口不够就会失败。我一般开10000个端口从30000到40000基本够用。第五时间同步。设备和平台的时间要同步否则回放时间戳对不上。我一般用NTP同步误差控制在1秒内。6. 从能跑到好用性能与扩展的几点经验跑通之后下一步就是让它稳定、好用。我总结几个实际项目里验证过的点。并发点播。一个平台同时点播多路时SIP信令和RTP收流都要能扛住。SIP可以用多线程或异步处理RTP收流每个会话一个线程或协程。我试过用Python的asyncio收流单机跑50路没问题再往上就要考虑用C或者Go重写收流部分。流媒体分发。平台收到流后要分发给多个客户端看。这时候可以用ZLMediaKit或者SRS做流媒体服务平台把流推给它们它们负责转协议、分发。这样平台只负责信令和收流分发交给专业服务架构更清晰。录像存储。录像可以存成MP4或者TS文件按时间和设备ID命名。我一般用TS因为TS对断电流友好MP4断电流文件可能损坏。存储路径按日期分目录方便查找。级联。GB28181支持平台级联下级平台向上级平台注册上级平台可以点播下级平台的设备。级联的信令和点播类似但多了一层转发。我做过三级级联延迟会增加但功能没问题。级联时要注意ID规划避免冲突。安全。GB28181默认用MD5鉴权安全性一般。实际项目里我一般把SIP和RTP限制在内网或者用专线避免暴露在公网。如果必须公网加个防火墙规则只允许特定IP访问。7. 我个人的学习路径和建议回头看我学GB28181的过程大概是先看文档把SIP、RTP、MANSCDP、MANSRTSP分清楚然后搭环境用现成平台和设备跑通注册和点播接着抓包把每一步的信令和媒体都看一遍最后自己写代码实现一个简单的平台。如果你刚开始学我建议你按这个顺序来先跑通再抓包再改代码。别一上来就自己写SIP栈那样容易卡在细节里。用ZLMediaKit或者SIPp这些现成工具先把流程跑通有了直观感受再深入细节。另外多设备对接是常态。我手里常备海康、大华、宇视各一台每次改代码都拿它们测一遍。不同厂商对协议的理解有差异比如有的设备回SDP时SSRC是0有的设备心跳间隔不是60秒。这些差异文档里不写只能靠实测。最后分享一个小技巧如果你在对接时卡住了先别急着改代码把SIP和RTP抓包发给对方让对方也抓一份两边一对问题基本就定位了。我靠这招解决过很多次扯皮比来回猜效率高多了。