首页 > 其他分享 >国网B接口调阅实时视频规范解读和代码示例分析

国网B接口调阅实时视频规范解读和代码示例分析

时间:2023-04-14 13:35:04浏览次数:49  
标签:国网 示例 des 调阅 video rtp device handle id

接口描述

国网B接口调阅实时视频,相关规范写的比较粗略:

调阅实时视频包括信令接口和媒体流接口,采用标准的SIP INVITE+SDP流程,媒体传输使用RTP/RTCP。

SDP 中 RTP Payload 的取值应遵守下面接口参数中的定义:

a) SDP 中的媒体信息,应仅有一个 m 行,用于描述视频格式。

b) 视频数据用 RTP 打包传输时,应考虑每个传输分组不大于 MTU,可采用的技术包括编码器层支持(如 ITU-T H.264 的 multi-slice 技术),或采用 RTP 层的分片机制(如 IETF RFC 3984 定义的 FU-A 技术)。

前端设备收到平台的INVITE请求后根据SDP描述进行媒体协商,协商通过后打开前端系统摄像机设备将获得的媒体流通过媒体通道发送到平台。

会话建立成功后,前端系统在某些特殊情况下可以主动结束当前呼叫。

平台应支持视频流的分发,以降低对前端系统的操作频繁性和节省网络带宽。

调阅实时视频的接口流程

国网B接口调阅实时视频规范解读和代码示例分析_国网B接口

主要功能流程如下:

a) F1:用户发送 INVITE 消息,携带 SDP 内容通过平台转发到前端设备。

b) F2:按照 SIP 要求,如前端系统在 0.5s 内未能处理该请求,则先发送 1xx 临时响应通过平台转发到用户。

c) F3:前端系统接受了调阅请求的操作,则发送携带 SDP 的 200 OK 响应通过平台转发到用户。

d) F4:用户发送 ACK 通过平台转发到前端设备。

e) 视频流从前端系统传输经平台转发到用户。

f) F5:用户结束会话,发送 BYE 消息到通过平台转发到前端系统。

g)F6:前端系统发送确认,将媒体通道拆线。

技术实现

由于国网B接口的invite实现和GB28181的差异不大,之前我们GB28181这块,已经有非常好的积累了。

国网B接口调阅实时视频规范解读和代码示例分析_国网B接口对接_02

Invite信令如下:

INVITE sip:[email protected]:5060 SIP/2.0
    Via: SIP/2.0/UDP 192.168.0.104:15060;branch=z9hG4bK864531896
    From: <sip:000000000000000001@0000000000>;tag=482531896
    To: <sip:[email protected]:5060>
    Call-ID: 804531783
    CSeq: 6 INVITE
    Content-Type: application/sdp
    Contact: <sip:[email protected]:15060>
    Max-Forwards: 70
    User-Agent: SIPB
    Request-URI: <sip:[email protected]:5060>
    Content-Length: 152
    
    v=0
    o=- 0 0 IN IP4 192.168.0.104
    s=Play
    c=IN IP4 192.168.0.104
    t=0 0
    m=video 30004 RTP/AVP 100
    a=recvonly
    a=rtpmap:100 H264/90000
    y=0130111000

收到Invite回调处理逻辑如下:

