海康SDK对接记录

前言:

该篇文档为了记录使用海康摄像头中的人脸比对,使用Java语言对接海康SDK的过程,记录其中遇到的问题和处理办法。
开发环境、框架、运行环境:idea、JDK1.8、 SpringBoot、docker等。

1.下载相关资源

1.根据开发系统下载海康SDK

海康SDK的地址:https://open.hikvision.com/download/5cda567cf47ae80dd41a54b3?type=10
根据开发环境,选择SDK下载
注意:
1.SDK中包含C、python、Java等相关的代码例子;
2.win系统和Linux是不同的,它们的区别就是动态库文件不同
image.png
解压以后的样子:
image.png

2.使用手册

开发前,可以先阅读一下使用手册,里面的内容算是比较全。
image.png

3.海康的ClientDemo

ClientDemo 测试工具是使用设备网络 SDK 开发包中的接口 开发而成的测试工具,可以用来测试设备的功能和接口,在开发的前 期和调试阶段用以测试设备的功能和 SDK 的接口
示例,我这里开启了人脸抓拍,如果有报警消息上传事件中心,就可以看到:
image.png

4.4200平台

iVMS-4200 客户端是一款与网络监控设备配套使用的综合应用软件,可满足用户多方面需求, 如设备管理、人员管理、考勤、可视对讲、数据分析、远程设备配置等
image.png

2.代码开发

关于人脸库照片数据导入:
限制:4M以下,手动导入人像后,会自动建模。

1.Maven依赖导入

说明:这里是将,海康提供的Java开发示例项目中,examples.jar和jna.jar 导入自己的Maven仓库

        <dependency>
            <groupId>net.java.jna</groupId>
            <artifactId>jna</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>net.java.examples</groupId>
            <artifactId>examples</artifactId>
            <version>1.0.0</version>
        </dependency>

2.动态库(重点)

SDK开发包【库文件】里的HCNetSDK.dll、HCCore.dll、HCNetSDKCom文件夹、libssl-1_1.dll、libcrypto-1_1.dll、hlog.dll、hpr.dll、zlib1.dll、PlayCtrl.dll、SuperRender.dll、AudioRender.dll等文件均要加载到程序里面,【HCNetSDKCom文件夹】(包含里面的功能组件dll库文件)需要和HCNetSDK.dll、HCCore.dll一起加载,放在同一个目录下,且HCNetSDKCom文件夹名不能修改。
注意:这里不同开发系统,加载的动态库不同,window是.dll后缀,Linux则是.so后缀,不要放错了。

3.报警布防核心配置类

说明:
海康提供的设备网络SDK是封装的动态链接库(Windows的dll或者Linux的so),各种开发语言对接SDK,都是通过加载动态库链接,调用动态库中的接口实现功能模块对接,因此,设备网络SDK的对接不区分开发语言,而且对接的流程和对应的接口都是通用的,各种语言调用动态库的方式有所不同
Java如何调用的:
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环境就可以完成。
–以上信息,在海康提供的,设备网络SDK使用手册_V6.1都有详细的说明

第一步:
将HCNetSDK.java复制到自己项目中。
image.png

第二步:初始化SDK代码演示:

