前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android平台GB28181设备接入端如何实时更新经纬度实现国标平台侧电子地图位置标注

Android平台GB28181设备接入端如何实时更新经纬度实现国标平台侧电子地图位置标注

原创
作者头像
音视频牛哥
发布于 2022-12-26 10:19:56
发布于 2022-12-26 10:19:56
82900
代码可运行
举报
运行总次数:0
代码可运行

技术背景

我们在做GB28181设备接入端的时候,其中有个功能,不难但非常重要:那就是GB28181实时位置的订阅(mobileposition subscribe)和上报(notify)。

特别是执法记录仪、智能安全帽、车载终端等场景下,现场人员的实时位置是国标平台侧非常关注的。国标平台侧通过周期性的获取GB28181设备接入端的经纬度信息,并在电子地图显示,需要看现场的情况,点开图标,进行音视频回传和语音广播语音对讲等操作,现场人员的总体概况一目了然。

规范解读

其他不表,我们先看看GB/T28181-2016规范中,关于订阅通知流程:

基本流程和注解如下:

  1. 国标服务平台向Android平台GB28181设备接入终端发送SUBSCRIBE消息体,并携带Expire头域指定订阅过期时间;
  2. Android平台GB28181设备接入终端收到SUBSCRIBE后,200 OK响应;
  3. Android平台GB28181设备接入终端发送 NOTIFY 消息相关的位置信息,并使用Event头域描述订阅事件,国标GB28181的移动设备位置订阅这个值是"presence"
  4. 国标服务平台收到 Android平台GB28181设备接入终端NOTIFY消息后,200 OK响应;
  5. NOTIFY...200 OK...NOTIFY...200 OK...etc..
  6. 国标服务平台在订阅过期之前,向Android国标接入终端发送刷新订阅 SUBSCRIBE 消息,消息头域中使用 Event头域描述订阅事件,消息体中携带订阅的详细参数,使用 Expire头域指定订阅过期时间;
  7. Android平台GB28181设备接入终端收到订阅消息后,向国标服务平台发送200 OK响应;
  8. NOTIFY...200 OK...NOTIFY...200 OK........
  9. 如国标服务平台需要取消订阅,可以向Android平台GB28181设备接入终端发送取消订阅SUBSCRIBE消息,消息头域中使用Event头域描述订阅事件,消息体中携带订阅的详细参数,Expire头域值为0;
  10. Android国标接入终端收到订阅消息后,向国标服务平台发送200 OK响应,取消向国标服务平台发送实时位置通知消息,取消订阅成功的话,也会发一个最终的NOTIFY给国标服务端;
  11. 这里需要注意的是:Android平台GB28181设备接入终端收到SUBSCRIBE请求后,会检查SUBSCRIBE请求中"Expires"值的大小,当且仅当这个值大于0且小于1小时,并且小于Notifier配置的最小值时,Notifier可能会返回一个"423 Interval too small"错误,并包含一个""Min-Expires" 头域;
  12. Android国标接入端发送的NOTIFY请求超时的话,应该移除这个订阅;
  13. NOTIFY request必须包含"Subscription-State"头,有三个可选的值:"active", "pending", "terminated". 当值是"active"或"pending"时,应该也包含一个”expires“参数,显示订阅剩余时间。

GB/T28181-2016针对MobilePosition描述

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<elementname="TargetID"type="tg:deviceIDType"/>移动设备位置数据通知
<! -- 命令类型:移动设备位置数据通知(必选)-->
<elementname="CmdType"fixed="MobilePosition"/>
<! -- 命令序列号(必选)-->
<elementname="SN" type="integer"minInclusivevalue= "1"/>
<! -- 产生通知时间(必选)--> 
<elementname="Time" type="dateTime"/> 
<! --经度(必选)--> <elementname="Longitude"type="double"/> 
<! -- 纬度(必选)--> <elementname="Latitude"type="double"/> 
<! --速度,单位:km/h(可选)--> 
<elementname="Speed"type="double"/> 
<!--方向,取值为当前摄像头方向与正北方的顺时针夹角,取值范围0°~360°,单位:(°)(可选)-->
<elementname="Direction"type="double"/>
<! --海拔高度,单位:m(可选)-->
<elementname="Altitude"type="tg:deviceIDType"/>

技术实现

Android平台GB28181设备接入端,启动GB28181后,调用InitGB28181Agent()的时候,添加设备:

