前言

  本来一个很简单的SDK接口对接,折腾了好久;总结下原因有:

  1. 海康的SDK底层使用C++写的,我不熟悉C++;
  2. 海康Java源码示例写的是一个Swing桌面应用,我需要的是嵌入到web项目;
  3. 海康《设备网络SDK使用手册》中的示例是用C++写的;并且会出现使用手册和Java源码示例版本不匹配的情况(用手册版本高于Java源码示例版)  

我的需求

  1. 统计一个出入口的实时进出客流量;即将摄像头产生的数据 抓取出来保存到业务数据库
  2. SDK版本:6.0.2.35

准备工作

  1. 海康摄像头iDS-2CD681XYZUV-ABD/C;并已经现场安装成功;
  2. 海康的SDK,下载地址(win64):https://www.hikvision.com/cn/download_more_570.html;后面用到的全部文档和参考源码全部在SDK文档中

代码处理

  1. 将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文件夹名不能修改。
  2. 将路径:Demo示例\4- Java 开发示例\2-报警布防监听\AlarmJavaDemo\src\alarmjavademo下的HCNetSDK类植入到项目中;
  3. 修改HCNetSDK类中的HCNetSDK加载的路径,否则会报无法加载HCNetSDK.dll错误;
    1. HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary("HCNetSDK",
    2. HCNetSDK.class);
    3. 改成
    4. String path=(HCNetSDK.class.getResource("/").getPath()).replaceAll("%20", " ").substring(1).replace("/", "\\")+"HCNetSDK.dll";
    5. HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary(path,
    6. HCNetSDK.class); 
  4. 写MemberFlowUploadService类,实现数据的抓取(见业务源码1);代码逻辑说明,可参考《设备网络SDK使用手册》-编程导引-客流量功模块的示例说明
  5. 写MemberFlowUPloadCallBackImpl类,即回调函数(见业务源码2);回调函数的实现,我参考书hideSDK中的Demo示例\4- Java 开发示例\2-报警布防监听\AlarmJavaDemo\src\alarmjavademo下的AlarmJavaDemoView类
  6. 控制台结果输出    
  1. 进入回调了
  2. sAlarmType---》lCommand=4355:客流量统计,进入人数:78,离开人数:83, byMode:0, dwRelativeTime:1298991096, dwAbsTime:1298991096
  3. 进入回调了
  4. sAlarmType---》lCommand=4355:客流量统计,进入人数:0,离开人数:1, byMode:1, tmStart:20190522163123,tmEnd :20190522163200
  5. 进入回调了
  6. sAlarmType---》lCommand=4355:客流量统计,进入人数:79,离开人数:83, byMode:0, dwRelativeTime:1298991115, dwAbsTime:1298991115  

 

源码分析

