GB/T28181-2016传输要求和Android平台设备接入技术实现

2022-09-10 20:12:38 浏览数 (1)

相关协议规范

GB/T28181-2016公共安全视频监控联网系统 信息传输、交换、控制技术要求相关的传输要求如下:

5.1 网络传输协议要求

联网系统网络层应支持IP协议,传输层应支持 TCP和 UDP协议。

5.2 媒体传输协议要求

视音频流在基于IP的网络上传输时应支持 RTP/RTCP协议;视音频流的数据封装格式应符合4.3.6 中的要求。

视音频流在基于IP的网络上传输时宜扩展支持 TCP协议,协议应符合附录 L的规定。

5.3 信息传输延迟时间

当信息(包括视音频信息、控制信息及报警信息等)经由IP网络传输时,端到端的信息延迟时间(包 括发送端信息采集、编码、网络传输、信息接收端解码、显示等过程所经历的时间)应满足下列要求: a) 前端设备与信号直接接入的监控中心相应设备间端到端的信息延迟时间应不大于2s; b) 前端设备与用户终端设备间端到端的信息延迟时间应不大于4s。

5.4 网络传输带宽

联网系统网络带宽设计应能满足前端设备接入监控中心、监控中心互联、用户终端接入监控中心的 带宽要求,并留有余量。前端设备接入监控中心单路的网络传输带宽应不低于512kbps,重要场所的 11GB/T28181—2016前端设备接入监控中心单路的网络传输带宽应不低于2Mbps,各级监控中心间网络单路的网络传输带宽应不低于2.5Mbps。

5.5 网络传输质量

联网系统IP网络的传输质量(如传输时延、包丢失率、包误差率、虚假包率等)应符合如下要求: a) 网络时延上限值为400ms; b) 时延抖动上限值为50ms; c) 丢包率上限值为1×10-3; d) 包误差率上限值为1×10-4。

5.6 视频帧率

本地录像时可支持的视频帧率应不低于25帧/s;图像格式为 CIF时,网络传输的视频帧率应不低于25帧/s;图像格式为4CIF以上时,网络传输的视频帧率应不低于15帧/s,重要图像信息宜25帧/s。

Android平台GB28181设备接入实现

Android平台GB28181接入SDK,实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如智能监控、智慧零售、智慧教育、远程办公、生产运输、智慧交通、车载或执法记录仪等场景。Android终端除支持常规的音视频数据接入外,还可以支持移动设备位置(MobilePosition)订阅和通知、语音广播和语音对讲。

除了符合技术规范里面的传输要求外,延迟方面,目前测试下来,Android平台GB28181设备接入延迟在毫秒级。

功能设计如下:

  • [视频格式]H.264/H.265(Android H.265硬编码);
  • [音频格式]G.711 A律、AAC;
  • [音量调节]Android平台采集端支持实时音量调节;
  • [H.264硬编码]支持H.264特定机型硬编码;
  • [H.265硬编码]支持H.265特定机型硬编码;
  • [软硬编码参数配置]支持gop间隔、帧率、bit-rate设置;
  • [软编码参数配置]支持软编码profile、软编码速度、可变码率设置;
  • 支持横屏、竖屏推流;
  • Android平台支持后台service推送屏幕(推送屏幕需要5.0 版本);
  • 支持纯视频、音视频PS打包传输;
  • 支持RTP OVER UDP和RTP OVER TCP被动模式;
  • 支持信令通道网络传输协议TCP/UDP设置;
  • 支持注册、注销,支持注册刷新及注册有效期设置;
  • 支持设备目录查询应答;
  • 支持心跳机制,支持心跳间隔、心跳检测次数设置;
  • 支持移动设备位置(MobilePosition)订阅和通知;
  • 支持国标GB/T28181—2016平台接入;
  • 支持语音广播及语音对讲;
  • [实时水印]支持动态文字水印、png水印;
  • [镜像]Android平台支持前置摄像头实时镜像功能;
  • [实时静音]支持实时静音/取消静音;
  • [实时快照]支持实时快照;
  • [降噪]支持环境音、手机干扰等引起的噪音降噪处理、自动增益、VAD检测;
  • [外部编码前视频数据对接]支持YUV数据对接;
  • [外部编码前音频数据对接]支持PCM对接;
  • [外部编码后视频数据对接]支持外部H.264数据对接;
  • [外部编码后音频数据对接]外部AAC数据对接;
  • [扩展录像功能]支持录像相关功能。

平台功能扩展:

Android平台,主要是采集设备接入这块的考量,由于GB28181设备接入行业应用广泛,常见的数据对接类型有:

  1. 编码前数据(目前支持的有YV12/NV21/NV12/I420/RGB24/RGBA32/RGB565等数据类型),其中,Android平台前后摄像头数据(需要考虑对接camera2接口和外置OTG摄像头),或者屏幕数据,或者Unity拿到的数据,均属编码前数据;
  2. 编码后数据(如无人机等264/HEVC数据,或者本地解析的MP4音视频数据);
  3. 拉取RTSP或RTMP流并接入至GB28181平台(比如其他IPC的RTSP流,可通过Android平台GB28181接入到国标平台)。

