海康设备网络SDK对接——java


背景:由于工作问题,最近对接了海康的设备网络SDK,参考了SDK自带demo,还有一部分的网上博客,发现没有很全的,自己决定把自己开发的经验分享下

基本信息:

  JDK11

  springboot 2.5

  官网下载的SDK:CH-HCNetSDKV6.1.6.45_build20210302_win64

  对接的设备:人脸识别一体机(明眸设备——卡为中心、人为中心)

代码简介:

  

 

   hklib是存放win下SDK文件的

  custom下是核心代码,五个Service结尾的,分别是明眸卡为中心,明眸人脸为中心,设备登陆,设备订阅,设备SDK初始化,包含了人脸识别一体机基本操作,登陆,订阅,下发卡号,人脸,删除卡号人脸,刷卡刷脸事件上报。

  lib目录下为SDK的对接文件,参考jSDK目录中 CH-HCNetSDKV6.1.6.45_build20210302_win64\Demo示例\4- Java 开发示例\4-明眸门禁优化接口(以人为中心)\Test1\src\Test1 部分修改

SDK继承:StdCallLibrary改成 Libray,StdCallLibaray是win下使用,改过之后可以win、linux通用

public interface HCNetSDK extends Library

Demo中win32的都是只能win下使用,由于本人没有引入example.jar 所以直接删除了相关内容(主要涉及视屏流),我对接的设备不需要使用。

 

 

SDK加载方式修改:

HCNetSDK INSTANCE = Native.load(OSUtils.getLoadLibrary(), HCNetSDK.class);

内部类代码全部继承:SdkStructure,重写一个getFiledOrder来解决空指针问题(不知道是不是只有我遇到的)

 public static class SdkStructure extends Structure {
        @Override
        protected  List<String> getFieldOrder(){
            List<String> fieldOrderList = new ArrayList<String>();
            for (Class<?> cls = getClass();
                 !cls.equals(SdkStructure.class);
                 cls = cls.getSuperclass()) {
                Field[] fields = cls.getDeclaredFields();
                int modifiers;
                for (Field field : fields) {
                    modifiers = field.getModifiers();
                    if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
                        continue;
                    }
                    fieldOrderList.add(field.getName());
                }
            }
            return fieldOrderList;
        }
    }
/**
	 * 获取库文件
	 * 区分win、linux
	 * @return
	 */
	public static String getLoadLibrary() {
		if (isChecking()) {
			return null;
		}
		String loadLibrary = "";
		String library = "";
		String osPrefix = getOsPrefix();
		if(osPrefix.toLowerCase().startsWith("win32-x86")) {
			loadLibrary = System.getProperty("user.dir")  + File.separator+ "hklib" + File.separator;
			library = "HCNetSDK.dll";
		} else if(osPrefix.toLowerCase().startsWith("win32-amd64") ) {
			loadLibrary = System.getProperty("user.dir")  + File.separator+ "hklib" + File.separator;
			library = "HCNetSDK.dll";
		} else if(osPrefix.toLowerCase().startsWith("linux-i386")) {
			loadLibrary = "/lib/";
			library = "libhcnetsdk.so";
		}else if(osPrefix.toLowerCase().startsWith("linux-amd64")) {
			loadLibrary = "/lib/";
			library = "libhcnetsdk.so";
		}
		
		log.info("[HK] ================= Load library Path :{} ==================", loadLibrary + library);
		return loadLibrary + library;
	}

  

设备登陆

public static String login(String m_sDeviceIP, String m_sUsername,String m_sPassword){
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息

        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_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_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.valueOf("8000");
        m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是
        m_strLoginInfo.write();

        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息
        int loginHandler = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (loginHandler == -1) {
            int errorCode = hCNetSDK.NET_DVR_GetLastError();
            IntByReference errorInt = new IntByReference(errorCode);
            log.error("[HK] login fail errorCode:{}, errMsg:{}", errorCode, hCNetSDK.NET_DVR_GetErrorMsg(errorInt));
            return hCNetSDK.NET_DVR_GetErrorMsg(errorInt);
        } else {
            loginHandleMap.put(m_sDeviceIP,loginHandler);
            int iCharEncodeType = m_strDeviceInfo.byCharEncodeType;
            encodeMap.put(loginHandler,iCharEncodeType);
            log.info("[HK] login success iCharEncodeType:{}", iCharEncodeType);
            log.info("[HK] login map:{}", loginHandleMap);
            return "success";
        }
    }
View Code

设备订阅+回调事件