源码1:MemberFlowUploadService类

  1. package com.hs.api.service.haikang.meberflow;
  2. import org.springframework.stereotype.Service;
  3. import java.util.Timer;
  4. import java.util.TimerTask;
  5. @Service
  6. public class MemberFlowUploadService{
  7. static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
  8. static HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息
  9. static HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息
  10. static String m_sDeviceIP = "192.168.1.X";//已登录设备的IP地址
  11. static String m_sUsername = "XXX";//设备用户名
  12. static String m_sPassword = "XXXXXX";//设备密码
  13. static short m_sPort = 8000;//端口号
  14.  
  15. public void initMemberFlowUpload(int remainMinuteTime){
  16. // 初始化
  17. hCNetSDK.NET_DVR_Init();
  18. //设置连接时间与重连时间
  19. hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
  20. hCNetSDK.NET_DVR_SetReconnect(10000, true);
  21. // 注册设备-登录参数,包括设备地址、登录用户、密码等
  22. m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
  23. System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
  24. m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
  25. System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());
  26. m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
  27. System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());
  28. m_strLoginInfo.wPort = m_sPort;
  29. m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是
  30. m_strLoginInfo.write();
  31. //设备信息, 输出参数
  32. int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo,m_strDeviceInfo);
  33. System.out.println("lUserID.size-->" + lUserID);
  34. if(lUserID< 0){
  35. System.out.println("hCNetSDK.NET_DVR_Login_V30()"+"\n" +hCNetSDK.NET_DVR_GetErrorMsg(null));
  36. hCNetSDK.NET_DVR_Cleanup();
  37. return;
  38. }
  39. //设置报警回调函数
  40. hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(new MemberFlowUPloadCallBackImpl(),null );
  41. //启用布防-其他报警布防参数不需要设置,不支持
  42. HCNetSDK.NET_DVR_SETUPALARM_PARAM lpSetupParam = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
  43. lpSetupParam.dwSize = 0;
  44. int lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID,lpSetupParam);
  45. if (lAlarmHandle< 0)
  46. {
  47. System.out.println("NET_DVR_SetupAlarmChan_V41 error, %d\n"+hCNetSDK.NET_DVR_GetLastError());
  48. hCNetSDK.NET_DVR_Logout(lUserID);
  49. hCNetSDK.NET_DVR_Cleanup();
  50. return;
  51. }
  52. //等待过程中,如果设备上传报警信息,在报警回调函数里面接收和处理报警信息
  53. Timer timer = new Timer();// 实例化Timer类
  54. timer.schedule(new TimerTask() {
  55. public void run() {
  56. //撤销布防上传通道
  57. if (! hCNetSDK.NET_DVR_CloseAlarmChan_V30(lAlarmHandle))
  58. {
  59. System.out.println("! hCNetSDK.NET_DVR_CloseAlarmChan_V31(lAlarmHandle)\n"+ hCNetSDK.NET_DVR_GetLastError() +"\n" +hCNetSDK.NET_DVR_GetErrorMsg(null) );
  60. hCNetSDK.NET_DVR_Logout(lUserID);
  61. hCNetSDK. NET_DVR_Cleanup();
  62. return;
  63. }
  64. //注销用户
  65. hCNetSDK.NET_DVR_Logout(lUserID);
  66. //释放SDK资源
  67. hCNetSDK.NET_DVR_Cleanup();
  68. this.cancel();
  69. System.gc();//主动回收垃圾
  70. }
  71. }, remainMinuteTime * 60 * 1000 );// 这里毫秒
  72. }
  73. }

 

 源码2:MemberFlowUPloadCallBackImpl类

  1. package com.hs.api.service.haikang.meberflow;
  2. import com.hs.dao.entity.saichang.statistics.StatisticsMemberInOut;
  3. import com.hs.dao.service.impl.saichang.statistics.StatisticsMemberInOutService;
  4. import com.sun.jna.Pointer;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import java.sql.Timestamp;
  7. import java.text.DateFormat;
  8. import java.text.SimpleDateFormat;
  9. import java.util.Date;
  10. import java.util.logging.Level;
  11. import java.util.logging.Logger;
  12. public class MemberFlowUPloadCallBackImpl implements HCNetSDK.FMSGCallBack_V31 {
  13. @Autowired
  14. private StatisticsMemberInOutService statisticsMemberInOutService;
  15. @Override
  16. public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
  17. System.out.println("进入回调了");
  18. try {
  19. String sAlarmType = new String();
  20. //报警时间
  21. Date today = new Date();
  22. DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
  23. String[] sIP = new String[2];
  24. sAlarmType = new String("lCommand=") + lCommand;
  25. //lCommand是传的报警类型
  26. HCNetSDK.NET_DVR_PDC_ALRAM_INFO strPDCResult = new HCNetSDK.NET_DVR_PDC_ALRAM_INFO();
  27. strPDCResult.write();
  28. Pointer pPDCInfo = strPDCResult.getPointer();
  29. pPDCInfo.write(0, pAlarmInfo.getByteArray(0, strPDCResult.size()), 0, strPDCResult.size());
  30. strPDCResult.read();
  31. if (strPDCResult.byMode == 0) {
  32. strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATFRAME.class);
  33. sAlarmType = sAlarmType + ":客流量统计,进入人数:" + strPDCResult.dwEnterNum + ",离开人数:" + strPDCResult.dwLeaveNum +
  34. ", byMode:" + strPDCResult.byMode + ", dwRelativeTime:" + strPDCResult.uStatModeParam.struStatFrame.dwRelativeTime +
  35. ", dwAbsTime:" + strPDCResult.uStatModeParam.struStatFrame.dwAbsTime;
  36. }
  37. if (strPDCResult.byMode == 1) {
  38. strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATTIME.class);
  39. //在这里实现数据的保存等业务逻辑,下面注释的代码是SDK提供的参考示例
  40.  
  41. /* String strtmStart = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwYear) +
  42. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMonth) +
  43. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwDay) +
  44. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwHour) +
  45. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMinute) +
  46. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwSecond);
  47. String strtmEnd = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwYear) +
  48. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMonth) +
  49. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwDay) +
  50. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwHour) +
  51. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMinute) +
  52. String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwSecond);
  53. sAlarmType = sAlarmType + ":客流量统计,进入人数:" + strPDCResult.dwEnterNum + ",离开人数:" + strPDCResult.dwLeaveNum +
  54. ", byMode:" + strPDCResult.byMode + ", tmStart:" + strtmStart + ",tmEnd :" + strtmEnd;*/
  55. }
  56. System.out.println("sAlarmType---》" +sAlarmType);
  57. //报警类型
  58. //报警设备IP地址
  59. sIP = new String(strPDCResult.struDevInfo.struDevIP.sIpV4).split("\0", 2);
  60. return true;
  61. } catch (Exception ex) {
  62. Logger.getLogger(MemberFlowUPloadCallBackImpl.class.getName()).log(Level.SEVERE, null, ex);
  63. return false;
  64. }
  65. }
  66. }

 其他问题解决

  1. 项目开发没有问题,最后用maven打包项目时,HCNetSDK的加载出了问题,分析错误日志,发现是因为maven打包时进行了test,无法找到HCNetSDK,只要打包时不test就可以了;
  2. windows server 2008 在jdk1.8.0_131下可以加载到HCNetSDK.dll(这里JDK默认在C:\Program Files );  在更新的JDK版本中就不行(这里JDK默认在C:\Program Files (x86))

版权声明:本文为wobuchifanqie原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/wobuchifanqie/p/10909700.html