当前位置:   article > 正文

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

node.js sip sdp

EasyGBS国标GB28181视频平台方案是一套完善、稳定、高效的国标设备接入与标准化输出平台,EasyGBS国标视频平台能够接入各种海康、大华、宇视的标准GB28181摄像机IPCamera、硬盘录像机NVR、视频平台,提供用户权限管理及Web可视化页面管理,提供设备状态管理,可实时查看设备是否掉线等信息,实时流媒体直播,设备状态监测、云台控制、录像检索、回放;提供RTSP、RTMP、HTTP-FLV、HLS等多种协议流输出;对外提供服务器获取状态、信息,控制等HTTP API接口;支持向上级联国标平台;支持云端录像存储、查询;支持企业级私有化部署,跨平台支持Linux & Windows。通过EasyGBS(www.easygbs.com)可以获取到关于国标GB28181非常全面的解决方案。

背景

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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);
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

如上代码所示,我们在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);
                    }
                }
            });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

如上代码所示,在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);     
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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

##获取更多信息

邮件:support@easydarwin.org

WEB:www.EasyDarwin.org

流媒体技术交流QQ群:538316953

Copyright © EasyDarwin.org 2012-2018

logo

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/943978
推荐阅读
相关标签
  

闽ICP备14008679号