相关代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
    * Camera2Activity.java
    * Author: daniusdk.com
    */ 
   private boolean initGB28181Agent() {
        if ( gb28181_agent_ != null )
            return  true;

        getLocation(context_);

        String local_ip_addr = IPAddrUtils.getIpAddress(context_);
        Log.i(TAG, "initGB28181Agent local ip addr: " + local_ip_addr);

        if ( local_ip_addr == null || local_ip_addr.isEmpty() ) {
            Log.e(TAG, "initGB28181Agent local ip is empty");
            return  false;
        }

        gb28181_agent_ = GBSIPAgentFactory.getInstance().create();
        if ( gb28181_agent_ == null ) {
            Log.e(TAG, "initGB28181Agent create agent failed");
            return false;
        }

        gb28181_agent_.addListener(this);
        gb28181_agent_.addPlayListener(this);
      
        gb28181_agent_.addTalkListener(this);
        gb28181_agent_.addAudioBroadcastListener(this);
        gb28181_agent_.addDeviceControlListener(this);
        gb28181_agent_.addQueryCommandListener(this);

        // 必填信息
        gb28181_agent_.setLocalAddress(local_ip_addr);
        gb28181_agent_.setServerParameter(gb28181_sip_server_addr_, gb28181_sip_server_port_, gb28181_sip_server_id_, gb28181_sip_domain_);
        gb28181_agent_.setUserInfo(gb28181_sip_username_, gb28181_sip_password_);

        // 可选参数
        gb28181_agent_.setUserAgent(gb28181_sip_user_agent_filed_);
        gb28181_agent_.setTransportProtocol(gb28181_sip_trans_protocol_==0?"UDP":"TCP");

        // GB28181配置
        gb28181_agent_.config(gb28181_reg_expired_, gb28181_heartbeat_interval_, gb28181_heartbeat_count_);

        com.gb.ntsignalling.Device gb_device = new com.gb.ntsignalling.Device("34020000001310000001", "安卓测试设备", Build.MANUFACTURER, Build.MODEL,
                    "宇宙","火星1","火星", true);

        if (mLongitude != null && mLatitude != null) {
            com.gb.ntsignalling.DevicePosition device_pos = new com.gb.ntsignalling.DevicePosition();

            device_pos.setTime(mLocationTime);
            device_pos.setLongitude(mLongitude);
            device_pos.setLatitude(mLatitude);
            gb_device.setPosition(device_pos);

            gb_device.setSupportMobilePosition(true); // 设置支持移动位置上报
        }

        gb28181_agent_.addDevice(gb_device);


        if (!gb28181_agent_.createSipStack()) {
            gb28181_agent_ = null;
            Log.e(TAG, "initGB28181Agent gb28181_agent_.createSipStack failed.");
            return  false;
        }

        boolean is_bind_local_port_ok = false;

        // 最多尝试5000个端口
        int try_end_port = gb28181_sip_local_port_base_ + 5000;
        try_end_port = try_end_port > 65536 ?65536: try_end_port;

        for (int i = gb28181_sip_local_port_base_; i < try_end_port; ++i) {
            if (gb28181_agent_.bindLocalPort(i)) {
                is_bind_local_port_ok = true;
                break;
            }
        }

        if (!is_bind_local_port_ok) {
            gb28181_agent_.releaseSipStack();
            gb28181_agent_ = null;
            Log.e(TAG, "initGB28181Agent gb28181_agent_.bindLocalPort failed.");
            return  false;
        }

        if (!gb28181_agent_.initialize()) {
            gb28181_agent_.unBindLocalPort();
            gb28181_agent_.releaseSipStack();
            gb28181_agent_ = null;
            Log.e(TAG, "initGB28181Agent gb28181_agent_.initialize failed.");
            return  false;
        }

        return true;
    }

Android平台GB28181设备接入端DevicePosition设计如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * DevicePosition.java
 * Author: daniusdk.com
 */
public class DevicePosition {
    private String mTime; // 产生位置信息的时间,格式如:2022-03-16T10:37:21, yyyy-MM-dd'T'HH:mm:ss
    private String mLongitude; // 经度
    private String mLatitude; //纬度
    private String mSpeed; // 速度,单位:km/h
    private String mDirection; // 方向,取值为当前摄像头方向与正北方的顺时针夹角,取值范围0°~360°,单位:(°)
    private String mAltitude; // 海拔高度,单位:m
 
    public String getTime() {
        return mTime;
    }
 
    public void setTime(String time) {
        this.mTime = time;
    }
 
    public String getLongitude() {
        return mLongitude;
    }
 
    public void setLongitude(double longitude) {
        this.mLongitude = String.valueOf(longitude);
    }
 
