Android平台GB28181设备接入侧如何实现按需打开视音频采集传输

本文涉及的产品
视觉智能开放平台,视频通用资源包5000点
视觉智能开放平台,图像通用资源包5000点
视觉智能开放平台,分割抠图1万点
简介: Android平台GB28181设备接入侧如何实现按需打开视音频采集传输

GB/T28181规范

GB/T28181是中国国家标准,全称为《安全防范视频监控联网系统信息传输、交换、控制技术要求》,该标准规定了城市安全防范监控系统中视频监控联网系统的一般要求和架构,以及信息传输、交换、控制的技术要求。它主要应用于安防领域,为各种视频监控系统提供了一致的接口规范,使得不同厂商生产的视频监控设备可以相互兼容。规范规定了公共安全视频监控联网系统(以下简称“联网系统”)的互联结构,传输、交换、控制的基本要求和安全性要求,以及控制、传输流程和协议接口等技术要求。适用于公共安全视频监控联网系统的方案设计、系统检测、验收以及与之相关的设备研发生产。其他视频监控联网系统可参照执行。目前已更新至GB/T28181-2022版。

为什么要开发Android平台GB28181接入模块

实际上,Android平台GB28181接入模块,主要目标是可实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景。

image.gif视沃科技(大牛直播SDK)GB28181设备接入SDK.png

