赞
踩
目录
设备网络SDK是基于设备私有网络通信协议开发的,为嵌入式网络硬盘录像机、NVR、网络摄像机、网络球机、视频服务器、解码器、报警主机、网络存储等产品服务的配套模块,用于远程访问和控制设备软件的二次开发。
图像预览, 文件回放和下载, 云台控制, 布防/撤防, 语音对讲, 日志管理, 解码卡, 远程升级, 远程重启/关闭, 格式化硬盘, 参数配置(系统配置, 通道配置, 串口配置, 报警配置, 用户配置), 多路解码器, 智能设备功能和获取设备能力集等。
以java为例
由于我司提供的设备网络SDK是封装的动态链接库(Windows的dll或者Linux的so),各种开发语言对接SDK,都是通过加载动态库链接,调用动态库中的接口实现功能模块对接,因此,设备网络SDK的对接不区分开发语言,而且对接的流程和对应的接口都是通用的,各种语言调用动态库的方式有所不同。本文重点介绍java开发语言如何对接设备网络SDK。目前我司提供的java语言开发的demo是通过JNA的方式调用动态链接库中的接口,JNA(Java Native Access)框架是SUN公司主导开发的开源java框架,是建立在JNI的基础上的一个框架,JNA框架提供了一组java工具类用于在运行期间动态访问动态链接库(native library:如Window的dll、Linux的so),实现在java语言中调用C/C++语言封装的接口,java开发人员只需要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射,而不需要编写任何Native/JNI代码,大大降低了Java调用动态链接库的开发难度。相比于JNI的方式,JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成。JNA调用C/C++的过程大致如下:
以
SpringBoot
项目为例,海康SDK版本为6.1.9.47,JNA版本为3.0.9,在windows环境使用Intellij IDEA 2022.2.3开发
-
- <dependency>
- <groupId>com.sun.jna</groupId>
- <artifactId>jna</artifactId>
- <version>3.0.9</version>
- </dependency>
-
-
- <dependency>
- <groupId>com.alibaba.fastjson2</groupId>
- <artifactId>fastjson2</artifactId>
- <version>2.0.20</version>
- </dependency>
-
-
server.port
一般的,我们希望在程序启动的时候就初始化sdk。
ApplicationRunner
作为初始化入口,当程序启动成功后,将执行 Runner 做初始化ApplicationRunner
需要放在线程池中 ThreadPoolExecutor
,并添加try-catch处理hCNetSDK.NET_DVR_Init()
此方法,并可通过返回值为 true
或 false
判断初始化是否成功。-
- package com.ramble.hikvisionsdkintegration;
- import com.ramble.hikvisionsdkintegration.service.SdkInitService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.ApplicationArguments;
- import org.springframework.boot.ApplicationRunner;
- import org.springframework.stereotype.Component;
-
- @Component
- public class AppRunner implements ApplicationRunner {
- @Autowired
- private SdkInitService hksdkInitService;
- @Override
- public void run(ApplicationArguments args) throws Exception {
- hksdkInitService.initSdk();
- }
- }
-
-
依赖库文件
加载到运行时中,并没有真正的做初始化SDK的工作找
的操作是在 getLoadLibrary
方法中管理的,这里编写的代码需要和部署时候选择的部署方式对应,否则可能会出现在windows中开发正常,部署到linux 中就报异常的问题SdkInitService:
-
- package com.ramble.hikvisionsdkintegration.service;
- import com.ramble.hikvisionsdkintegration.sdklib.HCNetSDK;
- import com.ramble.hikvisionsdkintegration.task.InitSdkTask;
- import com.ramble.hikvisionsdkintegration.util.OSUtils;
- import com.sun.jna.Native;
- import com.sun.jna.Pointer;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import java.util.concurrent.ThreadPoolExecutor;
-
- @Slf4j
- @Component
- public class SdkInitService {
- public static HCNetSDK hCNetSDK = null;
- static FExceptionCallBack_Imp fExceptionCallBack;
- static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack {
- public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {
- System.out.println("异常事件类型:" + dwType);
- return;
- }
- }
- public SdkInitService() {
- if (hCNetSDK == null) {
- synchronized (HCNetSDK.class) {
- try {
- hCNetSDK = (HCNetSDK) Native.loadLibrary(OSUtils.getLoadLibrary(), HCNetSDK.class);
- } catch (Exception ex) {
- log.error("SdkInitService-init-hCNetSDK-error");
- }
- }
- }
- }
- @Autowired
- private ThreadPoolExecutor executor;
- public void initSdk() {
- log.info("HKSDKInitService-init-coming");
- executor.execute(new InitSdkTask());
- }
- }
-
OSUtils:
-
- package com.ramble.hikvisionsdkintegration.util;
- import com.sun.jna.Platform;
- import lombok.extern.slf4j.Slf4j;
- import java.io.File;
-
- @Slf4j
- public class OSUtils {
- // 获取操作平台信息
- public static String getOsPrefix() {
- String arch = System.getProperty("os.arch").toLowerCase();
- final String name = System.getProperty("os.name");
- String osPrefix;
- if (Platform.isWindows()) {
- if ("i386".equals(arch)) {
- arch = "x86";
- }
- osPrefix = "win32-" + arch;
- } else if (Platform.isLinux()) {
- if ("x86".equals(arch)) {
- arch = "i386";
- } else if ("x86_64".equals(arch)) {
- arch = "amd64";
- }
- osPrefix = "linux-" + arch;
- } else {
- osPrefix = name.toLowerCase();
- if ("x86".equals(arch)) {
- arch = "i386";
- }
- if ("x86_64".equals(arch)) {
- arch = "amd64";
- }
- int space = osPrefix.indexOf(" ");
- if (space != -1) {
- osPrefix = osPrefix.substring(0, space);
- }
- osPrefix += "-" + arch;
- }
- return osPrefix;
- }
- public static String getOsName() {
- String osName = "";
- String osPrefix = getOsPrefix();
- if (osPrefix.toLowerCase().startsWith("win32-x86")
- || osPrefix.toLowerCase().startsWith("win32-amd64")) {
- osName = "win";
- } else if (osPrefix.toLowerCase().startsWith("linux-i386")
- || osPrefix.toLowerCase().startsWith("linux-amd64")) {
- osName = "linux";
- }
- return osName;
- }
- /**
- * 获取库文件
- * 区分win、linux
- *
- * @return
- */
- public static String getLoadLibrary() {
- if (isChecking()) {
- return null;
- }
- String userDir = System.getProperty("user.dir");
- log.info("getLoadLibrary-userDir={}", userDir);
- String loadLibrary = "";
- String library = "";
- String osPrefix = getOsPrefix();
- if (osPrefix.toLowerCase().startsWith("win32-x86")) {
- loadLibrary = System.getProperty("user.dir") + File.separator + "sdk" + File.separator + "hklibwin32" + File.separator;
- library = "HCNetSDK.dll";
- } else if (osPrefix.toLowerCase().startsWith("win32-amd64")) {
- loadLibrary = System.getProperty("user.dir") + File.separator + "sdk" + File.separator + "hklibwin64" + File.separator;
- library = "HCNetSDK.dll";
- } else if (osPrefix.toLowerCase().startsWith("linux-i386")) {
- //同 linux-amd64
- loadLibrary = "";
- library = "libhcnetsdk.so";
- } else if (osPrefix.toLowerCase().startsWith("linux-amd64")) {
- //方式一:使用系统默认的加载库路径,在系统的/usr/lib文件中加入你Java工程所需要使用的so文件,然后将HCNetSDKCom文件夹下的组件库也复制到/usr/lib目录,HCNetSDKCom文件夹中的组件库不要随意更换路径。CentOS 64位需拷贝到/usr/lib64下。
- //针对方式一,前缀就是绝对路径
- //loadLibrary = "/usr/lib64/lib/hkliblinux64/";
- //方式二:配置LD_LIBRARY_PATH环境变量加载库文件;配置/etc/ld.so.conf,加上你自己的Java工程所需要的so文件的路径
- //针对方式二,无需添加前缀,程序会从linux系统的so共享库中查找libhcnetsdk.so
- loadLibrary = "";
- library = "libhcnetsdk.so";
- }
- log.info("================= Load library Path :{} ==================", loadLibrary + library);
- return loadLibrary + library;
- }
- private static boolean checking = false;
- public static void setChecking() {
- checking = true;
- }
- public static void clearChecking() {
- checking = false;
- }
- public static boolean isChecking() {
- return checking;
- }
- }
-
-
InitSdkTask:
-
- package com.ramble.hikvisionsdkintegration.task;
- import com.ramble.hikvisionsdkintegration.sdklib.HCNetSDK;
- import com.ramble.hikvisionsdkintegration.service.SdkInitService;
- import com.ramble.hikvisionsdkintegration.util.OSUtils;
- import lombok.extern.slf4j.Slf4j;
- import java.util.Objects;
-
- @Slf4j
- public class InitSdkTask implements Runnable {
- /**
- * 装配 sdk 所需依赖
- */
- private static HCNetSDK hCNetSDK = SdkInitService.hCNetSDK;
- @Override
- public void run() {
- try {
- if (Objects.equals(OSUtils.getOsName(), "linux")) {
- log.info("InitSdk-is-linux");
- String userDir = System.getProperty("user.dir");
- log.info("InitSdk-userDir={}", userDir);
- String osPrefix = OSUtils.getOsPrefix();
- if (osPrefix.toLowerCase().startsWith("linux-i386")) {
- HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
- HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
- //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限
- //linux 下, 库加载参考:OSUtils.getLoadLibrary()
- String strPath1 = System.getProperty("user.dir") + "/hkliblinux32/libcrypto.so.1.1";
- String strPath2 = System.getProperty("user.dir") + "/hkliblinux32/libssl.so.1.1";
- System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
- ptrByteArray1.write();
- hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());
- System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
- ptrByteArray2.write();
- hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());
- //linux 下, 库加载参考:OSUtils.getLoadLibrary()
- String strPathCom = System.getProperty("user.dir") + "/hkliblinux32/HCNetSDKCom/";
- HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
- System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
- struComPath.write();
- hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
- } else if (osPrefix.toLowerCase().startsWith("linux-amd64")) {
- HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
- HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
- //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限
- //linux 下, 库加载参考:OSUtils.getLoadLibrary()
- String strPath1 = System.getProperty("user.dir") + "/hkliblinux64/libcrypto.so.1.1";
- String strPath2 = System.getProperty("user.dir") + "/hkliblinux64/libssl.so.1.1";
- System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
- ptrByteArray1.write();
- hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());
- System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
- ptrByteArray2.write();
- hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());
- String strPathCom = System.getProperty("user.dir") + "/hkliblinux64/HCNetSDKCom/";
- //linux 下, 库加载参考:OSUtils.getLoadLibrary()
- HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
- System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
- struComPath.write();
- hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
- } else {
- log.info("osPrefix={}", osPrefix);
- }
- }
- //初始化sdk
- boolean isOk = hCNetSDK.NET_DVR_Init();
- hCNetSDK.NET_DVR_SetConnectTime(10, 1);
- hCNetSDK.NET_DVR_SetReconnect(100, true);
- if (!isOk) {
- log.error("=================== InitSDK init fail ===================");
- } else {
- log.info("============== InitSDK init success ====================");
- }
- } catch (Exception e) {
- log.error("InitSDK-error,e={}", e.getMessage());
- e.printStackTrace();
- }
- }
- }
-
-
直接从官方示例代码中copy过来即可
-
- package com.ramble.hikvisionsdkintegration.controller;
- import com.alibaba.fastjson2.JSON;
- import com.ramble.hikvisionsdkintegration.dto.GlobalResponseEntity;
- import com.ramble.hikvisionsdkintegration.sdklib.HCNetSDK;
- import com.ramble.hikvisionsdkintegration.service.SdkInitService;
- import com.sun.jna.Memory;
- import com.sun.jna.Pointer;
- import com.sun.jna.ptr.IntByReference;
- import lombok.AllArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
-
- @Slf4j
- @AllArgsConstructor
- @RestController
- @RequestMapping("/test")
- public class TestController {
- private static String m_sDeviceIP = "192.168.1.142";
- private static String m_sUsername = "xxx";
- private static String m_sPassword = "xxx";
-
- /**
- * 获取sdk状态
- *
- * @return {@link GlobalResponseEntity}<{@link String}>
- * 返回值举例:{"success":true,"code":"000000","message":"request successfully",
- * "data":"{\"dwRes\":[0,0,0,0,0,0,0,0,0,0],\"dwTotalAlarmChanNum\":0,\"dwTotalBroadCastNum\":0,\"dwTotalFileSearchNum\":0,\"dwTotalFormatNum\":0,
- * \"dwTotalLogSearchNum\":0,\"dwTotalLoginNum\":1,\"dwTotalPlayBackNum\":0,\"dwTotalRealPlayNum\":0,\"dwTotalSerialNum\":0,\"dwTotalUpgradeNum\":0,
- * \"dwTotalVoiceComNum\":0,\"autoRead\":true,\"autoWrite\":true,\"pointer\":{\"size\":84,\"valid\":true}}"}
- */
-
- @GetMapping("/state")
- public GlobalResponseEntity<String> getSdkState() {
- //登录
- Integer userId = login();
- log.info("userId={}", userId);
- HCNetSDK.NET_DVR_SDKSTATE sdkState = new HCNetSDK.NET_DVR_SDKSTATE();
- //获取当前SDK状态信息
- boolean result = SdkInitService.hCNetSDK.NET_DVR_GetSDKState(sdkState);
- if (result) {
- sdkState.read();
- String s = JSON.toJSONString(sdkState);
- return GlobalResponseEntity.success(s);
- } else {
- int error = SdkInitService.hCNetSDK.NET_DVR_GetLastError();
- return GlobalResponseEntity.error("获取失败,错误码为:" + error);
- }
- }
-
-
- private Integer login() {
- 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 = SdkInitService.hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
- if (loginHandler == -1) {
- int errorCode = SdkInitService.hCNetSDK.NET_DVR_GetLastError();
- IntByReference errorInt = new IntByReference(errorCode);
- log.error("[HK] login fail errorCode:{}, errMsg:{}", errorCode, SdkInitService.hCNetSDK.NET_DVR_GetErrorMsg(errorInt));
- return null;
- } else {
- return loginHandler;
- }
- }
- }
-
-
所有厂家的所有版本sdk库文件均维护在项目源代码中,需要将linux库文件so文件拷贝到部署根目录,和jar文件同级
通过配置 LD_LIBRARY_PATH
环境变量加载库文件,打开系统的 /etc/profile
配置文件,在最后追加so库文件所在目录:
-
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/app/jars/hkliblinux64:/home/app/jars/hkliblinux64/HCNetSDKCom
-
如上所示:
● 32位就追加 hkliblinux32 目录,64位就追加 hkliblinux64 目录
● 不要忘记 HCNetSDKCom 目录也需要配置,因为里面也有so库文件。
执行source 命令,让配置生效:
-
- source /etc/profile
-
打开 /etc/ld.so.conf
配置文件,追加so库文件所在目录
-
- /home/app/jars/hkliblinux64
- /home/app/jars/hkliblinux64/HCNetSDKCom
-
如上所示:
● 32位就追加 hkliblinux32 目录,64位就追加 hkliblinux64 目录。
● 不要忘记 HCNetSDKCom 目录也需要配置,因为里面也有so库文件。
执行 ldconfig 命令,让配置生效:
-
- ldconfig
-
一般来说,可以在程序初始化SDK的时候添加日志,通过日志输出判断是否初始化成功。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。