1. 程式人生 > 其它 >海康裝置網路SDK對接——java

海康裝置網路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

完整程式碼見地址: