項目總結25:海康威視SDK-Java二次開發-客流量分析
前言html
原本一個很簡單的SDK接口對接,折騰了很久;總結下緣由有:java
- 海康的SDK底層使用C++寫的,我不熟悉C++;
- 海康Java源碼示例寫的是一個Swing桌面應用,我須要的是嵌入到web項目;
- 海康《設備網絡SDK使用手冊》中的示例是用C++寫的;而且會出現使用手冊和Java源碼示例版本不匹配的狀況(用手冊版本高於Java源碼示例版)
個人需求web
- 統計一個出入口的實時進出客流量;即將攝像頭產生的數據 抓取出來保存到業務數據庫
- SDK版本:6.0.2.35
準備工做spring
- 海康攝像頭iDS-2CD681XYZUV-ABD/C;並已經現場安裝成功;
- 海康的SDK,下載地址(win64):https://www.hikvision.com/cn/download_more_570.html;後面用到的所有文檔和參考源碼所有在SDK文檔中
代碼處理sql
- 將SDK開發包【庫文件】裏的HCNetSDK.dll、HCCore.dll、PlayCtrl.dll、SuperRender.dll、AudioRender.dll、HCNetSDKCom文件夾、ssleay32.dll、libeay32.dll文件均要加載到程序裏面,【HCNetSDKCom文件夾】(包含裏面的功能組件dll庫文件)須要和HCNetSDK.dll、HCCore.dll一塊兒加載,放在同一個目錄下(個人事springboot項目,放在resources目錄下),且HCNetSDKCom文件夾名不能修改。
- 將路徑:Demo示例\4- Java 開發示例\2-報警佈防監聽\AlarmJavaDemo\src\alarmjavademo下的HCNetSDK類植入到項目中;
- 修改HCNetSDK類中的HCNetSDK加載的路徑,不然會報沒法加載HCNetSDK.dll錯誤;
HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary("HCNetSDK", HCNetSDK.class); 改爲 String path=(HCNetSDK.class.getResource("/").getPath()).replaceAll("%20", " ").substring(1).replace("/", "\\")+"HCNetSDK.dll"; HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary(path, HCNetSDK.class);
- 寫MemberFlowUploadService類,實現數據的抓取(見業務源碼1);代碼邏輯說明,可參考《設備網絡SDK使用手冊》-編程導引-客流量功模塊的示例說明
- 寫MemberFlowUPloadCallBackImpl類,即回調函數(見業務源碼2);回調函數的實現,我參考書hideSDK中的Demo示例\4- Java 開發示例\2-報警佈防監聽\AlarmJavaDemo\src\alarmjavademo下的AlarmJavaDemoView類
- 控制檯結果輸出
進入回調了 sAlarmType---》lCommand=4355:客流量統計,進入人數:78,離開人數:83, byMode:0, dwRelativeTime:1298991096, dwAbsTime:1298991096 進入回調了 sAlarmType---》lCommand=4355:客流量統計,進入人數:0,離開人數:1, byMode:1, tmStart:20190522163123,tmEnd :20190522163200 進入回調了 sAlarmType---》lCommand=4355:客流量統計,進入人數:79,離開人數:83, byMode:0, dwRelativeTime:1298991115, dwAbsTime:1298991115
源碼分析數據庫
源碼1:MemberFlowUploadService類編程
package com.hs.api.service.haikang.meberflow; import org.springframework.stereotype.Service; import java.util.Timer; import java.util.TimerTask; @Service public class MemberFlowUploadService{ static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE; static HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//設備登陸信息 static HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//設備信息 static String m_sDeviceIP = "192.168.1.X";//已登陸設備的IP地址 static String m_sUsername = "XXX";//設備用戶名 static String m_sPassword = "XXXXXX";//設備密碼 static short m_sPort = 8000;//端口號 public void initMemberFlowUpload(int remainMinuteTime){ // 初始化 hCNetSDK.NET_DVR_Init(); //設置鏈接時間與重連時間 hCNetSDK.NET_DVR_SetConnectTime(2000, 1); hCNetSDK.NET_DVR_SetReconnect(10000, true); // 註冊設備-登陸參數,包括設備地址、登陸用戶、密碼等 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 = m_sPort; m_strLoginInfo.bUseAsynLogin = false; //是否異步登陸:0- 否,1- 是 m_strLoginInfo.write(); //設備信息, 輸出參數 int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo,m_strDeviceInfo); System.out.println("lUserID.size-->" + lUserID); if(lUserID< 0){ System.out.println("hCNetSDK.NET_DVR_Login_V30()"+"\n" +hCNetSDK.NET_DVR_GetErrorMsg(null)); hCNetSDK.NET_DVR_Cleanup(); return; } //設置報警回調函數 hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(new MemberFlowUPloadCallBackImpl(),null ); //啓用佈防-其餘報警佈防參數不須要設置,不支持 HCNetSDK.NET_DVR_SETUPALARM_PARAM lpSetupParam = new HCNetSDK.NET_DVR_SETUPALARM_PARAM(); lpSetupParam.dwSize = 0; int lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID,lpSetupParam); if (lAlarmHandle< 0) { System.out.println("NET_DVR_SetupAlarmChan_V41 error, %d\n"+hCNetSDK.NET_DVR_GetLastError()); hCNetSDK.NET_DVR_Logout(lUserID); hCNetSDK.NET_DVR_Cleanup(); return; } //等待過程當中,若是設備上傳報警信息,在報警回調函數裏面接收和處理報警信息 Timer timer = new Timer();// 實例化Timer類 timer.schedule(new TimerTask() { public void run() { //撤銷佈防上傳通道 if (! hCNetSDK.NET_DVR_CloseAlarmChan_V30(lAlarmHandle)) { System.out.println("! hCNetSDK.NET_DVR_CloseAlarmChan_V31(lAlarmHandle)\n"+ hCNetSDK.NET_DVR_GetLastError() +"\n" +hCNetSDK.NET_DVR_GetErrorMsg(null) ); hCNetSDK.NET_DVR_Logout(lUserID); hCNetSDK. NET_DVR_Cleanup(); return; } //註銷用戶 hCNetSDK.NET_DVR_Logout(lUserID); //釋放SDK資源 hCNetSDK.NET_DVR_Cleanup(); this.cancel(); System.gc();//主動回收垃圾 } }, remainMinuteTime * 60 * 1000 );// 這裏毫秒 } }
源碼2:MemberFlowUPloadCallBackImpl類windows
package com.hs.api.service.haikang.meberflow; import com.hs.dao.entity.saichang.statistics.StatisticsMemberInOut; import com.hs.dao.service.impl.saichang.statistics.StatisticsMemberInOutService; import com.sun.jna.Pointer; import org.springframework.beans.factory.annotation.Autowired; import java.sql.Timestamp; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; public class MemberFlowUPloadCallBackImpl implements HCNetSDK.FMSGCallBack_V31 { @Autowired private StatisticsMemberInOutService statisticsMemberInOutService; @Override public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) { System.out.println("進入回調了"); try { String sAlarmType = new String(); //報警時間 Date today = new Date(); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String[] sIP = new String[2]; sAlarmType = new String("lCommand=") + lCommand; //lCommand是傳的報警類型 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); //在這裏實現數據的保存等業務邏輯,下面註釋的代碼是SDK提供的參考示例 /* 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;*/ } System.out.println("sAlarmType---》" +sAlarmType); //報警類型 //報警設備IP地址 sIP = new String(strPDCResult.struDevInfo.struDevIP.sIpV4).split("\0", 2); return true; } catch (Exception ex) { Logger.getLogger(MemberFlowUPloadCallBackImpl.class.getName()).log(Level.SEVERE, null, ex); return false; } } }
其餘問題解決api
- 項目開發沒有問題,最後用maven打包項目時,HCNetSDK的加載出了問題,分析錯誤日誌,發現是由於maven打包時進行了test,沒法找到HCNetSDK,只要打包時不test就能夠了;
- windows server 2008 在jdk1.8.0_131下能夠加載到HCNetSDK.dll(這裏JDK默認在C:\Program Files ); 在更新的JDK版本中就不行(這裏JDK默認在C:\Program Files (x86))