@Override
    public void ntsOnInvitePlay(String deviceId, SessionDescription session_des) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                // 先振铃响应下
                gb28181_agent_.respondPlayInvite(180, device_id_);

                MediaSessionDescription video_des = null;
                SDPRtpMapAttribute ps_rtpmap_attr = null;

                Vector<MediaSessionDescription> video_des_list = session_des_.getVideoPSDescriptions();
                if (video_des_list != null && !video_des_list.isEmpty()) {
                    for(MediaSessionDescription m : video_des_list) {
                        if (m != null && m.isValidAddressType() && m.isHasAddress() ) {
                            video_des = m;
                            ps_rtpmap_attr = video_des.getPSRtpMapAttribute();
                            break;
                        }
                    }
                }

                if (null == video_des) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    Log.i(TAG, "ntsOnInvitePlay get video description is null, response 488, device_id:" + device_id_);
                    return;
                }

                Log.i(TAG,"ntsOnInvitePlay, device_id:" +device_id_+", is_tcp:" + video_des.isRTPOverTCP()
                        + " rtp_port:" + video_des.getPort() + " ssrc:" + video_des.getSSRC()
                        + " address_type:" + video_des.getAddressType() + " address:" + video_des.getAddress());

                long rtp_sender_handle = libPublisher.CreateRTPSender(0);
                if ( rtp_sender_handle == 0 ) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    Log.i(TAG, "ntsOnInvitePlay CreateRTPSender failed, response 488, device_id:" + device_id_);
                    return;
                }


                gb28181_rtp_payload_type_  = 100;
                gb28181_rtp_encoding_name_ =  "PS";

                libPublisher.SetRTPSenderTransportProtocol(rtp_sender_handle, video_des.isRTPOverUDP()?0:1);
                libPublisher.SetRTPSenderIPAddressType(rtp_sender_handle, video_des.isIPv4()?0:1);
                libPublisher.SetRTPSenderLocalPort(rtp_sender_handle, 0);
                libPublisher.SetRTPSenderSSRC(rtp_sender_handle, video_des.getSSRC());
                libPublisher.SetRTPSenderSocketSendBuffer(rtp_sender_handle, 2*1024*1024); // 设置到2M
                libPublisher.SetRTPSenderClockRate(rtp_sender_handle, 90000 /*ps_rtpmap_attr.getClockRate()*/);
                libPublisher.SetRTPSenderDestination(rtp_sender_handle, video_des.getAddress(), video_des.getPort());

                if ( libPublisher.InitRTPSender(rtp_sender_handle) != 0 ) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    return;
                }

                int local_port = libPublisher.GetRTPSenderLocalPort(rtp_sender_handle);
                if (local_port == 0) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    return;
                }

                Log.i(TAG,"get local_port:" + local_port);

                String local_ip_addr = IPAddrUtils.getIpAddress(context_);

                MediaSessionDescription local_video_des = new MediaSessionDescription(video_des.getType());


                local_video_des.addFormat(String.valueOf(100));
                local_video_des.addRtpMapAttribute(ps_rtpmap_attr);

                local_video_des.setAddressType(video_des.getAddressType());
                local_video_des.setAddress(local_ip_addr);
                local_video_des.setPort(local_port);

                local_video_des.setTransportProtocol(video_des.getTransportProtocol());
                local_video_des.setSSRC(video_des.getSSRC());

                if (!gb28181_agent_.respondPlayInviteOK(device_id_,local_video_des) ) {
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    Log.e(TAG, "ntsOnInvitePlay call respondPlayInviteOK failed.");
                    return;
                }

                gb28181_rtp_sender_handle_ = rtp_sender_handle;
            }

            private String device_id_;
            private SessionDescription session_des_;

            public Runnable set(String device_id, SessionDescription session_des) {
                this.device_id_ = device_id;
                this.session_des_ = session_des;
                return this;
            }
        }.set(deviceId, session_des),0);
    }

ack信令如下:

ACK sip:[email protected]:5060 SIP/2.0
    Via: SIP/2.0/UDP 192.168.0.104:15060;branch=z9hG4bK991532349
    From: <sip:000000000000000001@0000000000>;tag=482531896
    To: <sip:[email protected]:5060>;tag=2d6ebb3d
    Call-ID: 804531783
    CSeq: 6 ACK
    Contact: <sip:[email protected]:15060>
    Max-Forwards: 70
    User-Agent: SIPB
    Request-URI: <sip:[email protected]:5060>
    Content-Length: 0

ack回调代码处理逻辑如下:

@Override
    public void ntsOnAckPlay(String deviceId) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG,"ntsOnACKPlay, device_id:" +device_id_);

                if (!isRTSPPublisherRunning && !isPushingRtmp && !isRecording) {
                    InitAndSetConfig();
                }

                libPublisher.SetGB28181RTPSender(publisherHandle, gb28181_rtp_sender_handle_, gb28181_rtp_payload_type_, gb28181_rtp_encoding_name_);
                int startRet = libPublisher.StartGB28181MediaStream(publisherHandle);
                if (startRet != 0) {

                    if (!isRTSPPublisherRunning && !isPushingRtmp  && !isRecording) {
                        if (publisherHandle != 0) {
                            libPublisher.SmartPublisherClose(publisherHandle);
                            publisherHandle = 0;
                        }
                    }

                    destoryRTPSender();

                    Log.e(TAG, "Failed to start GB28181 service..");
                    return;
                }

                startAudioRecorder();

                startLayerPostThread();
                isGB28181StreamRunning = true;
            }

            private String device_id_;

            public Runnable set(String device_id) {
                this.device_id_ = device_id;
                return this;
            }

        }.set(deviceId),0);
    }