其他方面不再赘述,以下展示下,和语音广播语音对讲相关的设计:

代码语言:javascript复制
/*
     * CameraPublishActivity.java
     * CameraPublishActivity
     *
     * WebSite: https://daniusdk.com
     * Github: https://github.com/daniulive/SmarterStreaming
     * 
     */

    @Override
    public void ntsOnNotifyBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "ntsOnNotifyBroadcastCommand, fromUserName:"  from_user_name_   ", fromUserNameAtDomain:"  from_user_name_at_domain_
                  ", SN:"   sn_   ", sourceID:"   source_id_   ", targetID:"   target_id_);

                if (gb28181_agent_ != null ) {
                    gb28181_agent_.respondBroadcastCommand(from_user_name_, from_user_name_at_domain_,sn_,source_id_, target_id_, true);
                    btnGB28181AudioBroadcast.setText("收到GB28181语音广播通知");
                }
            }

            private String from_user_name_;
            private String from_user_name_at_domain_;
            private String sn_;
            private String source_id_;
            private String target_id_;

            public Runnable set(String from_user_name, String from_user_name_at_domain, String sn, String source_id, String target_id) {
                this.from_user_name_ = from_user_name;
                this.from_user_name_at_domain_ = from_user_name_at_domain;
                this.sn_ = sn;
                this.source_id_ = source_id;
                this.target_id_ = target_id;
                return this;
            }

        }.set(fromUserName, fromUserNameAtDomain, sn, sourceID, targetID),0);
    }

    @Override
    public void ntsOnAudioBroadcast(String commandFromUserName, String commandFromUserNameAtDomain, String sourceID, String targetID) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "ntsOnAudioBroadcastPlay, fromFromUserName:"   command_from_user_name_
                          " FromUserNameAtDomain:"   command_from_user_name_at_domain_
                          " sourceID:"   source_id_   ", targetID:"   target_id_);

                stopAudioPlayer();
                destoryRTPReceiver();

                if (gb28181_agent_ != null ) {
                    String local_ip_addr = IPAddrUtils.getIpAddress(context_);

                    boolean is_tcp = true; // 考虑到跨网段, 默认用TCP传输rtp包
                    rtp_receiver_handle_ = lib_player_.CreateRTPReceiver(0);
                    if (rtp_receiver_handle_ != 0 ) {
                        lib_player_.SetRTPReceiverTransportProtocol(rtp_receiver_handle_, is_tcp?1:0);
                        lib_player_.SetRTPReceiverIPAddressType(rtp_receiver_handle_, 0);

                        if (0 == lib_player_.CreateRTPReceiverSession(rtp_receiver_handle_, 0) ) {
                            int local_port = lib_player_.GetRTPReceiverLocalPort(rtp_receiver_handle_);
                            boolean ret = gb28181_agent_.inviteAudioBroadcast(command_from_user_name_,command_from_user_name_at_domain_,
                                    source_id_, target_id_, "IP4", local_ip_addr, local_port, is_tcp?"TCP/RTP/AVP":"RTP/AVP");

                            if (!ret ) {
                                destoryRTPReceiver();
                                btnGB28181AudioBroadcast.setText("GB28181语音广播");
                            }
                            else {
                                btnGB28181AudioBroadcast.setText("GB28181语音广播呼叫中");
                            }
                        } else {
                            destoryRTPReceiver();
                            btnGB28181AudioBroadcast.setText("GB28181语音广播");
                        }
                    }
                }
            }

            private String command_from_user_name_;
            private String command_from_user_name_at_domain_;
            private String source_id_;
            private String target_id_;

            public Runnable set(String command_from_user_name, String command_from_user_name_at_domain, String source_id, String target_id) {
                this.command_from_user_name_ = command_from_user_name;
                this.command_from_user_name_at_domain_ = command_from_user_name_at_domain;
                this.source_id_ = source_id;
                this.target_id_ = target_id;
                return this;
            }

        }.set(commandFromUserName, commandFromUserNameAtDomain, sourceID, targetID),0);
    }

    @Override
    public void ntsOnInviteAudioBroadcastException(String sourceID, String targetID, String errorInfo) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "ntsOnInviteAudioBroadcastException, sourceID:"   source_id_   ", targetID:"   target_id_);

                destoryRTPReceiver();
                btnGB28181AudioBroadcast.setText("GB28181语音广播");
            }

            private String source_id_;
            private String target_id_;

            public Runnable set(String source_id, String target_id) {
                this.source_id_ = source_id;
                this.target_id_ = target_id;
                return this;
            }

        }.set(sourceID, targetID),0);
    }

    @Override
    public void ntsOnInviteAudioBroadcastTimeout(String sourceID, String targetID) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "ntsOnInviteAudioBroadcastTimeout, sourceID:"   source_id_   ", targetID:"   target_id_);

                destoryRTPReceiver();
                btnGB28181AudioBroadcast.setText("GB28181语音广播");
            }

            private String source_id_;
            private String target_id_;

            public Runnable set(String source_id, String target_id) {
                this.source_id_ = source_id;
                this.target_id_ = target_id;
                return this;
            }

        }.set(sourceID, targetID),0);
    }

感兴趣的开发者,可以直接查看相关规范。

0 人点赞