news 2026/5/29 6:40:23

golang实现国标GB28181流媒体点播预览服务方案的框架流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
golang实现国标GB28181流媒体点播预览服务方案的框架流程

背景

28181协议全称为GB/T28181《安全防范视频监控联网系统信息传输、交换、控制技术要求》,是由公安部科技信息化局提出,由全国安全防范报警系统标准化技术委员会(SAC/TC100)归口,公安部一所等多家单位共同起草的一部国家标准(以下简称28181)。

28181协议在全国平安城市、交通、道路等监控中广泛采用,若想做统一的大监控平台,则支持28181协议接入是必不可少的。如今很多客户都是想在之前使用的28181平台的基础上进行拓展。

SkeyeVSS云平台目标支持市面上绝大多数监控设备接入,所以支持28181协议也是必然的要求;结合SkeyeVSS视频云平台的标准设备接入能解决市面上绝大多数设备以及平台的接入。

说明

SkeyeVSS视频云服务器是提供流转发的视频服务器,负责将GB28181设备/平台推送的PS流转成ES流,然后推送给SkeyeSMS流媒体服务器进行分发。
同时,GB28181流媒体服务器对外提供HTTP API接口,通过接口可以获知流媒体转发服务的运行状态信息,转发会话信息,服务器配置和版本信息等;

SkeyeVSS视频云服务器提供以下功能:
1. 接受和处理GB28181接入服务器的推流请求(如有推流权限验证则调用验证服务器接口);
2. 接受和处理GB28181设备的推流;
3. 实时流媒体处理,PS(TS)转ES;
4. 推送ES流到SkeyeSMS流媒体服务器;
5. 接受和处理GB28181接入服务器的断开推流请求;
6. 对外提供服务器获取状态、信息,控制等http API接口;

GB28181流媒体服务器对接SkeyeSMS云平台整体框架

流媒体点播详细流程

1 接入服务器发送Invite请求
接入服务器向流媒体服务器发送Invite请求,请求流媒体服务返回携带SDP 消息体,消息体中
描述了媒体服务器接收媒体流的IP、端口、媒体格式等内容;
Invite请求代码如下:

const options = { serialServer: serialServer, serialDevice: code, method: common.SIP_INVITE, contentType: common.CONTENT_NONE, content: sdp, host: hostip, port: hostport, rtpovertcp: (parseInt(rtpovertcp)===0?'UDP':'TCP') }; console.log('inviteMediaServer......sendRequest' + JSON.stringify(options)); uas.sendRequest(options);

2 流媒体服务接受Invite请求处理并ACK应答
流媒体服务接受Invite请求,并在回调函数中处理请求,js代码如下:

