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

news2024/11/27 12:44:26

接口描述

国网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描述进行媒体协商,协商通过后打开前端系统摄像机设备将获得的媒体流通过媒体通道发送到平台。

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

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

调阅实时视频的接口流程

主要功能流程如下:

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接口后,完成平台端的register和PushResourse交互,有些平台注册后,会接着响应Push_Resource request,其他不表,这里主要谈下invte和Ack相关回调处理:

Invite信令如下:

    INVITE sip:1301110005010100001@192.168.0.102:5060 SIP/2.0
    Via: SIP/2.0/UDP 192.168.0.104:15060;branch=z9hG4bK864531896
    From: <sip:000000000000000001@0000000000>;tag=482531896
    To: <sip:1301110005010100001@192.168.0.102:5060>
    Call-ID: 804531783
    CSeq: 6 INVITE
    Content-Type: application/sdp
    Contact: <sip:000000000000000001@192.168.0.104:15060>
    Max-Forwards: 70
    User-Agent: SIPB
    Request-URI: <sip:1301110005010100001@192.168.0.102: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:1301110005010100001@192.168.0.102:5060 SIP/2.0
    Via: SIP/2.0/UDP 192.168.0.104:15060;branch=z9hG4bK991532349
    From: <sip:000000000000000001@0000000000>;tag=482531896
    To: <sip:1301110005010100001@192.168.0.102:5060>;tag=2d6ebb3d
    Call-ID: 804531783
    CSeq: 6 ACK
    Contact: <sip:000000000000000001@192.168.0.104:15060>
    Max-Forwards: 70
    User-Agent: SIPB
    Request-URI: <sip:1301110005010100001@192.168.0.102: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来说,面更窄,资料也更少,如果产品化,有测试平台的话,还是不难实现的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/423606.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用低代码平台可视化设计表单

表单在前端可谓是非常常见的场景&#xff0c;而且通常需要花费开发非常多的时间来处理各种复杂的逻辑。特别是在企业中后台的业务中&#xff0c;存在着大量的表单&#xff0c;比如客户的订单&#xff0c;投诉的问题单&#xff0c;服务跟进过程每个流程的流转。凡是存在用户输入…

西安五日游规划

文章目录前言一、行前准备二、必带清单三、打卡美食四、景点地理坐标五、旅游时间轴六、景点小巴士第一天第二天第三天第四天第五天其他七、住宿八、小贴士总结前言 西安五日游。计划从北京出发&#xff0c;游玩五天&#xff0c;第五天回京。 一、行前准备 计划行程 票务预订 …

雅思资料汇总

关于雅思 流程&#xff1a; 雅思考试将全面启用现场照相和生物识别技术, 包括指纹采集和验证,考生将无需提供个人照片。我们建议考生在考试当天提前到场以完成个人物品放置&#xff0c;身份证件验证&#xff0c;检录入场等一系列重要考前准备工作。大厅在当天会贴出考生的考号…

【网络原理】应用层协议 与 传输层协议

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;Java EE初阶&#x1f447; 目 录&#x1f3c9;一. 应用层协议⚾️二. 传输层协议&#x1f452;1. UDP 协议&#x1f302;2. 校验和&#x1f453;3. TCP 协议&#x1f3c9;一. 应用层协议 我们自己写的应用程…

2023年MathorCup数模B题赛题

B 题 城市轨道交通列车时刻表优化问题 列车时刻表优化问题是轨道交通领域行车组织方式的经典问题之一。 列车时刻表规定了列车在每个车站的到达和出发(或通过)时刻&#xff0c;其在实 际运用过程中&#xff0c;通常用列车运行图来表示。图 1 为某一运行图的示例&#xff0c;图 …

代码随想录算法训练营第五十九天 | 503. 下一个更大元素 II、42. 接雨水

503. 下一个更大元素 II 方法一&#xff1a;将两个nums数组放在一起&#xff0c;使用单调栈求下一个更大元素&#xff0c;最后再把结果集即result数组resize到原数组大小就可以了。 方法二&#xff1a;在遍历的过程中模拟走了两遍nums class Solution { public:vector<in…

5G-OAI关于物理层中PDCCH源码解析

5G物理层是指5G网络的传输技术&#xff0c;包括无线帧、子帧、时隙、符号等方面的定义和规范。具体来说&#xff0c;5G物理层定义了无线帧的长度、帧结构、子帧结构、传输速率、带宽、时间同步等方面的参数&#xff0c;以及物理层信道的编码、调制和解调方式等方面的规范。5G物…

k8s 滚动部署学习总结

k8s 滚动部署学习总结 滚动发布 滚动发布配置总结 定义&#xff1a; 滚动升级&#xff08;Rolling update&#xff09; 就是指每次更新部分Pod&#xff0c;而不是在同一时刻将该Service下面的所有Pod shutdown&#xff0c;然后去更新逐个更新可以避免将业务中断 使用Deploy…

GEE初学者笔记之快速上手篇

