概述
前言:因业务需要对接海康威视的综合安防管理平台获得下属所管理的摄像头,根据摄像头code获得监控视频流信息
1、详情可以浏览海康开放平台,在官网上有对应的接入指南以及开放的API接口【前提是本地已部署了海康视频流媒体服务器】
2、通过海康开放平台我们看到相关的对接指南,进行开发前准备。如下图所示:
3、AK/SK可以要求甲方提供,如果是驻场开发可以在当前的局域网下通过运管中心的登录名/密码登陆该平台,通过下面的索引步骤来获得 AK/SK。
4、获得到 AK/SK后,通过参考开放的API文档,找到项目所需的对用接口,本文所用到的接口主要为:
- 分页获取区域列表
- 根据区域获取下级编码设备列表
- 获取监控点预览取流
5、相应开发代码
- 引入海康依赖
<!--海康依赖-->
<dependency>
<groupId>com.hikvision.ga</groupId>
<artifactId>artemis-http-client</artifactId>
<version>1.1.3</version>
</dependency>
- 对应接口的测试代码
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import net.sf.json.JSONObject;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import java.util.HashMap;
import java.util.Map;
/**
* @author Orange
* @version 1.0
* @Description:调用海康接口获得监控视频流
* @date 2020/11/16 14:44
*/
public class HkTest {
private static final Logger logger = LoggerFactory.getLogger(HkTest.class);
static {
ArtemisConfig.host = "10.*.1.99:443"; // artemis网关服务器ip端口
ArtemisConfig.appKey = "25411867"; // 秘钥appkey
ArtemisConfig.appSecret = "*************";// 秘钥appSecret
}
/**
*设置OpenAPI接口的上下文
*/
private static final String ARTEMIS_PATH = "/artemis";
/*
* @Description: 分页获取区域信息
* @author: Orange
* @Param: /api/resource/v1/regions/root
* @Return: java.lang.String
* @Date: 2020/11/17 11:21
*/
public static String getRegionsPageList(int pageNo, int pageSize){
//获取区域信息路径 /api/resource/v1/regions/root
final String getRegionsList = ARTEMIS_PATH + "/api/resource/v1/regions";
Map<String, String> path = new HashMap<String, String>(2) {
{
put("https://", getRegionsList);
}
};
//定义提交类型
String contentType = "application/json";
//参数装换
JSONObject jsonBody = new JSONObject();
jsonBody.put("pageNo", pageNo);
jsonBody.put("pageSize", pageSize);
String body = jsonBody.toString();
//传参调用方法
String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null);
//返回编码信息
return result;
}
/*
* @Description: 根据区域编号获取下级监控点列表
* @author: Orange
* @Param:
* @Return: java.lang.String
* @Date: 2020/11/17 11:36
*/
public static String getCamerasByRegionCode(String regionIndexCode, int pageNo, int pageSize) {
//根据区域编号获取下级监控点列表路径
final String getRootApi = ARTEMIS_PATH + "/api/resource/v1/regions/regionIndexCode/cameras";
Map<String, String> path = new HashMap<String, String>(2) {
{
put("https://", getRootApi);
}
};
String contentType = "application/json";
JSONObject jsonBody = new JSONObject();
jsonBody.put("pageNo", pageNo);
jsonBody.put("pageSize", pageSize);
jsonBody.put("regionIndexCode", regionIndexCode);
String body = jsonBody.toString();
String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null);
//返回编码信息
return result;
}
/*
* @Description: 根据摄像头编码code获得播放流
* @author: Orange
* @Param:
* @Return: java.lang.String
* @Date: 2020/11/17 13:19
*/
public static String getCamerasUrlByCode(String cameraIndexCode) {
final String getCamsApi = ARTEMIS_PATH + "/api/video/v1/cameras/previewURLs";
Map<String, String> path = new HashMap<String, String>(2) {
{
put("https://", getCamsApi);
}
};
String contentType = "application/json";
net.sf.json.JSONObject jsonBody = new net.sf.json.JSONObject();
jsonBody.put("cameraIndexCode", cameraIndexCode);//监控点唯一标识
jsonBody.put("streamType", 0);//码流类型,0:主码流,1:子码流,2:第三码流,参数不填,默认为主码流
jsonBody.put("protocol", "rtsp");//取流协议,“rtsp”:RTSP协议,“rtmp”:RTMP协议,“hls”:HLS协议
jsonBody.put("transmode", 1);//传输协议,0:UDP,1:TCP,默认是TCP
jsonBody.put("expand", "streamform=ps");//扩展内容,格式:key=value
String body = jsonBody.toString();
String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null);
//返回编码信息
return result;
}
/*
* @Description: 获取摄像头列表
* @author: Orange
* @Param: int
* @Return: java.lang.String
* @Date: 2020/11/17 10:32
*/
public static String getAllRegionInfo(int pageNo, int pageSize) {
//获取摄像头列表路径
final String getCameraList = ARTEMIS_PATH + "/api/resource/v1/cameras";
Map<String, String> path = new HashMap<String, String>(2) {
{
put("https://", getCameraList);
}
};
//定义提交类型
String contentType = "application/json";
//参数装换
JSONObject jsonBody = new JSONObject();
jsonBody.put("pageNo", pageNo);
jsonBody.put("pageSize", pageSize);
String body = jsonBody.toString();
//传参调用方法
String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null);
//返回结果
return result;
}
public static void main(String[] args) {
//调用获取区域信息接口 JSONObject pa=JSONObject.parseObject(params)
String regionsPageList = HKGetCamera.getRegionsPageList(1, 100);
System.out.println( regionsPageList.getClass());
//根据区域id来获取下属于摄像列表
Object camerasByRegionCode = HkTest.getCamerasByRegionCode("e2a69da6-e406-4404-b7f5-6101357248fd", 1, 5);
//根据摄像头code来获得视频流地址
String camerasUrlByCode = HkTest.getCamerasUrlByCode("7ab2f03ffef245dca9345deb02d12997");
//获得摄像头列表
String cameraResult= HkTest.getAllRegionInfo(1,500);
//打印查看返回信息
System.out.println("获得区域信息列表:"+ regionsPageList);
System.out.println("根据区域节点获得摄像头信息:"+ camerasByRegionCode);
System.out.println("根据摄像头code来获得流:"+ camerasUrlByCode);
System.out.println("获得摄像头列表:"+ cameraResult);
}
}
- 获得接口返回数组中的有效信息,下属代码以获取摄像头 code 以及 视频流 url 举例,
String regionsPageList = HKGetCamera.getRegionsPageList(1, 100);
JSONObject jsonObject = JSONObject.parseObject(regionsPageList);
String data = jsonObject.getString("data");
JSONObject jsonData = JSONObject.parseObject(data);
String list = jsonData.getString("list");
JSONArray jsonArray = JSONObject.parseArray(list);
ArrayList<String> regionsResult = new ArrayList<>();
if (Objects.nonNull(jsonArray) && jsonArray.size() > 0) {
for (Object object : jsonArray) {
JSONObject parseObject = JSONObject.parseObject(object.toString());
String cameraIndexCode = parseObject.getString("indexCode");
//2、将获得的地区信息编码封装到list中
regionsResult.add(cameraIndexCode);
}
}
for (String regionsCode : regionsResult) {
String camerasByRegionCode = null;
try{
camerasByRegionCode = HKGetCamera.getCamerasByRegionCode(regionsCode, 10, 1);
JSONObject json = JSONObject.parseObject(camerasByRegionCode);
String resultData = json.getString("data");
JSONObject da = JSONObject.parseObject(resultData);
String url = da.getString("url");
}catch (Exception e){}
}
5、对接监控视频流的处理,可以根据接口传参来设置返回结果中的视频流格式。注意:rtsp格式的视频流无法直接在web端进行播放,但是 rtmp格式的视频流可以,部分摄像头支持返回的 rtmp流可以播放,部分不支持,所以要根据实际的业务需求来进行选择,若是摄像头不支持返回可直接播放的 rtmp流,可以将返回的 rtsp格式的视频流经ffmpeg+nginx进行装换为rtmp。但是效率很低,一般不推荐使用。
6、参考海康开放 API 时要注意对应海康综合安防管理平台的版本,不同版本间的 API 几乎不可通用,下图举例 1.10 版本对应 V1.0 版本接口
8、近期所使用的海康综合管理平台升级,由最初使用的1.1.0 升级为1.5.1,因此项目上需要更改视频信息的api版本,海康平台Hikvision AI Cloud默认显示的API为高版本,且支持向下兼容,对应历史版本api在如下位置
9、为了更快捷的将接口返回的数据信息进行分析整理入库,提供了如下代码,
/* @Description: HkTest工具类补充代码 */
/**
* @Description: 数据处理
* @author: 作者
* @Param:
* @Return:
* @Date: 2021/2/3 14:52
*/
public static JSONArray checkData(String regionsPageList) {
com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(regionsPageList);
String code = jsonObject.getString("code");
if (StringUtils.isBlank(code) || !"0".equalsIgnoreCase(code)) {
return null;
}
com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");
if (ObjectUtil.isNull(data)) {
return null;
}
Integer total = data.getInteger("total");
JSONArray list = data.getJSONArray("list");
System.out.println("所有的list 的长度" + list.size());
return list;
}
/**
* @Description: 数据处理
* @author: 作者
* @Param:
* @Return:
* @Date: 2021/2/3 14:52
*/
public static JSONArray checkCameraData(String cameraList) {
com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(cameraList);
if (ObjectUtil.isNull(jsonObject)) {
return null;
}
String code = jsonObject.getString("code");
if (StringUtils.isBlank(code) || !"0".equalsIgnoreCase(code)) {
return null;
}
com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");
if (ObjectUtil.isNull(data)) {
return null;
}
Integer total = data.getInteger("total");
JSONArray list = data.getJSONArray("list");
System.out.println("所有的 list 的长度" + list.size() +"total:" + total +" list 的长度 和 total是否相等:"+ (total==list.size()) );
return list;
}
10、数据提取封装到对应的数据表实现入库存储
package cn.stylefeng.guns.base;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.modular.led.entity.LedCameraArea;
import cn.stylefeng.guns.modular.led.entity.LedCameraAreaCameras;
import cn.stylefeng.guns.modular.led.service.LedCameraAreaCamerasService;
import cn.stylefeng.guns.modular.led.service.LedCameraAreaService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Orange
* @version 1.0
* @Description:此类用于获得数据并解析入库
* @date 2021/2/3 14:04
*
* 根节点:"root000000"
*/
public class HkOptainData {
private Map getmap(List<LedCameraArea> allAreas) {
Map<String, LedCameraArea> map = new HashMap<>();
for (LedCameraArea allArea : allAreas) {
map.put(allArea.getIndexCode(), allArea);
}
return map;
}
private void digui(List<LedCameraArea> ledCameraAreas, Map<String, LedCameraArea> noleaf, Map<String, String> map) {
for (LedCameraArea ledCameraArea : ledCameraAreas) {
StringBuffer namebuffer = new StringBuffer();
StringBuffer codebuffer = new StringBuffer();
diguitree(ledCameraArea, noleaf, map, namebuffer, codebuffer, ledCameraArea.getIndexCode());
}
}
private void diguitree(LedCameraArea ledCameraArea, Map<String, LedCameraArea> noleaf, Map<String, String> map, StringBuffer namebuffer, StringBuffer codebuffer, String key) {
String pid = ledCameraArea.getParentIndexCode();
namebuffer.append(ledCameraArea.getName()).append(",");
codebuffer.append(ledCameraArea.getIndexCode()).append(",");
LedCameraArea ledCameraArea1 = noleaf.get(pid);
if (ObjectUtil.isNotNull(ledCameraArea1)) {
String parentIndexCode = ledCameraArea1.getParentIndexCode();
if (!"root000000".equalsIgnoreCase(parentIndexCode)) {
diguitree(ledCameraArea1, noleaf, map, namebuffer, codebuffer, key);
} else {
map.put(key, codebuffer.toString() + ";" + namebuffer.toString());
}
} else {
map.put(key, codebuffer.toString() + ";" + namebuffer.toString());
System.out.println(pid);
}
}
@Autowired
LedCameraAreaService ledCameraAreaService;
@Autowired
LedCameraAreaCamerasService ledCameraAreaCamerasService;
@Test
public void testHkRegions() {
//初始化根节点
String[] roots = new String[]{"root000000"};
String regionsPageList = HkTest.getRegionsPageList(roots, 1, 1000);
JSONArray objects = HkTest.checkData(regionsPageList);
if (CollectionUtils.isNotEmpty(objects)) {
for (Object object : objects) {
com.alibaba.fastjson.JSONObject jsonObject = (com.alibaba.fastjson.JSONObject) object;
LedCameraArea entity = JSONObject.parseObject(jsonObject.toJSONString(), LedCameraArea.class);
ledCameraAreaService.add(entity);
}
}
}
@Test
public void testHkCameros() {
QueryWrapper<LedCameraArea> wrapper = new QueryWrapper<>();
wrapper.eq("leaf", 1);//叶子节点筛选
List<LedCameraArea> ledCameraAreas = ledCameraAreaService.selectLedCameraArea(wrapper);
QueryWrapper<LedCameraArea> allwrapper = new QueryWrapper<>();
List<LedCameraArea> allAreas = ledCameraAreaService.selectLedCameraArea(allwrapper);
Map<String, LedCameraArea> noleaf = getmap(allAreas);
//先把相应的 tree 弄出来
for (LedCameraArea ledCameraArea : allAreas) {
noleaf.put(ledCameraArea.getIndexCode(), ledCameraArea);
}
Map<String, String> map = new HashMap<>();
digui(ledCameraAreas, noleaf, map);
//初始化计数器
int n=0;
for (LedCameraArea ledCameraArea : ledCameraAreas) {
String nameandcode = map.get(ledCameraArea.getIndexCode());
String namepath="";
String codepath="";
if (StringUtils.isNotBlank(nameandcode)) {
String[] split = nameandcode.split(";");
codepath=split[0];
namepath=split[1];
}
String name=ledCameraArea.getName();
String code=ledCameraArea.getExternalIndexCode();
Object camerasByRegionCode = HkTest.getCamerasByRegionCode(ledCameraArea.getIndexCode(), 1, 1000);
JSONArray objects = HkTest.checkCameraData((String) camerasByRegionCode);
if (ObjectUtil.isNull(objects)) {
continue;
}
n+=objects.size();
System.out.println(ledCameraArea.getName()+":"+ledCameraArea.getIndexCode()+";"+objects.size());
for (Object object : objects) {
com.alibaba.fastjson.JSONObject jsonObject = (com.alibaba.fastjson.JSONObject) object;
LedCameraAreaCameras entity = JSONObject.parseObject(jsonObject.toJSONString(), LedCameraAreaCameras.class);
entity.setRegionCode(code);
entity.setRegionName(name);
entity.setRegionPath(codepath);
entity.setRegionPathName(namepath);
ledCameraAreaCamerasService.add(entity);
}
}
System.out.println("总共多少个摄像头:"+ n +" 总共多少个区域 :"+ledCameraAreas.size());
}
}
11、实体类的创建可根据api返回的数据创建对应的属性,也可仅对部分可用数据进行封装
/*此处举例部分属性*/
@TableField("dept_id")
private Long deptId;
@TableField("indexCode")
private String indexCode;
@TableField("nodeType")
private String nodeType;
@TableField("name")
private String name;
@TableField("regionPath")
private String regionPath;
@TableField("parentIndexCode")
private String parentIndexCode;
@TableField("cascadeCode")
private String cascadeCode;
@TableField("cascadeType")
private String cascadeType;
@TableField("externalIndexCode")
private String externalIndexCode;
@TableField("available")
private boolean available;
@TableField("leaf")
private boolean leaf;
@TableField("catalogType")
private Long catalogType;
12、平台版本升级后通过api所返回数据【json格式】内容变得更多,仅获取项目所需得内容即可
{
"code": "0",
"msg": "success",
"data": {
"total": 46,
"pageNo": 1,
"pageSize": 100,
"list": [{
"indexCode": "root000000",
"nodeType": 0,
"name": "根节点",
"regionPath": "@root000000@",
"parentIndexCode": "-1",
"cascadeType": 0,
"externalIndexCode": "370102",
"sort": 1,
"createTime": "2021-01-19T14:53:39.136+08:00",
"updateTime": "2021-01-22T09:55:17.075+08:00",
"regionCode": "",
"available": true,
"leaf": false,
"catalogType": 10,
"cascadeCode": "0"
}]
}
}
13、最后感谢一位CSDN博主,对我所提问题的耐心解答,这是他的博文地址,欢迎大家前去拜读!
https://blog.csdn.net/weixin_43716343/article/details/108054096#comments_13802942
14、话外:高版本的综合安防平台可以获得支持web端直接播放得rtmp格式视频流,如果返回的rtmp 视频流可以在第三方工具,如 VLC 上播放但是在页面使用 video.js 无法进行播放,可以考虑是否是视频码流所造成的影响。可以通过调用接口时指定码流格式 【0:为主码流】【1:为子码流】
最后
以上就是尊敬音响为你收集整理的对接海康综合安防管理平台经验总结的全部内容,希望文章能够帮你解决对接海康综合安防管理平台经验总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复