uas.on('invite', async ctx => { const request = ctx.request; const content = JSON.parse(request.content); const status = 200; const serial = sip.parseUri(request.uri).user; const host = config.server.serverHost; let ssid = serial.substring(16,20);// PrefixInteger(sessionid,4); let sirialid = serial.substring(3,8); const ssrc = "0"+sirialid+ssid; console.log("ssrc = "+ssrc); let sdp = ''; //如果已存在 let bHas = this.session_.has(serial); console.log(bHas); if (bHas) { console.log('this.session_ has exist serial: '+serial); sdp = ''; } else{ let port = config.server.udpPort;//流媒体接收TCP端口 let transport = 'RTP/AVP'; let a = "a=recvonly\r\n"; if(content.rtpovertcp === 'TCP' ) { port = config.server.tcpPort;//流媒体接收TCP端口 transport = 'TCP/RTP/AVP'; a = "a=recvonly\r\na=setup:passive\r\n"; } sdp = "v=0\r\n" + `o=${serial} 0 0 IN IP4 ${host}\r\n` + "s=Play\r\n" + `c=IN IP4 ${host}\r\n` + "t=0 0\r\n" + `m=video ${port} ${transport} 96 98 97\r\n` + "a=rtpmap:96 PS/90000\r\n" + "a=rtpmap:98 H264/90000\r\n" + "a=rtpmap:97 MPEG4/90000\r\n" + `${a}`+ //`a=connection:new\r\n` + `y=${ssrc}\r\n`; // A new channel is coming, delete the old rtpserver.deleteChannels(parseInt(ssrc)); // Create a new stram,and add to redis this.registerStream(parseInt(ssrc),uuidv4(),true); } let response = sip.makeResponse(request, status, common.messages[status]); uas.sendAckEx(response, sdp); });

如上代码所示,我们在SDP消息体中提供了两种流传输方式,分别是TCP和UDP,通过Invite请求所带的 “rtpovertcp ”参数来控制,TCP方式因为其不丢包的传输方式在GB28181设备推流到公网服务器的方案中得以广泛应用,然而,目前市面上的多数支持国标的设备都不支持tcp模式推流,udp仍然是主流的推流方式,不过,经测试udp推流方式在公网应用中效果比较差,需要进一步优化或者改进。

3 接入服务器接收ACK应答并Invite请求设备开始推流
回调函数中ack应答处理js代码如下:

uas.once('ack', async ctx => { const request = ctx.request; const callId = request.headers['call-id']; if (request.content.length > 0 ) { const serial = serialDevice;//sip.parseUri(request.headers.from.uri).user; let response ; if(!this.session_.has(callId)) { response = await this.inviteDevice(serial, code, callId, request.content); //Invite Device is complete if(response != undefined) { if(response.content) { const transform = require('sdp'); const res = transform.parse(response.content); console.log(res.media[0].protocol); if((res.media[0].protocol === 'RTP/AVP'&&parseInt(rtpovertcp)===0) || (res.media[0].protocol === 'TCP/RTP/AVP'&&parseInt(rtpovertcp)===1) ){ if (response.status === 200 ) { //send ack to stream server this.ackMediaServer(response.status,request,request.content); this.session_.set(callId, response); } } else{ response.status = 700; } } console.log('inviteMediaServer ack is coming.......response='+JSON.stringify(response)); } resolve(response); } else{ console.log('inviteMediaServer this.session_.has: '+callId); } } });

如上代码所示,在InviteDevice请求完成后,我们在返回Response处理过程中做过一次特殊处理,即:如果TCP拉流时发现设备拉流应答中返回其推流模式依然是’RTP/AVP’的UDP模式,我们认为其设备不支持TCP模式,从而向上层返回700,不支持的流媒体传输方式。

4 Invite设备正常返回200应答并传递给流媒体服务器
代码在第3点中有所体现。

5 流媒体服务接受拉流请求成功应答

uas.on('ack', async ctx => { const request = ctx.request; if (request.content.length === 0) { return; } const serial = sip.parseUri(request.headers.from.uri).user; this.session_.set(serial, request); const ssrc = serialTossrc(serial); // resole a new stram,and refresh to redis const info = JSON.parse(await redis.get(`stream:${parseInt(ssrc)}`)); this.registerStream(parseInt(ssrc),info.uuId,false); });

至此,整个拉流过程已经完成,这时,不出意外的话设备端将会通过我们指定的传输方式将流推送到我们指定的UDP/TCP服务器上,并转发到我们指定的SkeyeSMS流媒体服务器。

SkeyeVSS技术交流QQ群:102644504

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/31 20:25:12

白春礼院士:科研活动的基本单元正从人向人机系统转变

“AIfor Science(简称为AI4S)的竞争本质上是认知体系的竞争”,3月29日,中国科学院院士白春礼在第二届浦江AI学术年会开幕式上表示,不同科研体系如何理解科学,是以模型为核心,通过高维空间中的模…

作者头像 李华
网站建设 2026/3/31 20:22:36

Flink SQL CDC避坑指南:为什么你的Debezium源表总是漏数据?

Flink SQL CDC数据一致性实战:从Debezium陷阱到高可靠架构设计 在电商大促秒杀和金融交易风控这类对数据一致性要求严苛的场景中,Flink CDC已成为实时数仓建设的核心组件。但当你在凌晨三点收到报警通知,发现订单宽表丢失了关键字段时&#x…

作者头像 李华
网站建设 2026/3/31 20:22:35

Zotero Duplicates Merger:终极免费插件,5分钟解决文献重复难题

Zotero Duplicates Merger:终极免费插件,5分钟解决文献重复难题 【免费下载链接】ZoteroDuplicatesMerger A zotero plugin to automatically merge duplicate items 项目地址: https://gitcode.com/gh_mirrors/zo/ZoteroDuplicatesMerger 还在为…

作者头像 李华
网站建设 2026/3/31 20:22:35

STM32G030C8T6 + DRV8833 驱动42步进电机:从零到64细分的保姆级代码解析

STM32G030C8T6 DRV8833 驱动42步进电机:从零到64细分的保姆级代码解析 当我们需要精确控制步进电机的位置和速度时,细分驱动技术就显得尤为重要。本文将深入探讨如何使用STM32G030C8T6微控制器和DRV8833电机驱动器实现42步进电机的高精度64细分控制。不…

作者头像 李华
网站建设 2026/3/31 20:19:33

D2RML:多账号游戏管理的自动化技术解决方案

D2RML:多账号游戏管理的自动化技术解决方案 【免费下载链接】D2RML Diablo 2 Resurrected Multilauncher 项目地址: https://gitcode.com/gh_mirrors/d2/D2RML 一、重新定义游戏多开价值:从重复操作到智能管理 在游戏多账号运营场景中&#xff0…

作者头像 李华