1.基础概念 (1)谷歌云平台 整个GEE是基于Google Cloud云平台的一整套API开发环境。因此整个数据的处理全部都是在Google Cloud平台上实现的&#xff0c;无需本地机器参与运算。一般开发流程是在线/离线编辑代码&#xff0c;然后提交服务器端运行&#xff0c;完成之后会输出给我…

【Jenkins 2.x 实践指南】1.4 软件工程生产力--章节小结

目录 一、生产力三要素 1. 生产力 2. IT 中的生产力 二、Devops 和 Jenkins 1. DevOps 模式定义(AWS官方定义) 2. DevOps 实践经验 2.1 持续集成 2.2 持续交付 2.3 微服务 2.4 基础设施即代码 2.5 监控和日志记录 2.6 沟通与合作 一、生产力三要素 1. 生产力 劳动…

GPT系列简介与gpt训练(nanoGPT)

generateivelt pre-trained transformer ,GPT使用transformer做特征提取行&#xff0c;单项语言模型作为训练任务 gpt 1.0 通过自左向右生成式的构建预训练任务&#xff0c;然后得到一个通用的预训练模型&#xff0c;这个模型和BERT一样都可用来做下游任务的微调。GPT-1当时在…

Firefly-rk3288 开发板Linux系统编译

前言 手上的一块Firefly-RK3288开发板&#xff0c;看了下Firefly提供的SDK&#xff0c;压缩包就有15个多G&#xff0c;直接吓退。还好最近看到了韦东山老师提供的教学资料。记下学习步骤及遇到的问题解决办法。 1、开发环境 资料提供的有百问网制作的 ubuntu18.04 虚拟机镜像…

卷积计算转换为矩阵乘计算的几种场景和方法

本文默认卷积的输入输出数据格式为NHWC。 1x1卷积 输入shape为[N, H, W, C] , filter为[Hf, Wf, Ci, Co] FH, FW都为1&#xff0c;直接把输入shape reshape为[N, H * W, C], filter reshape为[[Hf * Wf * Ci, Co],然后进行矩阵乘得到[N, H * W, Co]&#xff0c;再reshape为卷…

ChatGPT 本地部署及搭建

这篇简要说下清华开源项目 ChatGLM 本地部署的详细教程。清华开源项目 ChatGLM-6B 已发布开源版本&#xff0c;这一项目可以直接部署在本地计算机上做测试&#xff0c;无需联网即可体验与 AI 聊天的乐趣。 项目地址&#xff1a;GitHub - THUDM/ChatGLM-6B: ChatGLM-6B&#xf…

一次小破站JS代码审计出XSS漏洞思路学习

今天看了小破站一个大佬的分析&#xff0c;感觉思路很有意思&#xff0c;感兴趣的xdm可以到大佬视频下提供的链接进行测试&#xff08;传送门&#xff09;这类社交平台的XSS漏洞利用起来其实危害是特别大的&#xff0c;利用XSS能在社交平台上呈现蠕虫式的扩散&#xff0c;大部分…

redis内存回收——过期、淘汰

DB结构删除策略惰性删除周期删除SLOWFAST淘汰策略redis内存设置过大时会增加同步等操作的复杂度 DB结构 /* Redis database representation. There are multiple databases identified* by integers from 0 (the default database) up to the max configured* database. The …

es 搜索中同时包含 “query“ 和 “filter“ 子句

Elasticsearch支持很多查询方式&#xff0c;其中一种就是DSL&#xff0c;它是把请求写在JSON里面&#xff0c;然后进行相关的查询。 一、Query DSL 与 Filter DSL DSL查询语言中存在两种&#xff1a;查询DSL&#xff08;query DSL&#xff09;和过滤DSL&#xff08;filter DSL…

数据库管理-第六十八期 Oracle 23c的其他(20230417)

数据库管理 2023-04-17第六十八期 Oracle 23c的其他1 DGPDB2 无锁并发总结第六十八期 Oracle 23c的其他 由于Oracle 23c的文档相对较少&#xff0c;一是当前文档主要面向开发人员&#xff0c;二是感觉实际内容还在不断增加&#xff0c;主要还有一点就是各种新特性的在官方文档…

几分种学会React Router v6使用

React路由可以实现页面间的切换。 传送门&#xff1a;英文文档 中文教程&#xff1a; https://www.reactrouter.cn/docs/getting-started/tutorial 1.基础使用 react 需求&#xff1a;实现一个普通的底部导航切换 1.安装react-router npm i react-router-dom62.配置根组件…

C#调试与测试 | DebuggerDisplay使用技巧

DebuggerDisplay使用技巧 文章目录DebuggerDisplay使用技巧前言DebuggerDisplay介绍示例代码前言 当你在开发一个大型的应用程序时&#xff0c;调试是一个不可避免的任务。调试器是你的好朋友&#xff0c;但是有时候它并不能直接给你所需的信息。这时&#xff0c;就需要使用 C…