总结

国网B接口调阅实时视频流程和GB28181流程基本一致,感兴趣的开发者,可以参考相关的规范实现,B接口相对GB28181来说,面更窄,资料也更少,如果产品化,有测试平台的话,还是不难实现的。


标签:国网,示例,des,调阅,video,rtp,device,handle,id
From: https://blog.51cto.com/daniusdk/6189914

相关文章

  • django admin 使用SimpleUI自定义按钮弹窗框示例
    actions=['button_exeScript',]defbutton_exeScript(self,request,queryset):passbutton_exeScript.layer={#弹出层中的输入框配置#这里指定对话框的标题'title':'弹出层输入框',#提示信息......
  • 6.case语句之场景示例:Rsync启动脚本
    1.编写一个rsync的启动停止脚本   实现:startstopstatusrestart   1.如何启动rsync        /usr/bin/rsync--daemon   2.如何停止rsync    pkillrsync #注意:千万不要使用rsync作为脚本的名字   3.参考系统中其他的服务的......
  • 【Azure Developer】使用 Microsoft Graph API 获取 AAD User 操作示例
    问题描述查看官方文档“ Getauser ”,产生了一个操作示例的想法,在中国区Azure环境中,演示如何获取AADUser信息。 问题解答使用MicrosoftGraphAPI,演示如何获取AADUser信息,因参考文档是针对GlobalAzure,所以文档种的URL为://GlobalAzureMicrosoftGraphAPIHostG......
  • React国际化方案及示例
    ​背景:随着公司走向国际,那么需要对产品进行国际化语言的预言处理。该预言方案主要是为了满足跨国企业和全球用户的需求而设计的。随着公司步入国际领域,该方案将有助于提高公司的国际化水平和竞争力。在国际化项目中,需要考虑不同语言、文化和地区的用户习惯和需求,确保产品的功能和......
  • REST API 设计规范:最佳实践和示例
    REST(RepresentationalStateTransfer)是一种基于HTTP协议的Web架构风格,它的出现大大简化了Web应用的开发和维护工作,成为现代Web开发的基础。RESTfulAPI设计规范是Web应用开发的重要一环,本文将从特点与技术现状、设计规范、应用场景和发展趋势四个方面进行介绍。正文开......
  • 65、K8S-部署管理-Helm基础知识、安装、入门示例
    Kubernetes学习目录1、基础知识1.1、需求在kubernetes平台上,我们在部署各种各样的应用服务的时候,可以基于手工或者自动的方式对各种资源对象实现伸缩操作,尤其是对于有状态的应用,我们可以结合持久性存储机制实现更大场景的伸缩动作。但是,无论我们怎么操作各种资源对象,问......
  • 一个Java web 应用系统的需求文档示例:
    #需求文档##引言本文档旨在描述一个在线商城网站的需求,并给出设计方案。该网站是一个B2C电商平台,旨在提供给用户方便快捷的购物体验。本文档面向的读者包括项目经理、开发人员、测试人员和其他与该系统相关的人员。##功能需求本次需求的功能需求包括:1.用户登录和注......
  • MyBatis中XXMapper示例记录
    XXMapper.xml的结构示例如下,包括<resultMap>、<id>、<result>、<select>、<update>、<foreach>、<if>标签的使用:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper......
  • SPRING ThreadPoolTaskExecutor示例
    0、前言当我们需要实现并发、异步等操作时,通常都会使用到ThreadPoolTaskExecutor。它是springcore包中的,而ThreadPoolExecutor是JDK中的JUC。ThreadPoolTaskExecutor是对ThreadPoolExecutor进行了封装处理。1、示例1.1、配置类importorg.springframework.context.annotation......
  • 善借ChatGPT提效,Cursor四问答设计业务简一概念模型示例
    作为一个程序员,对新事物不好奇,没有学习新技术的自觉意识,不知道如何更好地运用工具来提升自己的效率,又如何保持自己的竞争力呢上一次文字创作:梦,仰望星空;路,脚踏实地今天看看辅助编程~上一篇工具Cursor介绍:人人都是程序员,AI神器Cursor辅助,体验自然语言编程第一问:请使用java帮我......