static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    final HCNetSDK.FMSGCallBack_V31 callback = new HKEventCallback();
    //key: loginHandler  value: subscribeHandler
    public static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
    private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


    public String startSubscribe(int loginHandler) {
        String msg = "success";
        boolean b = hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(callback, null);
        if (!b) {
            log.error("订阅失败");
        }
        HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
        m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
        m_strAlarmInfo.byLevel = 1;
        m_strAlarmInfo.byAlarmInfoType = 1;
        // m_strAlarmInfo.byDeployType = 0;// 客户端布防
        m_strAlarmInfo.byDeployType = 1;// 服务端布防
        m_strAlarmInfo.write();
        int subscribeHandler = hCNetSDK.NET_DVR_SetupAlarmChan_V41(loginHandler, m_strAlarmInfo);
        if (subscribeHandler == -1) {
            int errorCode = hCNetSDK.NET_DVR_GetLastError();
            msg = hCNetSDK.NET_DVR_GetErrorMsg(new IntByReference(errorCode));
            log.error("布防失败");
        } else {
            map.put(loginHandler, subscribeHandler);
        }
        return msg;
    }

    public void stopSubscribe(Integer subscribeHandler) {
        if (subscribeHandler == null) {
            log.error("stopSubscribe null");
            return;
        }

        boolean b = hCNetSDK.NET_DVR_CloseAlarmChan_V30(subscribeHandler);
        //防止数据紊乱(重复登陆等)导致两个map内容不一致,采用循环删除
        for (var loginHandler : map.keySet()) {
            if (subscribeHandler.intValue() == map.get(loginHandler)) {
                map.remove(loginHandler);
            }
        }
        if (!b) {
            log.error("撤防失败");
        }

    }


    /**
     * 2021-06-09
     */
    class HKEventCallback implements HCNetSDK.FMSGCallBack_V31 {

        @Override
        public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
            int loginHandler = pAlarmer.lUserID;
            Integer subscribeHandler = map.get(loginHandler);
            if (subscribeHandler == null) {
                log.error("上报句柄不存在");
            }
            // lCommand是传的报警类型
            switch (lCommand) {
                case HCNetSDK.COMM_ALARM_ACS: // 门禁主机报警信息
                    try {
                        processAlarmEvent(pAlarmer, pAlarmInfo);
                    } catch (Exception e) {
                        log.error("门禁事件异常 error:{}", ExceptionUtils.getStackTrace(e));
                    }
                    break;
                default:
                    break;
            }
            return true;
        }
    }

    private void processAlarmEvent(HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo) {
        String[] sIP = new String[2];
        sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
        //报警设备ip
        String ip = sIP[0];
        String eventTime = null;
        String employeeId = null;
        String cardNo = null;
        Byte cardType = null;

        HCNetSDK.NET_DVR_ACS_ALARM_INFO strACSInfo = new HCNetSDK.NET_DVR_ACS_ALARM_INFO();
        strACSInfo.write();
        Pointer pACSInfo = strACSInfo.getPointer();
        pACSInfo.write(0, pAlarmInfo.getByteArray(0, strACSInfo.size()), 0, strACSInfo.size());
        strACSInfo.read();
        //主类型 5 事件上报
        if (strACSInfo.dwMajor != 5) {
            return;
        }
        cardNo = new String(strACSInfo.struAcsEventInfo.byCardNo).trim();
        cardType = strACSInfo.struAcsEventInfo.byCardType;
        byte timeType = strACSInfo.byTimeType;
        HCNetSDK.NET_DVR_TIME struTime = strACSInfo.struTime;
        LocalDateTime uplaodTime = LocalDateTime.of(struTime.dwYear, struTime.dwMonth, struTime.dwDay, struTime.dwHour, struTime.dwMinute, struTime.dwSecond);


        //以人为中心设备
        if (strACSInfo.byAcsEventInfoExtend == 1) {
            var test = new HCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND();
            test.write();
            var pAcsEventInfoExtend = test.getPointer();
            pAcsEventInfoExtend.write(0, strACSInfo.pAcsEventInfoExtend.getByteArray(0, test.size()), 0, test.size());
            test.read();
            employeeId = new String(test.byEmployeeNo).trim();
        }

        if (timeType == 0) {
            eventTime = dtf.format(uplaodTime);
        } else if (timeType == 1) {
            var zonedDateTime = uplaodTime.atZone(ZoneId.from(ZoneOffset.UTC)).withZoneSameInstant(ZoneId.systemDefault());
            eventTime = dtf.format(zonedDateTime);
        } else {
            log.error("上报时间不正确");
        }
        if (strACSInfo.dwPicDataLen > 0) {
            long offset = 0;
            ByteBuffer buffers = strACSInfo.pPicData.getByteBuffer(offset, strACSInfo.dwPicDataLen);
            byte[] bytes = new byte[strACSInfo.dwPicDataLen];
            buffers.rewind();
            buffers.get(bytes);
            log.info("有图片");
        }

        // 刷卡成功
        if (strACSInfo.dwMinor == 1) {
            log.info("刷卡成功");
            //刷脸成功
        } else if (strACSInfo.dwMinor == 75) {
            log.info("刷脸成功");
            //刷脸失败
        } else if (strACSInfo.dwMinor == 76) {
            log.info("刷脸失败");
        } else {
        }

    }
View Code

完整代码见地址:

 https://github.com/theWangs/haikang/tree/master


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM