Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 747|回复: 0

node.js实现国标GB28181流媒体点播(即实时预览)服务解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-9-5 17:20:55 | 显示全部楼层 |阅读模式

    背景

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

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

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

    说明

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

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

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

    框架

    流媒体点播详细流程

    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服务器上,并转发到我们指定的EasyDSS流媒体服务器。

    获取更多信息

    邮件:support@easydarwin.org

    WEB:www.EasyDarwin.org

    流媒体技术交流QQ群:538316953

    Copyright © EasyDarwin.org 2012-2018

    logo

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-22 00:12 , Processed in 1.085794 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表