@PostConstruct
    public void initSDKTools() {
        if (hCNetSDK == null) {
            // 动态库加载
            if (!CreateSDKInstance()) {
                log.error("load HaiKang SDK fail");
                return;
            }
        }
        //linux系统建议调用以下接口加载组件库
        if (osSelect.isLinux()) {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限
            String strPath1 = System.getProperty("user.dir") + properties.getLibPath() + File.separator
                + "libcrypto.so.1.1";
            String strPath2 = System.getProperty("user.dir") + properties.getLibPath() + File.separator
                + "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") + properties.getLibPath();
            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());
        }
        //SDK初始化,一个程序只需要调用一次
        boolean initSuc = hCNetSDK.NET_DVR_Init();
        if (!initSuc) {
            log.error("初始化失败........................");
        }
        // 设置连接时间与重连时间
        hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
        hCNetSDK.NET_DVR_SetReconnect(10000, true);

        //启动SDK写日志
        hCNetSDK.NET_DVR_SetLogToFile(3, "..\\sdkLog\\", false);

        //异常消息回调
        if (fExceptionCallBack == null) {
            fExceptionCallBack = new FExceptionCallBack_Imp();
        }

        Pointer pUser = null;
        //设置异常回调函数(可在回调函数中获取设备上下线状态等)
        if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) {
            return;
        }
        log.info("设置异常消息回调成功");

        //设置报警回调函数
        fmsgCallBack_v31 = new FMSGCallBack1();
        boolean b = hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(fmsgCallBack_v31, null);
        //如果设置报警回调失败,获取错误码
        if (!b) {
            log.error("SetDVRMessageCallBack failed, error code=" + hCNetSDK.NET_DVR_GetLastError());
        }

        //    设备上传的报警信息是COMM_VCA_ALARM(0x4993)类型,
        // 在SDK初始化之后增加调用NET_DVR_SetSDKLocalCfg(enumType为NET_DVR_LOCAL_CFG_TYPE_GENERAL)设置通用参数NET_DVR_LOCAL_GENERAL_CFG的byAlarmJsonPictureSeparate为1,
        // 将Json数据和图片数据分离上传,这样设置之后,报警布防回调函数里面接收到的报警信息类型为COMM_ISAPI_ALARM(0x6009),
        // 报警信息结构体为NET_DVR_ALARM_ISAPI_INFO(与设备无关,SDK封装的数据结构),更便于解析。
        HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struNET_DVR_LOCAL_GENERAL_CFG = new HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
        struNET_DVR_LOCAL_GENERAL_CFG.byAlarmJsonPictureSeparate = 1;   //设置JSON透传报警数据和图片分离
        struNET_DVR_LOCAL_GENERAL_CFG.write();
        Pointer pStrNET_DVR_LOCAL_GENERAL_CFG = struNET_DVR_LOCAL_GENERAL_CFG.getPointer();
        hCNetSDK.NET_DVR_SetSDKLocalCfg(17, pStrNET_DVR_LOCAL_GENERAL_CFG);
        // 登录设备
        int userId = haiKangListenService.deviceRegister(properties.getHost(), properties.getPort(),
            properties.getUsername(), properties.getPassword());
        // 布放
        haiKangListenService.placement(userId);
    }

    /**
     * win系统和Linux系统,动态库加载
     */
    private boolean CreateSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (osSelect.isWindows()) {
                        //win系统加载库路径
                        strDllPath = System.getProperty("user.dir")
                            + "\\src\\main\\resources\\lib\\hikvision\\win64\\HCNetSDK.dll";
                    } else if (osSelect.isLinux()) {
                        //Linux系统加载库路径
                        strDllPath = System.getProperty("user.dir") + properties.getLibPath() + File.separator
                            + "libhcnetsdk.so";
                    }
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
                } catch (Exception ex) {
                    log.error("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

设置布防相关参数代码:


    static List<Integer> userId = new ArrayList<>();
    static List<Integer> listen = new ArrayList<>();
    static List<Integer> nativeL = new ArrayList<>();
// 布防相关信息设置和启动监听,这里直接复制海康demo里面就行。
    public void placement(int lUserID) {
        //布防参数
        HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
        m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
        //布防等级
        m_strAlarmInfo.byLevel = 1;
        // 智能交通报警信息上传类型:0- 老报警信息(NET_DVR_PLATE_RESULT),1- 新报警信息(NET_ITS_PLATE_RESULT)
        m_strAlarmInfo.byAlarmInfoType = 1;
        //布防类型 0:客户端布防 1:实时布防
        m_strAlarmInfo.byDeployType = 1;
        m_strAlarmInfo.write();
        int nativeLong = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID, m_strAlarmInfo);
        //如果布防失败返回-1
        if (nativeLong < 0) {
            System.out.println("SetupAlarmChan failed, error code=" + hCNetSDK.NET_DVR_GetLastError());
            //注销
            hCNetSDK.NET_DVR_Logout(lUserID);
        }
        //启动监听
        boolean lListenHandle = hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(fmsgCallBack_v31, null);
        if (!lListenHandle) {
            log.error("启动监听失败,错误号:" + hCNetSDK.NET_DVR_GetLastError());
        } else {
            log.info("==================启动监听成功,等待设备上传报警信息==================");
        }
        userId.add(lUserID);
        // listen.add(lListenHandle);
        nativeL.add(nativeLong);
    }

// 注册登录设备



// 登录设备的方法
@Async
public int deviceRegister(String ip, int port, String userName, String password) {
    //登录设备,每一台设备分别登录; 登录句柄是唯一的,可以区分设备
    //设备登录信息
    HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
    //设备信息
    HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
    //设备ip地址
    String m_sDeviceIP = ip;
    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());
    //设备用户名
    String m_sUsername = userName;
    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());
    //设备密码
    String m_sPassword = password;
    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());
    //SDK端口
    m_strLoginInfo.wPort = (short) port;
    //是否异步登录:0- 否,1- 是
    m_strLoginInfo.bUseAsynLogin = false;
    //ISAPI登录
    m_strLoginInfo.byLoginMode = 0;
    m_strLoginInfo.write();

    int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
    if (lUserID == -1) {
        log.error("登录失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
        throw new ProjectException(ExceptionEnum.HAIKANG_LOGIN_ERROR.getCode());
    } else {
        System.out.println(hCNetSDK.NET_DVR_GetLastError());
        log.info(
            m_sDeviceIP + ":设备登录成功! " + "设备序列号:" + new String(m_strDeviceInfo.struDeviceV30.sSerialNumber).trim());
        m_strDeviceInfo.read();
        return lUserID;
    }
}