    public void setLongitude(String longitude) { this.mLongitude =longitude; }
 
    public String getLatitude() {
        return mLatitude;
    }
 
    public void setLatitude(double latitude) {
        this.mLatitude = String.valueOf(latitude);
    }
 
    public void setLatitude(String latitude) { this.mLatitude = latitude;}
 
    public String getSpeed() {
        return mSpeed;
    }
 
    public void setSpeed(double speed) {
        this.mSpeed = String.valueOf(speed);
    }
 
    public String getDirection() {
        return mDirection;
    }
 
    public void setDirection(double direction) {
        this.mDirection = String.valueOf(direction);
    }
 
    public String getAltitude() {
        return mAltitude;
    }
 
    public void setAltitude(double altitude) {
        this.mAltitude = String.valueOf(altitude);
    }
}

当有SUBSCRIBE request请求位置更新,上层处理如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
    public void ntsOnDevicePositionRequest(String deviceId, int interval) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                getLocation(context_);

                Log.v(TAG, "ntsOnDevicePositionRequest, deviceId:" + this.device_id_ + ", Longitude:" + mLongitude
                        + ", Latitude:" + mLatitude + ", Time:" + mLocationTime);


                if (mLongitude != null && mLatitude != null) {
                    com.gb.ntsignalling.DevicePosition device_pos = new com.gb.ntsignalling.DevicePosition();

                    device_pos.setTime(mLocationTime);
                    device_pos.setLongitude(mLongitude);
                    device_pos.setLatitude(mLatitude);

                    if (gb28181_agent_ != null ) {
                        gb28181_agent_.updateDevicePosition(device_id_, device_pos);
                    }
                }
            }

            private String device_id_;
            private int interval_;

            public Runnable set(String device_id, int interval) {
                this.device_id_ = device_id;
                this.interval_ = interval;
                return this;
            }

        }.set(deviceId, interval),0);
    }

总结

国标平台侧获取到Android平台GB28181设备接入端的实时位置信息后,可以非常方便的根据实时经纬度信息,把前端设备位置标注到地图服务上。Android平台获取实时经纬度并无难度,这里不再赘述。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
VBA进程查找程序路径与命令参数
Function 进程路径(Optional exen) 'Debug.Print 进程路径("EXCEL.EXE") If IsMissing(exen) Then exen = "EXCEL.EXE" Set p = GetObject("WinMgmts:").InstancesOf("Win32_Process") For Each Pj In p If Pj.Description = exen Then 进程路径 = Pj.ExecutablePath Next End Functi
林万程
2018/06/26
1.1K0
python: 监控windows 下进
目的: 针对Windows下进程异常退出后,此程序自动启动被监控进程。如:监控Serv-U.exe 程序是使用python语言编写,可在Windows下双击MonitorWin32Process.exe直接运行。程序会按照config.ini配置文件,进行监控进程。如果没有被监控的进程,则会按照进程启动路径自动启动。 详细使用请查看压包内的使用说明.
py3study
2020/01/07
1.6K0
规避检测(共五章):第五章
沙盒模拟通常持续很短的时间,因为沙盒加载了数千个样本。仿真 时间很少超过3-5分钟。因此,恶意软件可以利用这一事实来避免检测:它可能会执行 在开始任何恶意活动之前长时间延迟。
Creaper
2023/11/20
3860
规避检测(共五章):第五章
怎么制止qq刷屏代码-vbs「建议收藏」
最近有些人向小编反应QQ刷屏代码没办法关,小编认为有必要发布一下关程序的代码, 专门针对上次的QQ刷屏代码:
全栈程序员站长
2022/07/01
8740
Python wmi 模块的学习
# -*- coding:utf-8 -*- import datetime import os import wmi import time import _winreg import pythoncom import threading import win32api import win32con import Queue c = wmi.WMI() # 如果要连接远程机器,只需要在WMI构造器中指定远程机器名即可 # c = wmi.WMI("some_other_machine") # Li
py3study
2020/01/08
2.9K0
PS编程补充说明
描述: 脚本和批处理都属于伪可执行文件,它们只是包含了若干命令行解释器能够解释和执行的命令行代码。
全栈工程师修炼指南
2022/09/29
2K0
各种有趣vbs,bat脚本[通俗易懂]
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/167212.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/20
9750
mshta usage
Example 1, show a message box in many different ways.
全栈程序员站长
2022/09/14
8620
IFix 调度后台任务被关闭如何处理(含代码)
在 IFix 使用过程中经常会使用到调度功能来实现定时报告,事件触发类的脚本,那么后台调度的进程也会出现被操作人员等意外关闭的情况。那么就会造成我们的定时报告,脚本等无法正常运行。
剑指工控
2021/11/09
8900
WMI利用(横向移动)
上一篇文章我们简单的解释了什么是WMI,WMI做什么,为什么使用WMI。本文是笔者在阅读国内部分的解释WMI横向移动的文章后写下的一篇文章,希望帮助同学们在攻防中进入横向移动后根据实际场景利用WMI来解决问题。在横向移动中的固定过程中一定离不开“信息收集”,然后分析信息根据实际场景(工作组或者域)来进行横向移动,至于使用什么工具,为什么使用这个工具,笔者使用WMI的意见。所以本文分为三个段落,信息收集、横向移动、部分意见。 信息收集。
谢公子
2022/01/19
3K0
WMI利用(横向移动)
域控制器安全
本篇继续阅读学习《内网安全攻防:渗透测试实战指南》,本章是域控制器安全,介绍了使用Kerberos域用户提权和导出ntds.dit中散列值的方法,并针对域控制器攻击提出了有效的安全建议
中龙技术
2022/09/29
7890
Windows WMI库最简单的读取方式.
首先我们先声明一个VARIANT类型转Array数组的函数. 这函数已经做了完全的兼容.
Tuesday
2019/09/04
8170
Windows WMI库最简单的读取方式.
钓鱼文档碎碎念(一)
本文将简单介绍使用宏代码进行钓鱼的方法,并使其可以回连到CobaltStrike. CobaltStrike.自带有宏钓鱼功能。可以使用如下步骤进行创建:
鸿鹄实验室
2021/03/31
9020
钓鱼文档碎碎念(一)
WMI技术介绍和应用——查询正在运行的进程信息
       在《WMI技术介绍和应用——使用VC编写一个半同步查询WMI服务的类》一文中,我们介绍到了一个半同步查询WMI类的框架。本文将是该技术的一个应用,介绍如何使用WMI技术查询正在运行的进程信息。(转载请指明出于breaksoftware的csdn博客)
