一、下载海康SDK
去海康官网下载最新SDK及window、linux环境的动态库(.dll/.so)
(注意linux环境,该动态库文件设置目录设备可读写权限)
其中SDK我重命名了一下,同时为了兼容windows和linux版本,两版本SDK都继承自定义的接口IHkSdkInterface
import com.xxxx.hkcamera.alarm.HCNetSDK;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
/**
* 为了海康win、Linux的整合写的接口类
*/
public interface IHkSdkInterface extends Library {
// 初始化sdk
boolean NET_DVR_Init();
// // 设置连接时间与重连时间
boolean NET_DVR_SetConnectTime(int i, int i1);
// boolean NET_DVR_SetReconnect(int i, boolean b);
// // 登录接口
int NET_DVR_Login_V40(HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo, HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo);
// NativeLong NET_DVR_Login_V30(String sDVRIP, short wDVRPort, String sUserName, String sPassword, HCNetSDKLinux.NET_DVR_DEVICEINFO_V30 lpDeviceInfo);
// 获取错误号
int NET_DVR_GetLastError();
// // 回调服务
boolean NET_DVR_SetDVRMessageCallBack_V31(HCNetSDK.FMSGCallBack_V31 fMessageCallBack, Pointer pUser);
// boolean NET_DVR_SetDVRMessageCallBack_V30(HCNetSDKLinux.FMSGCallBack fMessageCallBack, Pointer pUser);
// // 布防监控
int NET_DVR_SetupAlarmChan_V41(int lUserID,HCNetSDK.NET_DVR_SETUPALARM_PARAM alarmChanV41);
// NativeLong NET_DVR_SetupAlarmChan_V30(NativeLong lUserID);
// // 布防撤销
boolean NET_DVR_CloseAlarmChan_V30(int handle);
// boolean NET_DVR_CloseAlarmChan_V30(NativeLong lAlarmHandle);
// // 退出
boolean NET_DVR_Logout(int userId);
// boolean NET_DVR_Logout(NativeLong lUserID);
// 释放sdk
boolean NET_DVR_Cleanup();
boolean NET_DVR_RemoteControl(int lUserID, int dwCommand, Pointer lpInBuffer, int dwInBufferSize);
boolean NET_DVR_SetReconnect(int i, boolean b);
boolean NET_DVR_SetSDKLocalCfg(int i, Pointer pointer);
}
二、SDK的接入
/**
* @Description: TODO()
* @Date: 2021-04-06 11:05
*/
@Slf4j
public class HCNetAlarm {
static IHkSdkInterface hCNetSDK ;
//设备登录信息
HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
//设备信息
HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
//已登录设备的IP地址
String m_sDeviceIP;
//设备用户名
String m_sUsername;
//设备密码
String m_sPassword;
int lAlarmHandle;//报警布防句柄
int lUserID;//用户句柄
//报警回调函数实现
public static FMSGCallBack_V31 fMSFCallBack_V31;
private IAlarmService handler;//图片抓拍回调函数实现
/**资源初始化
* @return
*/
public int initDevice(String Path) {
//初始化
if (OSinfo.isLinux()) {
// Linux 版本 海康sdk布防
// hcNetSDK = HCNetSDKLinux.INSTANCE;
hCNetSDK=(HCNetSDKLinux) Native.loadLibrary(Path, HCNetSDKLinux.class);
} else {
// windows 注册登录、布防撤防
hCNetSDK= (HCNetSDKI) Native.loadLibrary(Path, HCNetSDKI.class);
}
if (!hCNetSDK.NET_DVR_Init()) {
//初始化失败
log.info("初始化失败");
return 1;
}
return 0;
}
/**
* 注销
* @param lUserID
*/
public void logout(int lUserID){
//注销
hCNetSDK.NET_DVR_Logout(lUserID);
//释放SDK资源
hCNetSDK.NET_DVR_Cleanup();
}
/**
* 设备注册
* @param ip
* @param name
* @param password
* @param
* @return
*/
public int deviceRegister(int lUserID, String ip , String name, String password, String port){
//注册之前先注销已注册的用户
if (lUserID > -1) {
//先注销
hCNetSDK.NET_DVR_Logout(lUserID);
lUserID = -1;
}
//ip地址
m_sDeviceIP = ip;
m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
//设备用户名
m_sUsername = name;
m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());
//设备密码
m_sPassword = password;
m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());
m_strLoginInfo.wPort = (short) Integer.parseInt(port);
//是否异步登录:0- 否,1- 是
m_strLoginInfo.bUseAsynLogin = false;
m_strLoginInfo.write();
lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
if (lUserID == -1) {
log.info("注册失败,错误号:" , hCNetSDK.NET_DVR_GetLastError());
return -1;
} else {
HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struGeneralCfg = new HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
//控制JSON透传报警数据和图片是否分离,0-不分离,1-分离(分离后走COMM_ISAPI_ALARM回调返回)
struGeneralCfg.byAlarmJsonPictureSeparate = 1;
struGeneralCfg.write();
if (!hCNetSDK.NET_DVR_SetSDKLocalCfg(17, struGeneralCfg.getPointer())) {
return -1;
}
//设置连接时间与重连时间
hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
hCNetSDK.NET_DVR_SetReconnect(10000, true);
log.info("注册成功 userID:{}",lUserID);
return lUserID;
}
}
/**
* 建立布防上传通道
*/
public int setupAlarmChan(int lUserID,int lAlarmHandle,IAlarmService handler) {
log.info("开始布防");
this.handler = handler;
if (lUserID == -1) {
log.info("请先注册");
return lUserID;
}
if (lAlarmHandle < 0) {
//尚未布防,需要布防
if (fMSFCallBack_V31 == null) {
fMSFCallBack_V31 = new FMSGCallBack_V31();
Pointer pUser = null;
if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(fMSFCallBack_V31, pUser)) {
log.info("设置回调函数失败!", hCNetSDK.NET_DVR_GetLastError());
}
}
HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
//智能交通布防优先级:0- 一等级(高),1- 二等级(中),2- 三等级(低)
m_strAlarmInfo.byLevel = 1;
//智能交通报警信息上传类型:0- 老报警信息(NET_DVR_PLATE_RESULT), 1- 新报警信息(NET_ITS_PLATE_RESULT)
m_strAlarmInfo.byAlarmInfoType = 1;
//布防类型(仅针对门禁主机、人证设备):0-客户端布防(会断网续传),1-实时布防(只上传实时数据)
m_strAlarmInfo.byDeployType = 1;
m_strAlarmInfo.write();
lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID, m_strAlarmInfo);
if (lAlarmHandle == -1) {
log.info("布防失败,错误码=========={}", hCNetSDK.NET_DVR_GetLastError());
//注销 释放sdk资源
logout(lUserID);
return lAlarmHandle;
} else {
log.info("布防成功");
return lAlarmHandle;
}
}
return lAlarmHandle;
}
/**
* 报警撤防
*/
public int closeAlarmChan(int lAlarmHandle) {
if (lAlarmHandle > -1) {
if (hCNetSDK.NET_DVR_CloseAlarmChan_V30(lAlarmHandle)) {
log.info("撤防成功");
lAlarmHandle = -1;
return lAlarmHandle;
}
return lAlarmHandle;
}
return lAlarmHandle;
}
public class FMSGCallBack_V31 implements HCNetSDK.FMSGCallBack_V31 {
//报警信息回调函数
//lCommand 上传消息类型 pAlarmer 报警设备信息 pAlarmInfo 报警信息 dwBufLen 报警信息缓存大小 pUser 用户数据
@Override
public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
alarmDataHandle(lCommand, pAlarmer, pAlarmInfo, dwBufLen, pUser);
return true;
}
/**
* 接收设备上传的报警信息
* @param lCommand 上传消息类型
* @param pAlarmer 报警设备信息
* @param pAlarmInfo 报警信息
* @param dwBufLen 报警信息缓存大小
* @param pUser 用户数据
* @return
*/
public void alarmDataHandle(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
String sAlarmType = new String();
String[] newRow = new String[3];
//报警时间
Date today = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String[] sIP = new String[2];
sAlarmType = new String("lCommand=0x") + Integer.toHexString(lCommand);
String serialNumber;
//lCommand是传的报警类型
switch (lCommand) {
//客流统计
case HCNetSDK.COMM_ALARM_PDC:
HCNetSDK.NET_DVR_PDC_ALRAM_INFO strPDCResult = new HCNetSDK.NET_DVR_PDC_ALRAM_INFO();
strPDCResult.write();
Pointer pPDCInfo = strPDCResult.getPointer();
pPDCInfo.write(0, pAlarmInfo.getByteArray(0, strPDCResult.size()), 0, strPDCResult.size());
strPDCResult.read();
if (strPDCResult.byMode == 0) {
strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATFRAME.class);
sAlarmType = sAlarmType + ":客流量统计,进入人数:" + strPDCResult.dwEnterNum + ",离开人数:" + strPDCResult.dwLeaveNum +
", byMode:" + strPDCResult.byMode + ", dwRelativeTime:" + strPDCResult.uStatModeParam.struStatFrame.dwRelativeTime +
", dwAbsTime:" + strPDCResult.uStatModeParam.struStatFrame.dwAbsTime;
}
if (strPDCResult.byMode == 1) {
strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATTIME.class);
String strtmStart = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwYear) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMonth) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwDay) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwHour) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMinute) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwSecond);
String strtmEnd = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwYear) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMonth) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwDay) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwHour) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMinute) +
String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwSecond);
sAlarmType = sAlarmType + ":客流量统计,进入人数:" + strPDCResult.dwEnterNum + ",离开人数:" + strPDCResult.dwLeaveNum +
", byMode:" + strPDCResult.byMode + ", tmStart:" + strtmStart + ",tmEnd :" + strtmEnd;
}
newRow[0] = dateFormat.format(today);
//报警类型
newRow[1] = sAlarmType;
//报警设备IP地址
sIP = new String(strPDCResult.struDevInfo.struDevIP.sIpV4).split("\0", 2);
newRow[2] = sIP[0];
log.info("客流信息数量======{}", Arrays.toString(newRow));
break;
case HCNetSDK.COMM_UPLOAD_FACESNAP_RESULT:
//实时人脸抓拍上传
HCNetSDK.NET_VCA_FACESNAP_RESULT strFaceSnapInfo = new HCNetSDK.NET_VCA_FACESNAP_RESULT();
strFaceSnapInfo.write();
Pointer pFaceSnapInfo = strFaceSnapInfo.getPointer();
pFaceSnapInfo.write(0, pAlarmInfo.getByteArray(0, strFaceSnapInfo.size()), 0, strFaceSnapInfo.size());
strFaceSnapInfo.read();
sAlarmType = sAlarmType + ":人脸抓拍上传[人脸评分:" + strFaceSnapInfo.dwFaceScore + ",年龄:" + strFaceSnapInfo.struFeature.byAge + ",性别:" + strFaceSnapInfo.struFeature.bySex + "]";
log.info(sAlarmType);
newRow[0] = dateFormat.format(today);
//报警类型
newRow[1] = sAlarmType;
//报警设备IP地址
sIP = new String(strFaceSnapInfo.struDevInfo.struDevIP.sIpV4).split("\0", 2);
newRow[2] = sIP[0];
log.info("人脸抓拍========{}",Arrays.toString(newRow));
//获取设备系列号
serialNumber = new String(pAlarmer.sSerialNumber, StandardCharsets.UTF_8).trim();
int length = strFaceSnapInfo.dwFacePicLen;//抓拍图片长度
int dwBackgroundPicLen=strFaceSnapInfo.dwBackgroundPicLen;//背景图长度
byte[] bytess = strFaceSnapInfo.pBuffer1.getByteArray(0, length);//抓拍图片的bytes
byte[] bytess2 = strFaceSnapInfo.pBuffer2.getByteArray(0, dwBackgroundPicLen);//抓拍图片的bytes
//SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); //设置日期格式
Long time = System.currentTimeMillis(); // new Date()为获取当前系统时间
handler.onFaceSnaped(sIP[0], bytess,bytess2, length, time,serialNumber,strFaceSnapInfo.struFeature.byAge,strFaceSnapInfo.struFeature.bySex);
break;
case HCNetSDK.COMM_ISAPI_ALARM:
//ISAPI协议报警信息
handler.ISAPIAlarm(lCommand, pAlarmInfo, pAlarmer);
log.info("------ISAPI协议报警信息-------");
break;
default:
newRow[0] = dateFormat.format(today);
//报警类型
newRow[1] = sAlarmType;
//报警设备IP地址
sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
newRow[2] = sIP[0];
// log.info("其他报警信息=========={}",Arrays.toString(newRow));
break;
}
}
}
/**
* 设备状态
// * @param camera
* @return
*/
public Boolean onlineState(int lUserID,String ip , String name, String password, String port){
HCNetAlarm hcNetAlarm = new HCNetAlarm();
int row = hcNetAlarm.initDevice("");
if (row == 1){
log.info("初始化失败");
}
hcNetAlarm.deviceRegister(lUserID,ip,name,password,port);
//检查设备在线状态
log.info("设备信息========={}",hcNetAlarm.m_strDeviceInfo.struDeviceV30);
boolean isOnLine = hCNetSDK.NET_DVR_RemoteControl(lUserID,20005,null,0);
log.info("checkDeviceOnLine---isOnLine============{}",isOnLine);
return isOnLine;
}
}
其中handler为业务处理类
* @program: monitoralarm
* @description: TODO
*/
public interface IAlarmService {
/**
* liburl路径
* @return
*/
String getPath();
/**
*
* @param ip 用来标识哪个摄像头
* @param bytes 图片字节流
* @param length 字节流长度
* @param time 时间戳(毫秒)
* 设备序列号
*/
void onFaceSnaped(String ip, byte[] bytes, byte[] bytes2,int length, long time,String serialNumber,Byte age,Byte sex);
/**
* 根据ISAPI报警返回的json设置抓拍信息
* @param jsonData
* @param serialNumber
*/
void setSnapImgByJsonInfo(String jsonData, byte[] bytes, String serialNumber);
void ISAPIAlarm(int lCommand, Pointer pAlarmInfo, HCNetSDK.NET_DVR_ALARMER pAlarmer);
}
@Override
public void ISAPIAlarm(int lCommand, Pointer pAlarmInfo, HCNetSDK.NET_DVR_ALARMER pAlarmer) {
String sAlarmType = new String();
String[] newRow = new String[3];
String[] sIP = new String[2];
sAlarmType = new String("lCommand=0x") + Integer.toHexString(lCommand);
Date today = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
HCNetSDK.NET_DVR_ALARM_ISAPI_INFO struEventISAPI = new HCNetSDK.NET_DVR_ALARM_ISAPI_INFO();
struEventISAPI.write();
Pointer pEventISAPI = struEventISAPI.getPointer();
pEventISAPI.write(0, pAlarmInfo.getByteArray(0, struEventISAPI.size()), 0, struEventISAPI.size());
struEventISAPI.read();
sAlarmType = sAlarmType + ":ISAPI协议报警信息, 数据格式:" + struEventISAPI.byDataType +
", 图片个数:" + struEventISAPI.byPicturesNumber;
newRow[0] = dateFormat.format(today);
//报警类型
newRow[1] = sAlarmType;
//报警设备IP地址
sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
newRow[2] = sIP[0];
SimpleDateFormat sf1 = new SimpleDateFormat("yyyyMMddHHmmss");
String curTime = sf1.format(new Date());
//获取设备系列号
String serialNumber = new String(pAlarmer.sSerialNumber, StandardCharsets.UTF_8).trim();
String jsonData = "";
try {
byte[] jsonbytes = new byte[struEventISAPI.dwAlarmDataLen];
jsonbytes = struEventISAPI.pAlarmData.getByteArray(0, struEventISAPI.dwAlarmDataLen);
jsonData = new String(jsonbytes, "UTF-8");
log.info("============抓拍json数据==========:" + jsonData);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
for (int i = 0; i < struEventISAPI.byPicturesNumber; i++) {
HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA struPicData = new HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA();
struPicData.write();
Pointer pPicData = struPicData.getPointer();
pPicData.write(0, struEventISAPI.pPicPackData.getByteArray(i * struPicData.size(), struPicData.size()), 0, struPicData.size());
struPicData.read();
try {
long offset = 0;
byte[] buffer = new byte[struPicData.dwPicLen];
buffer = struPicData.pPicData.getByteArray(offset, struPicData.dwPicLen);
//设置抓拍信息
setSnapImgByJsonInfo(jsonData, buffer, serialNumber);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
}
//设置车辆信息
@Transactional
public void setVehicle(JSONObject vehicle, SnapVehicle snapVehicle) {
JSONArray property = vehicle.getJSONArray("Property");
log.info("=============抓拍车辆特征信息=========-" + property);
for (int i = 0; i < property.size(); i++) {
JSONObject jsonObject = property.getJSONObject(i);
if ("plateType".equals(jsonObject.getString("description"))) {
//设置车牌类型
snapVehicle.setPlateType(jsonObject.getString("value"));
}
if ("plateColor".equals(jsonObject.getString("description"))) {
//设置车牌颜色
snapVehicle.setPlateColor(jsonObject.getString("value"));
}
if ("vehicleType".equals(jsonObject.getString("description"))) {
//设置车辆类型
snapVehicle.setVehicleType(jsonObject.getString("value"));
}
if ("vehicleColor".equals(jsonObject.getString("description"))) {
//设置车辆颜色
snapVehicle.setVehicleColor(jsonObject.getString("value"));
}
if ("plateNo".equals(jsonObject.getString("description"))) {
//设置车牌号码
snapVehicle.setPlateNo(jsonObject.getString("value"));
snapVehicle.setCreateTime(new Date());
snapVehicleMapper.insert(snapVehicle);
}
}
}
@Override
public void setSnapImgByJsonInfo(String jsonData, byte[] bytes, String serialNumber) {
String base64Url = Base64Util.encode(bytes);
Device device = deviceService.getOne(new QueryWrapper<Device>().lambda().eq(Device::getSerialNum, serialNumber));
JSONObject jsonObject = JSONObject.parseObject(jsonData);
if (jsonObject != null) {
JSONArray captureResult = jsonObject.getJSONArray("CaptureResult");
if (captureResult != null) {
JSONObject object = captureResult.getJSONObject(0);
JSONObject human = object.getJSONObject("Human");
JSONObject vehicle = object.getJSONObject("Vehicle");
if (vehicle != null) {
FileDto fileDto = new FileDto(null, base64Url, null, true, "TOLLGATE_SNAP", null, null);
FileInfoVo fileInfoVo = null;
try {
fileInfoVo = fileInfoService.uploadFile(fileDto);
} catch (Exception e) {
e.printStackTrace();
}
if (fileInfoVo != null) {
SnapVehicle snapVehicle = new SnapVehicle();
snapVehicle.setId(StringUtils.getUUID());
snapVehicle.setShootTime(new Date());
final String url = fileInfoVo.getUrl();
final String localUrl = url.replace(localWebServerUrl, webServerUrl);
snapVehicle.setImageUrl(localUrl);
snapVehicle.setSerialNumber(serialNumber);
if (device != null) {
snapVehicle.setCommunityCode(device.getCommunity());
snapVehicle.setSnapshotSite(device.getInstallationLoc());
}
//设置车辆特征信息
setVehicle(vehicle, snapVehicle);
}
}
if (human != null) {
onFaceSnaped(null,bytes,null,0,new Date().getTime(),serialNumber,null,null);
}
}
}
}```
# 三、设备接入使用
需要设备的IP、端口、账号、密码
其中path配置到配置文件中
![image.png](https://ucc.alicdn.com/pic/developer-ecology/d670dbc13832418fa245df26346b6d9b.png)
HCNetAlarm hcNetAlarm = new HCNetAlarm();
hcNetAlarm.lAlarmHandle = -1;
int row = hcNetAlarm.initDevice(alarmService.getPath());
if (row == 1){
log.info("初始化失败");
}
//设置连接超时时间与重连功能
hcNetAlarm.hCNetSDK.NET_DVR_SetConnectTime(2000,1);
hcNetAlarm.hCNetSDK.NET_DVR_SetReconnect(10000,true);
//注册
hcNetAlarm.deviceRegister(hcNetAlarm.lUserID,CAMERA_IP,CAMERA_UN,CAMERA_PD,CAMERA_PORT);
//设置报警回调函数
//建立报警上传通道(启用布防)
//布防参数
hcNetAlarm.setupAlarmChan(hcNetAlarm.lUserID,hcNetAlarm.lAlarmHandle,alarmService);
//todo: hcNetAlarm.lUserID,hcNetAlarm.lAlarmHandle 存储到数据库
}