赞
踩
以下内容都是自己最近做的真实项目总结的经验,一些需要注意的地方我在下面都有做说明,希望可以给刚接触大华sdk调用的兄弟一些建议,少走一些弯路!另外大华的文档写的也很详细,都可以对着看!
1、官网下载大华sdk(注意区分不同平台对应版本,如果项目最终需要部署到LINUX服务器,建议直接下载LINUX版本的sdk,不要折腾windows版的),下载地址:
https://support.dahuatech.com/tools/sdkExploit/24
2、SDK下载好之后,用解压缩工具解压到本地目录,然后用idea打开,可以看到sdk的完整代码结构,主要jar包在libs目录下,技术文档在doc目录下,方法调用demo在src/main/java/com/netsdk/demo下,我们需要调用的示例都可以在这个目录下找到:
3、使用idea的package命令或install命令,直接将整个sdk打成jar包并导入本地maven仓库,有的人会把NetSDKLib下面的代码都复制出来,然后粘贴到自己的项目里,非常不建议这样做,因为要导入的东西实在太多,可能最后自己都放弃了,最好的办法就是直接把sdk打包好扔进maven仓库,需要哪个方法直接调用,添加到maven仓库命令如下(需要根据自己的jar包地址做修改,JNI和大华本身的sdk都要单独打包好放入maven仓库!!):
mvn install:install-file -Dfile=D:\java\apache-maven-3.6.3\linuxJar\netsdk-1.0-demo.jar -DgroupId=com.dahua.netsdk -DartifactId=dahua-netsdk-linux -Dversion=1.0.0 -Dpackaging=jar -DgeneratePom=true
4、在自己的项目pom文件中引入大华sdk相关依赖:
<!-- <!– 这是windows版本的demo–>--> <!-- <dependency>--> <!-- <groupId>com.dahua.netsdk</groupId>--> <!-- <artifactId>dahua-netsdk-windows</artifactId>--> <!-- <version>1.0.0</version>--> <!-- </dependency>--> <!-- <dependency>--> <!-- <groupId>com.dahua.netsdk</groupId>--> <!-- <artifactId>dahua-netsdk-jni</artifactId>--> <!-- <version>1.0.0</version>--> <!-- </dependency>--> <!-- 这是Linux版本的demo--> <dependency> <groupId>com.dahua.netsdk</groupId> <artifactId>dahua-netsdk-linux</artifactId> <version>1.0.0</version> </dependency> <!--1.1.0是linux的jni包 --> <dependency> <groupId>com.dahua.netsdk</groupId> <artifactId>dahua-netsdk-jni</artifactId> <version>1.1.0</version> </dependency> <!-- 大华摄像头sdk end -->
1、官方文档好像没有关于人数统计的流程图,临时借用一下智能订阅的流程图,步骤都是差不多的,先初始化-然后登录-向设备订阅事件-回调函数中进行业务逻辑处理等
2、SDK初始化、登录、订阅等功能集成到工具类:
public class SdkUtils { private final static Logger logger = LoggerFactory.getLogger(DySmsHelper.class); public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE; public static NetSDKLib configsdk = NetSDKLib.CONFIG_INSTANCE; // 设备信息 public static NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex(); // 登陆句柄 public static NetSDKLib.LLong m_hLoginHandle = new NetSDKLib.LLong(0); // 监听服务句柄 public static NetSDKLib.LLong mServerHandler = new NetSDKLib.LLong(0); private static boolean bInit = false; private static boolean bLogopen = false; /** * 初始化SDK * * @param disConnect * @param haveReConnect * @return */ public static boolean init(NetSDKLib.fDisConnect disConnect, NetSDKLib.fHaveReConnect haveReConnect) { bInit = netsdk.CLIENT_Init(disConnect, null); if (!bInit) { logger.info("初始化SDK失败"); return false; } //打开日志,可选 NetSDKLib.LOG_SET_PRINT_INFO setLog = new NetSDKLib.LOG_SET_PRINT_INFO(); File path = new File("./sdklog/"); if (!path.exists()) { path.mkdir(); } String logPath = path.getAbsoluteFile().getParent() + "\\sdklog\\" + ToolKits.getDate() + ".log"; setLog.nPrintStrategy = 0; setLog.bSetFilePath = 1; System.arraycopy(logPath.getBytes(), 0, setLog.szLogFilePath, 0, logPath.getBytes().length); System.out.println(logPath); setLog.bSetPrintStrategy = 1; bLogopen = netsdk.CLIENT_LogOpen(setLog); if (!bLogopen) { System.err.println("Failed to open NetSDK log"); } // 设置断线重连回调接口,设置过断线重连成功回调函数后,当设备出现断线情况,SDK内部会自动进行重连操作 netsdk.CLIENT_SetAutoReconnect(haveReConnect, null); //设置登录超时时间和尝试次数,可选 int waitTime = 5000; //登录请求响应超时时间设置为5S int tryTimes = 1; //登录时尝试建立链接1次 netsdk.CLIENT_SetConnectTime(waitTime, tryTimes); // 设置更多网络参数,NET_PARAM的nWaittime,nConnectTryNum成员与CLIENT_SetConnectTime // 接口设置的登录设备超时时间和尝试次数意义相同,可选 NetSDKLib.NET_PARAM netParam = new NetSDKLib.NET_PARAM(); netParam.nConnectTime = 10000; // 登录时尝试建立链接的超时时间 netParam.nGetConnInfoTime = 3000; // 设置子连接的超时时间 netParam.nGetDevInfoTime = 3000;//获取设备信息超时时间,为0默认1000ms netsdk.CLIENT_SetNetworkParam(netParam); return true; } /** * 清除环境 */ public static void cleanup() { if (bLogopen) { netsdk.CLIENT_LogClose(); } if (bInit) { netsdk.CLIENT_Cleanup(); } } /** * 登录设备 */ public static boolean login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) { //IntByReference nError = new IntByReference(0); //入参 NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY(); pstInParam.nPort = m_nPort; pstInParam.szIP = m_strIp.getBytes(); pstInParam.szPassword = m_strPassword.getBytes(); pstInParam.szUserName = m_strUser.getBytes(); //出参 NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY(); pstOutParam.stuDeviceInfo = m_stDeviceInfo; //m_hLoginHandle = netsdk.CLIENT_LoginEx2(m_strIp, m_nPort, m_strUser, m_strPassword, 0, null, m_stDeviceInfo, nError); m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam); if (m_hLoginHandle.longValue() == 0) { System.err.printf("Login Device[%s] Port[%d]Failed. %s\n", m_strIp, m_nPort, ToolKits.getErrorCodePrint()); } else { System.out.println("Login Success [ " + m_strIp + " ]"); } return m_hLoginHandle.longValue() == 0 ? false : true; } /** * 登录 * * @param ip * @param port * @param userName * @param password * @param deviceIDs * @return */ public static NetSDKLib.LLong login(String ip, int port, String userName, String password, String deviceIDs) { //入参 NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY(); Pointer deviceId = ToolKits.GetGBKStringToPointer(deviceIDs); pstInParam.nPort = port; pstInParam.szIP = ip.getBytes(); pstInParam.szPassword = password.getBytes(); pstInParam.szUserName = userName.getBytes(); pstInParam.emSpecCap = NetSDKLib.EM_LOGIN_SPAC_CAP_TYPE.EM_LOGIN_SPEC_CAP_SERVER_CONN; // 主动注册登录 pstInParam.pCapParam = deviceId; // 出参 NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY(); try { m_stDeviceInfo.sSerialNumber = deviceIDs.getBytes("GBK"); } catch (Exception e) { logger.error("转换设备ID异常,deviceID={}", deviceIDs, e); } pstOutParam.stuDeviceInfo = m_stDeviceInfo; m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam); long value = m_hLoginHandle.longValue(); if (value == 0) { logger.error("登录失败,ip={},port={},error={}", ip, port, ToolKits.getErrorCodePrint()); } else { logger.info("设备登录成功。ip={},port={}", ip, port); // 登录成功后像物联网平台上报设备状态变化 // reportDeviceStatus(deviceIDs, "online"); } return m_hLoginHandle; } /** * 登出设备 */ public static boolean logout() { if (m_hLoginHandle.longValue() == 0) { return false; } boolean bRet = netsdk.CLIENT_Logout(m_hLoginHandle); if (bRet) { m_hLoginHandle.setValue(0); } return bRet; } // Attach 订阅 人数统计事件 public static boolean attachVideoStatSummary(int channel, NetSDKLib.fVideoStatSumCallBack fVideoStatSumCallBack) { NetSDKLib.NET_IN_ATTACH_VIDEOSTAT_SUM inParam = new NetSDKLib.NET_IN_ATTACH_VIDEOSTAT_SUM(); inParam.nChannel = channel; inParam.cbVideoStatSum = fVideoStatSumCallBack; NetSDKLib.NET_OUT_ATTACH_VIDEOSTAT_SUM outParam = new NetSDKLib.NET_OUT_ATTACH_VIDEOSTAT_SUM(); NetSDKLib.LLong m_hAttachHandle = LoginModule.netsdk.CLIENT_AttachVideoStatSummary(m_hLoginHandle, inParam, outParam, 5000); //打开日志,可选 NetSDKLib.LOG_SET_PRINT_INFO setLog = new NetSDKLib.LOG_SET_PRINT_INFO(); File path = new File("./sdklog/"); if (!path.exists()) { path.mkdir(); } String logPath = path.getAbsoluteFile().getParent() + "\\sdklog\\" + ToolKits.getDate() + ".log"; setLog.nPrintStrategy = 0; setLog.bSetFilePath = 1; System.arraycopy(logPath.getBytes(), 0, setLog.szLogFilePath, 0, logPath.getBytes().length); System.out.println(logPath); setLog.bSetPrintStrategy = 1; bLogopen = netsdk.CLIENT_LogOpen(setLog); if (!bLogopen) { System.err.println("Failed to open NetSDK log"); } if (m_hAttachHandle.longValue() == 0) { System.err.printf("Attach Failed!LastError = %s\n", ToolKits.getErrorCodePrint()); return false; } System.out.printf("Attach Succeed at Channel %d ! AttachHandle: %d. Wait Device Notify Information\n", channel, m_hAttachHandle.longValue()); return true; } }
3、初始化、登录、订阅部分详细代码:
public class ServiceTask extends TimerTask { private static Logger logger = LoggerFactory.getLogger(ServiceTask.class); // 设备信息 public static ConcurrentMap<String, DeviceInfo> deviceMap = new ConcurrentHashMap<>(); // 设备断线通知回调 private static DisConnectCallBack disConnectCB = new DisConnectCallBack(); // 网络连接恢复 private static HaveReConnectCallBack haveReConnectCB = new HaveReConnectCallBack(); // 设备是否登录 // public static Map<String, Boolean> deviceLoginMap = new HashMap<>(); public static Map<String, FHumanNumberStatisticCallBack> deviceLoginMap = new HashMap<>(); // 客流量统计订阅回调 // private FHumanNumberStatisticCallBack humanNumberStatisticCB = FHumanNumberStatisticCallBack.getInstance(); private static boolean bInit = false; private static boolean bLogin = false; @Resource private IDeviceInfoService deviceInfoService; @Override public void run() { //从设备表查询设备信息 QueryWrapper<DeviceInfo> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc("channel"); List<DeviceInfo> deviceInfoList = deviceInfoService.list(queryWrapper); Map<Integer,DeviceInfo> deviceInfoMap = deviceInfoList.stream().collect(Collectors. toMap(DeviceInfo::getChannel, Function.identity()));//按通道号分组 long currentTimeStamp = System.currentTimeMillis(); //先初始化 if(!bInit){ bInit = SdkUtils.init(disConnectCB, haveReConnectCB); } if (!bInit) { logger.info("初始化SDK失败"); bInit = false; }else{ if(null!=deviceInfoList&&deviceInfoList.size()>0){ for(DeviceInfo deviceInfo :deviceInfoList){ Boolean reconnectStatus = deviceInfo.getReconnectStatus(); String deviceId = deviceInfo.getDeviceId(); // Boolean logined = deviceLoginMap.getOrDefault(deviceId, false); FHumanNumberStatisticCallBack logined = deviceLoginMap.get(deviceId); //当map的连接状态为false时才重新登录 if(null==logined){ //登录摄像头 Boolean isLogin = SdkUtils.login(deviceInfo.getDeviceIp(), deviceInfo.getPort(), deviceInfo.getUserName(), deviceInfo.getPassword()); if(!isLogin){ logger.error("登录摄像头失败,deviceID={},ip={},port={}", deviceInfo.getDeviceId(), deviceInfo.getDeviceIp(), deviceInfo.getPort()); // 登录失败后将摄像头登录状态保存在map中 deviceLoginMap.put(deviceId, null); deviceInfo.setReconnectStatus(false); }else{ logger.info("登录摄像头成功,deviceID={},ip={},port={}", deviceInfo.getDeviceId(), deviceInfo.getDeviceIp(), deviceInfo.getPort()); // // 登录成功后将摄像头登录状态保存在map中 // deviceLoginMap.put(deviceId, true); // deviceInfo.setReconnectStatus(true); // 登录成功后开启人数统计订阅事件 Integer channel = deviceInfo.getChannel(); FHumanNumberStatisticCallBack humanNumberStatisticCB = new FHumanNumberStatisticCallBack(); // humanNumberStatisticCB.setDeviceId(deviceInfo.getDeviceId()); humanNumberStatisticCB.setDeviceInfoMap(deviceInfoMap); // 登录成功后将摄像头登录状态保存在map中 deviceLoginMap.put(deviceId, humanNumberStatisticCB); deviceInfo.setReconnectStatus(true); Boolean isAttached = SdkUtils.attachVideoStatSummary(channel,humanNumberStatisticCB); if (!isAttached) { logger.error("开启人数统计订阅事件失败,deviceInfo={}", deviceInfo); continue; }else{ logger.info("开启人数统计订阅事件成功,deviceInfo={}", deviceInfo); } } } } //批量更新当前连接状态 deviceInfoService.updateBatchById(deviceInfoList); } } logger.info("结束执行摄像头登录的定时器任务,耗时{}ms",System.currentTimeMillis()-currentTimeStamp); } }
4、回调函数内的业务逻辑处理(根据自己业务需要编写):
public class FHumanNumberStatisticCallBack implements NetSDKLib.fVideoStatSumCallBack { private static IHumanNumberStatisticService humanNumberStatisticService; // 推送消息记录map public static Map<String, HumanNumberStatistic> humanNumberStatisticMap = new HashMap<>(); public Map<Integer, DeviceInfo> deviceInfoMap = new HashMap<>(); @Autowired public void setHumanNumberStatisticService(IHumanNumberStatisticService humanNumberStatisticService) { FHumanNumberStatisticCallBack.humanNumberStatisticService = humanNumberStatisticService; } private static FHumanNumberStatisticCallBack instance = new FHumanNumberStatisticCallBack(); public static FHumanNumberStatisticCallBack getInstance() { return instance; } private EventTaskCommonQueue eventTaskQueue = new EventTaskCommonQueue(); public FHumanNumberStatisticCallBack() { eventTaskQueue.init(); } // // private String deviceId; @Override public void invoke(NetSDKLib.LLong lAttachHandle, NetSDKLib.NET_VIDEOSTAT_SUMMARY stVideoState, int dwBufLen, Pointer dwUser) { SummaryInfo summaryInfo = new SummaryInfo( stVideoState.nChannelID, stVideoState.stuTime.toStringTime(), stVideoState.stuEnteredSubtotal.nToday, stVideoState.stuEnteredSubtotal.nHour, stVideoState.stuEnteredSubtotal.nTotal, stVideoState.stuExitedSubtotal.nToday, stVideoState.stuExitedSubtotal.nHour, stVideoState.stuExitedSubtotal.nTotal, stVideoState.nInsidePeopleNum, stVideoState.emRuleType); String szRuleName = ""; try { szRuleName = new String(stVideoState.szRuleName,"gb2312"); }catch(Exception e){ e.printStackTrace(); } System.out.printf("Channel[%d] GetTime[%s]\n" + "People In Information[Total[%d] Hour[%d] Today[%d]]\n" + "People Out Information[Total[%d] Hour[%d] Today[%d]]\n"+ "nInsidePeopleNum[%d]\n"+ "emRuleType[%d]\n"+ "szRuleName[%s]\n"+ "nRetExitManNum[%d]\n", summaryInfo.nChannelID, summaryInfo.eventTime, summaryInfo.enteredTotal, summaryInfo.enteredHour, summaryInfo.enteredToday, summaryInfo.exitedTotal, summaryInfo.exitedHour, summaryInfo.exitedToday , stVideoState.nInsidePeopleNum , stVideoState.emRuleType ,szRuleName , stVideoState.nRetExitManNum); DeviceInfo deviceInfo = deviceInfoMap.get(summaryInfo.nChannelID); if(deviceInfo==null){ System.out.println("summaryInfo.nChannelID="+(summaryInfo.nChannelID)+",未匹配到设备"); return; } System.out.println("nChannelID="+(summaryInfo.nChannelID)+",deviceInfo="+deviceInfo); //保存推送数据 HumanNumberStatistic humanNumberStatistic = new HumanNumberStatistic(); humanNumberStatistic.setDeviceId(deviceInfo.getDeviceId()); humanNumberStatistic.setChannel(summaryInfo.nChannelID); humanNumberStatistic.setEventTime(summaryInfo.eventTime); humanNumberStatistic.setEnteredTotal(summaryInfo.enteredTotal); humanNumberStatistic.setEnteredHour(summaryInfo.enteredHour); humanNumberStatistic.setEnteredToday(summaryInfo.enteredToday); humanNumberStatistic.setExitedToday(summaryInfo.exitedToday); humanNumberStatistic.setExitedHour(summaryInfo.exitedHour); humanNumberStatistic.setExitedTotal(summaryInfo.exitedTotal); humanNumberStatistic.setNInsidePeopleNum(summaryInfo.nInsidePeopleNum); humanNumberStatistic.setEmRuleType(summaryInfo.emRuleType); humanNumberStatistic.setDeviceType(deviceInfo.getDeviceType()); //根据设备id查询当前窗口预设等待时长 humanNumberStatistic.setWaitTimeAverage(humanNumberStatisticService.findWaitTimeAverage(deviceInfo.getDeviceId())); //双目摄像头,不记录区域内人数统计这条记录 if(deviceInfo.getDeviceType()==2&&(summaryInfo.enteredTotal==0&&summaryInfo.enteredHour==0&&summaryInfo.enteredToday==0 &&summaryInfo.exitedTotal==0&&summaryInfo.exitedHour==0&&summaryInfo.exitedToday==0)){ ; }else{ humanNumberStatisticMap.put(deviceInfo.getDeviceId(),humanNumberStatistic); } public Map<Integer, DeviceInfo> getDeviceInfoMap() { return deviceInfoMap; } public void setDeviceInfoMap(Map<Integer, DeviceInfo> deviceInfoMap) { this.deviceInfoMap = deviceInfoMap; } }
1、首先就是开头讲到的,如果服务器是linux,千万一开始就别浪费太多时间在windows版本的sdk上,到最后部署的时候会发现linux版本的sdk和windows版还是有些不一样的地方的,windows版本中如果调用的是demo里的方法,有可能在linux的sdk中找不到!
2、sdk的通道号是从0开始的,如果项目对接的是录像机,就要看下通道号是不是和sdk的对的上,应该是要加一才能和sdk对的上的!!
3、demo里给出的字段不全,需要哪些字段可以在NetSDKLib java类里面仔细找,用到哪个自己在summaryInfo里添加!
4、项目完整代码可以移步我的资源里下载,有问题大家一起讨论!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。