方亮
2019/01/16
1.8K0
PS常用命令之系统WMI查看和操作相关命令
[TOC] 0x00 前言简述 Q: 什么是WMI? 答: WMI出现至今已经多年,但很多人对它并不熟悉。知道它很好很强大,但不知道它从哪里来,怎么工作,使用范围是什么? WMI有一组API我们不管
全栈工程师修炼指南
2022/09/29
1.5K0
经典vbs代码收集「建议收藏」
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/144726.html原文链接:https://javaforall.cn
全栈程序员站长
2022/08/30
1.8K0
GadgetToJScript在VBA中的利用
https://www.shutingrz.com/post/explore-dotnet-serialize-g2js/
鸿鹄实验室
2021/07/06
2.7K0
GadgetToJScript在VBA中的利用
WMI技术介绍和应用——Instance/Method Provider
        在《WMI技术介绍和应用——事件通知》一文中,我们提到了提供者(Provider)这个概念。我们还是要引入WMI的结构图(转载请指明出于breaksoftware的csdn博客)
方亮
2019/01/16
9420
python通过ssh-powershell监控windows
对于服务器的监控来说,监控linux不管是自己动手写脚本还是用一些开源的工具比如nagios,zenoss什么的。但毕竟还是有些公司有 windows做服务器的,相对linux来说,windows没有方便的shell,cmd下提供的命令对于监控来说远远没有linux方便。但是现在 windows上如果安装了powershell(win7,2008自带),就比以前方便多了,linux上的命令基本都能在powershell里执 行,比如查看进程还是ps. 自己封装了一个python通过ssh(通过pexpect模块)调用powershell的脚本,里面包 快ps,netstat,ping检测,查看硬盘,cpu信息和负载,内存信息。通过创建ssh_win32类对象,然后调用它的方法,返回的都是解析好 的python对象。 ssh_powershell.py
用户7999227
2021/11/01
5790
WMI 攻击手法研究 – 探索命名空间、类和方法 (第二部分)
本篇文章是 WMI 攻击手法研究的第二篇,主要研究 WMI 中的 3 个组件,在整篇文章中,我们将交替使用 WMI 和 CIM cmdlet,以便熟悉这两种 cmdlet 类型。
帝旭科技
2022/11/23
1.7K0
WMI 攻击手法研究 – 探索命名空间、类和方法 (第二部分)
相关推荐
VBA进程查找程序路径与命令参数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验