// 项目停止后,释放资源

	// 项目停止后,释放资源
	@PreDestroy
    public void LogoutAndStopListen() {
        //撤销布防上传通道
        for (int i = 0; i < userId.size(); i++) {
            if (!hCNetSDK.NET_DVR_CloseAlarmChan_V30(nativeL.get(i))) {
                //注销
                hCNetSDK.NET_DVR_Logout(userId.get(i));
            }
        }
        //停止监听 lListenHandle是启动监听时返回值
        for (Integer integer : listen) {
            hCNetSDK.NET_DVR_StopListen_V30(integer);
        }
    }

这里可以尝试启动一下项目,同时查看日志是否启动成功。

4.报警事件信息处理

	@Override
    public void alarmDataHandle(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen,
        Pointer pUser) {
        //lCommand是传的报警类型
        switch (lCommand) {
            //人脸比对报警
            case HCNetSDK.COMM_SNAP_MATCH_ALARM:
                HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM strFaceSnapMatch = new HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM();
                strFaceSnapMatch.write();
                Pointer pFaceSnapMatch = strFaceSnapMatch.getPointer();
                pFaceSnapMatch.write(0, pAlarmInfo.getByteArray(0, strFaceSnapMatch.size()), 0,
                    strFaceSnapMatch.size());
                strFaceSnapMatch.read();
                // 人脸比对报警图片保存,图片格式URL格式
                System.out.println("检测到人脸比对事件");
                break;
            case HCNetSDK.COMM_ISAPI_ALARM:
                // 处理安全帽检测上传的照片数据
                HCNetSDK.NET_DVR_ALARM_ISAPI_INFO struEventISAPI = new HCNetSDK.NET_DVR_ALARM_ISAPI_INFO();
                struEventISAPI.write();
                Pointer pEventISAPI = struEventISAPI.getPointer();
                pEventISAPI.write(0, pAlarmInfo.getByteArray(0, struEventISAPI.size()), 0, struEventISAPI.size());
                struEventISAPI.read();

                HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA struPicData = new HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA();
                struPicData.write();
                Pointer pPicData = struPicData.getPointer();
                pPicData.write(0, struEventISAPI.pPicPackData.getByteArray(0, struPicData.size()), 0,
                    struPicData.size());
                struPicData.read();
                System.out.println("检测到安全帽事件");
                break;
            default:
                log.info("报警类型" + Integer.toHexString(lCommand));
                break;
        }

3.避坑总结

1.关于动态库加载问题?
不同系统,加载的动态库不同,这里一定要注意。
Windows上可能会遇到动态库无法加载,建议直接使用绝对路径
linux上加载.so为后缀的动态库,使用相对路径
如果win系统开发没有问题了,注意在Linux系统跑项目的时候,也要注意动态库加载问题。
2.海康网上客服只能处理设备配置问题,SDK问题需要给海康发邮件;
3.超脑人脸比对报警,上传事件照片是URL,交互方式还需要认证。
4.样例代码地址:代码样例供参考
5.关于安全帽相关,可以用COMM_ISAPI_ALARM(6009)和COMM_UPLOAD_AIOP_VIDEO(4021)接收
以上,更新时间2023-11-7 11:08:28,其他还有啥,后续慢慢补充吧。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
海康威视SDK是一种用于视频监控系统开发的软件开发工具包,可以支持多种编程语言和操作系统。其中,C语言是一种非常常用的语言,因此在二次开发海康威视SDK时,使用C语言进行开发是非常常见的。 下面是一些在C语言中使用海康威视SDK进行二次开发的常用步骤: 1. 安装SDK 首先,需要从官方网站上下载并安装海康威视SDK。安装过程中需要注意选择合适的操作系统和编程语言版本。 2. 引入头文件 在C语言程序中,需要通过#include指令引入SDK的头文件。这些头文件包含了SDK中所提供的函数和数据类型的定义。 3. 初始化SDK 在使用SDK之前,需要调用SDK提供的初始化函数,以便进行必要的设置和准备工作。这个初始化函数通常会返回一个句柄,用于后续的操作。 4. 连接设备 使用SDK提供的函数,可以连接到监控系统中的设备,获取设备信息和视频流等数据。连接设备时需要指定设备的IP地址、端口号、用户名和密码等信息。 5. 获取视频流 一旦连接到设备,就可以使用SDK提供的函数获取设备的视频流数据。这些数据可以保存到本地文件中,也可以实时播放。 6. 控制设备 使用SDK提供的函数,可以对监控系统中的设备进行控制。例如,可以控制摄像头的移动、缩放等操作。 7. 释放资源 在程序结束之前,需要调用SDK提供的释放资源函数,以释放所有使用的内存和其他资源。 总之,在使用海康威视SDK进行C语言开发时,需要掌握SDK的相关API和函数,以及熟悉C语言的基本语法和编程思想。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值