Android终端除支持常规的音视频数据接入外,还可以支持移动设备位置(MobilePosition)订阅和通知、语音广播和语音对讲,历史视音频文件查询和下载,支持对接数据类型如下:

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

    功能设计

    实际上,我们在做Android平台GB28181设备接入模块之前,已经有非常成熟的视音频采集(屏幕、摄像头、外部音视频数据)、软硬编码、录像、快照、实时动态水印等技术储备,所以,GB28181设备接入,主要考虑的是信令和媒体流传输这块,考虑到设备性能和实际场景,我们信令和媒体传输设计是分离的,Android端GB28181设备接入侧注册到国标平台后,如果国标平台不需要查看前端设备数据,我们仅维持心跳(KeepAlive),需要查看的时候,我们再开摄像头、麦克风编码打包投递数据给平台侧,尽可能的减少性能消耗,这块在执法记录仪、智能安全帽等场景下,非常实用。

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

      Android端如何实现后台视音频GB28181接入

      后台采集摄像头和麦克风这块,不再赘述,基本做Andorid开发的,都能搞得定,需要注意的是,后台service推送,需要加入省电优化白名单,以免8.0及以上版本设备后台运行超过一分钟被自动停掉,6.0以上版本,需要动态获取权限:

      if (Build.VERSION.SDK_INT>=26)
      {
      if(!isIgnoringBatteryOptimizations())
        {
      gotoSettingIgnoringBatteryOptimizations();
        }
      }
      //6.0及以上版本,动态获取Audio权限if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M)
      {
      RequestAudioPermission();
      }

      image.gif

      我们要做的就是选择分辨率、软硬编码等参数后,启动GB28181即可:

      推送smartservicecamerapublisher.jpg

      因为系后台服务,启动后,任务栏可以看到:

      smartservicecamerapublisher.jpg

      收到平台侧发来的Invite后,我们会调用try_preview_camera()来启动摄像头后台预览。

      /** BackgroudService.java* Author: daniusdk.com*/@OverridepublicvoidntsOnInvitePlay(StringdeviceId, SessionDescriptionsession_des) {
      handler_.postDelayed(newRunnable() {
      @Overridepublicvoidrun() {
      // 先振铃响应下gb28181_agent_.respondPlayInvite(180, device_id_);
      if (!try_preview_camera()) {
      gb28181_agent_.respondPlayInvite(488, device_id_);
      Log.i(TAG, "ntsOnInvitePlay try_preview_camera failed, response 488, device_id:"+device_id_);
      return;
            }
      MediaSessionDescriptionvideo_des=null;
      SDPRtpMapAttributeps_rtpmap_attr=null;
      // 28181 视频使用PS打包Vector<MediaSessionDescription>video_des_list=session_des_.getVideoPSDescriptions();
      if (video_des_list!=null&&!video_des_list.isEmpty()) {
      for(MediaSessionDescriptionm : 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;
            }
      if (null==ps_rtpmap_attr ) {
      gb28181_agent_.respondPlayInvite(488, device_id_);
      Log.i(TAG, "ntsOnInvitePlay get ps rtp map attribute 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());
      longrtp_sender_handle=lib_publisher_.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_=ps_rtpmap_attr.getPayloadType();
      gb28181_rtp_encoding_name_=ps_rtpmap_attr.getEncodingName();
      lib_publisher_.SetRTPSenderTransportProtocol(rtp_sender_handle, video_des.isRTPOverUDP()?0:1);
      lib_publisher_.SetRTPSenderIPAddressType(rtp_sender_handle, video_des.isIPv4()?0:1);
      lib_publisher_.SetRTPSenderLocalPort(rtp_sender_handle, 0);
      lib_publisher_.SetRTPSenderSSRC(rtp_sender_handle, video_des.getSSRC());
      lib_publisher_.SetRTPSenderSocketSendBuffer(rtp_sender_handle, 2*1024*1024); // 设置到2Mlib_publisher_.SetRTPSenderClockRate(rtp_sender_handle, ps_rtpmap_attr.getClockRate());
      lib_publisher_.SetRTPSenderDestination(rtp_sender_handle, video_des.getAddress(), video_des.getPort());
      if ( lib_publisher_.InitRTPSender(rtp_sender_handle) !=0 ) {
      gb28181_agent_.respondPlayInvite(488, device_id_);
      lib_publisher_.DestoryRTPSender(rtp_sender_handle);
      return;
            }
      intlocal_port=lib_publisher_.GetRTPSenderLocalPort(rtp_sender_handle);
      if (local_port==0) {
      gb28181_agent_.respondPlayInvite(488, device_id_);
      lib_publisher_.DestoryRTPSender(rtp_sender_handle);
      return;
            }
      Log.i(TAG,"get local_port:"+local_port);
      Stringlocal_ip_addr=IPAddrUtils.getIpAddress(context_);
      MediaSessionDescriptionlocal_video_des=newMediaSessionDescription(video_des.getType());
      local_video_des.addFormat(String.valueOf(ps_rtpmap_attr.getPayloadType()));
      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) ) {
      lib_publisher_.DestoryRTPSender(rtp_sender_handle);
      Log.e(TAG, "ntsOnInvitePlay call respondPlayInviteOK failed.");
      return;
            }
      gb28181_rtp_sender_handle_=rtp_sender_handle;
          }
      privateStringdevice_id_;
      privateSessionDescriptionsession_des_;
      publicRunnableset(Stringdevice_id, SessionDescriptionsession_des) {
      this.device_id_=device_id;
      this.session_des_=session_des;
      returnthis;
          }
        }.set(deviceId, session_des),0);
      }

      image.gif

      try_preview_camera()实现如下:

      privatebooleantry_preview_camera() {
      if (camera_!=null)
      returntrue;
      SurfaceHoldersurface_holder=get_surface_holder();
      if (null==surface_holder) {
      Log.e(TAG, "try_preview_camera surface_holder is null");
      returnfalse;
          }
      camera_=open_camera(current_camera_type_);
      if (null==camera_) {
      Log.e(TAG, "try_preview_camera open_camera is null type:"+current_camera_type_);
      returnfalse;
           }
      if (!start_camera_preview(surface_holder)) {
      release_camera();
      Log.i(TAG, "try_preview_camera start_camera_preview failed");
      returnfalse;
          }
      returntrue;
       }

      image.gif

      收到ack后,直接发送数据到国标平台侧即可

      @OverridepublicvoidntsOnAckPlay(StringdeviceId) {
      handler_.postDelayed(newRunnable() {
      @Overridepublicvoidrun() {
      Log.i(TAG,"ntsOnACKPlay, device_id:"+device_id_);
      InitAndSetConfig();
      lib_publisher_.SetGB28181RTPSender(publisher_handle_, gb28181_rtp_sender_handle_, gb28181_rtp_payload_type_, gb28181_rtp_encoding_name_);
      //libPublisher.SetGBTCPConnectTimeout(publisherHandle, 10*60*1000);//libPublisher.SetGBInitialTCPReconnectInterval(publisherHandle, 1000);//libPublisher.SetGBInitialTCPMaxReconnectAttempts(publisherHandle, 3);intstartRet=lib_publisher_.StartGB28181MediaStream(publisher_handle_);
      if (startRet!=0) {
      if (publisher_handle_!=0) {
      lib_publisher_.SmartPublisherClose(publisher_handle_);
      publisher_handle_=0;
              }
      destoryRTPSender();
      Log.e(TAG, "Failed to start GB28181 service..");
      return;
            }
      startAudioRecorder();
      startLayerPostThread();
      is_gb_stream_running_=true;
          }
      privateStringdevice_id_;
      publicRunnableset(Stringdevice_id) {
      this.device_id_=device_id;
      returnthis;
          }
        }.set(deviceId),0);
      }

      image.gif

      关闭预览查看,处理bye信令:

      @OverridepublicvoidntsOnByePlay(StringdeviceId) {
      handler_.postDelayed(newRunnable() {
      @Overridepublicvoidrun() {
      Log.i(TAG, "ntsOnByePlay, stop GB28181 media stream, deviceId="+device_id_);
      stopGB28181Stream();
      destoryRTPSender();
          }
      privateStringdevice_id_;
      publicRunnableset(Stringdevice_id) {
      this.device_id_=device_id;
      returnthis;
          }
        }.set(deviceId),0);
      }

      image.gif

      其中stopGB28181Stream()需要关闭摄像头(对应release_camera())和麦克风(对应stopAudioRecorder()),确保只有国标平台测查看的时候,才开启摄像头,尽可能的减少性能损耗。

      //停止GB28181 媒体流privatevoidstopGB28181Stream() {
      if (!is_gb_stream_running_)
      return;
      stopLayerPostThread();
      stopAudioRecorder();
      release_camera();
      is_gb_stream_running_=false;
      lib_publisher_.StopGB28181MediaStream(publisher_handle_);
      if (publisher_handle_!=0) {
      lib_publisher_.SmartPublisherClose(publisher_handle_);
      publisher_handle_=0;
        }
      }

      image.gif

      总结

      以上是大概的流程,摄像头麦克风采集做到后台的话,可以在需要预览采集数据的时候才打开,不用的时候,直接关闭,只保留信令这块,打开视音频预览后,如果有语音广播过来,可以直接播放语音广播的数据,这样尽可能的减少设备的性能消耗,提高待机时间,特别是执法记录仪等户外设备,按需打开摄像头和麦克风,按需投递视音频数据到平台外侧,意义非常大。

      相关文章
      |
      6月前
      |
      存储 Android开发
      如何查看Flutter应用在Android设备上已被撤销的权限?
      如何查看Flutter应用在Android设备上已被撤销的权限?
      273 64
      |
      6月前
      |
      存储 Android开发 数据安全/隐私保护
      如何在Android设备上撤销Flutter应用程序的所有权限?
      如何在Android设备上撤销Flutter应用程序的所有权限?
      361 64
      |
      6月前
      |
      缓存 Android开发 开发者
      Flutter环境配置完成后,如何在Android设备上运行Flutter应用程序?
      Flutter环境配置完成后,如何在Android设备上运行Flutter应用程序?
      1024 62
      |
      6月前
      |
      开发工具 Android开发 开发者
      在Android设备上运行Flutter应用程序时,如果遇到设备未授权的问题该如何解决?
      在Android设备上运行Flutter应用程序时,如果遇到设备未授权的问题该如何解决?
      335 61
      |
      3月前
      |
      监控 Android开发 数据安全/隐私保护
      批量发送短信的平台,安卓群发短信工具插件脚本,批量群发短信软件【autojs版】
      这个Auto.js脚本实现了完整的批量短信发送功能,包含联系人管理、短信内容编辑、发送状态监控等功能
      |
      7月前
      |
      存储 编解码 监控
      Android平台GB28181执法记录仪技术方案与实现
      本文介绍了大牛直播SDK的SmartGBD在执法记录仪场景中的应用。GB28181协议作为视频监控联网的国家标准,为设备互联互通提供规范。SmartGBD专为Android平台设计,支持音视频采集、编码与传输,具备自适应算法和多功能扩展优势。文章分析了执法记录仪的需求,如实时音视频传输、设备管理及数据安全,并详细阐述了基于SmartGBD的技术实现方案,包括环境准备、SDK集成、设备注册、音视频处理及功能扩展等步骤。最后展望了SmartGBD在未来智慧物联领域的广阔应用前景。
      278 13
      |
      7月前
      |
      监控 Shell Linux
      Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
      ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
      |
      19天前
      |
      开发工具 Android开发
      X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
      X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
      233 11
      X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
      |
      29天前
      |
      Java 开发工具 Maven
      【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
      【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
      106 6
      |
      3月前
      |
      安全 数据库 Android开发
      在Android开发中实现两个Intent跳转及数据交换的方法
      总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
      199 11

      热门文章

      最新文章