海康NVR设备上传人脸图片到人脸库

海康开放平台——海康文档链接——海康开发包和文档下载链接

硬件:海康超脑NVR(全称Network Video Recorder,即网络视频录像机)、人脸摄像机。

环境:JDK_1.8 Windows 64位 jna.jar版本为3.0.9

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>3.0.9</version>
</dependency>

定义SDK接口:

自定义一个接口HCNetSDK,继承Library 或 StdCallLibrary。默认的是继承Library ,如果动态链接库里的函数是以stdcall方式输出的,那么就继承StdCallLibrary。接口内部需要一个公共静态常量:INSTANCE,通过这个常量,就可以获得这个接口的实例,从而使用接口的方法,也就是调用外部dll/so的函数。INSTANCE常量通过 Native.loadLibrary() API函数获得,(新版本的jna中,常量是通过Native.load()函数获取的)该函数有2个参数:

1)第一个参数是动态链接库dll/so的全路径名称(可以是绝对路径或者相对路径),本demo采用的是绝对路径。

2)第二个参数是自定义接口的Class类型。JNA通过这个Class类型,根据指定的.dll/.so文件,动态创建接口的实例。该实例由JNA通过反射自动生成。

// SDK接口说明,HCNetSDK.dll
public interface HCNetSDK extends StdCallLibrary {

    HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary("E:\\DEMO_TEST\\JAVA_Demo\\JNA_TEST\\lib\\HCNetSDK.dll", HCNetSDK.class);
    
    // 动态库中结构体、接口描述
    public static class NET_DVR_USER_LOGIN_INFO extends Structure{
        public byte[] sDeviceAddress = new byte[NET_DVR_DEV_ADDRESS_MAX_LEN];
        public byte byUseTransport;
        public short wPort;
        public byte[] sUserName = new byte[NET_DVR_LOGIN_USERNAME_MAX_LEN];
        public byte[] sPassword = new byte[NET_DVR_LOGIN_PASSWD_MAX_LEN];
        public FLoginResultCallback cbLoginResult;
        public Pointer pUser;
        public boolean bUseAsynLogin;
        public byte byProxyType;   // 0:不使用代理,1:使用标准代理,2:使用EHome代理
        public byte byUseUTCTime;  // 0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换
        public byte byLoginMode;   // 0-Private 1-ISAPI 2-自适应
        public byte byHttps;       // 0-不适用tls,1-使用tls 2-自适应
        public int iProxyID;    // 代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值
        public byte byVerifyMode;  // 认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效;
        public byte[] byRes2 = new byte[119];
        
        // 结构体中重写getFieldOrder方法,FieldOrder顺序要和结构体中定义的顺序保持一致
        @Override
        protected List getFieldOrder(){
            return  Arrays.asList("sDeviceAddress","byUseTransport","wPort","sUserName","sPassword",                                                               "cbLoginResult","pUser","bUseAsynLogin","byProxyType","byUseUTCTime",
                                  "byLoginMode","byHttps","iProxyID","byVerifyMode","byRes2");
    	} 
        
	}
    
    // 常量(宏)定义
    public static final int NET_DVR_DEV_ADDRESS_MAX_LEN = 129;
    public static final int NET_DVR_LOGIN_USERNAME_MAX_LEN = 64;
    public static final int NET_DVR_LOGIN_PASSWD_MAX_LEN = 64;
    
    /*** API函数声明 ***/
    
    // 初始化SDK,调用其他SDK函数的前提
	boolean NET_DVR_Init();  
    
    // 启用日志文件写入接口
	boolean NET_DVR_SetLogToFile(int bLogEnable , String  strLogDir, boolean bAutoDel); 
    
	// 返回最后操作的错误码
    int NET_DVR_GetLastError();  
    
    // 释放SDK资源,在程序结束之前调用
	boolean NET_DVR_Cleanup();
    
    // 登录接口
	int NET_DVR_Login_V40(NET_DVR_USER_LOGIN_INFO pLoginInfo, NET_DVR_DEVICEINFO_V40 lpDeviceInfo); 
    
    // 用户注销
	boolean NET_DVR_Logout(int lUserID); 

	// 回调函数申明
	public static interface FLoginResultCallback extends StdCallCallback{
        
    // 登录状态回调函数
	public int invoke(int lUserID,int dwResult,NET_DVR_DEVICEINFO_V30 lpDeviceinfo,Pointer pUser);
}

测试登录

海康NVR设备上传人脸图片到人脸库

package com.hik;
/**
 * @author test
 * @create 2021-02-07-15:53
 */
public class jna_test {
    // 接口的实例,通过接口实例调用外部dll/so的函数
    static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE; 
    
    // 用户登录返回句柄
    static int lUserID;  
    int iErr = 0;
    
    public static void main(String[] args) throws InterruptedException {
        jna_test test01 = new jna_test();
        // 初始化
        boolean initSuc = hCNetSDK.NET_DVR_Init();
        if (initSuc != true) {
            System.out.println("初始化失败");
        }
        // 打印SDK日志
        hCNetSDK.NET_DVR_SetLogToFile(3, ".\\SDKLog\\", false);
        // 用户登陆操作
        test01.Login_V40("192.168.1.64",(short)8000,"admin","test12345");
        /*
        *实现SDK中其余功能模快
        */
        Thread.sleep(5000);
        //用户注销,释放SDK
        test01.Logout();    
    }
    /**
     *
     * @param m_sDeviceIP 设备ip地址
     * @param wPort       端口号,设备网络SDK登录默认端口8000
     * @param m_sUsername 用户名
     * @param m_sPassword 密码
     */
    public void Login_V40(String m_sDeviceIP,short wPort,String m_sUsername,String m_sPassword) {
        /* 注册 */
        // 设备登录信息
        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();
        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.wPort =wPort ;
        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());
        // 是否异步登录:false- 否,true- 是
        m_strLoginInfo.bUseAsynLogin = false; 
        // write()调用后数据才写入到内存中
        m_strLoginInfo.write();  
        
        lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (lUserID == -1) {
            System.out.println("登录失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
            return;
        } else {
            System.out.println("登录成功!");
            
            // read()后,结构体中才有对应的数据 
            m_strDeviceInfo.read();  
            return;
        }
    }
    //设备注销 SDK释放
    public void Logout() {
        if (lUserID>=0)
        {
            if (hCNetSDK.NET_DVR_Logout(lUserID) == false) {
                System.out.println("注销失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
            }
            System.out.println("注销成功");
            hCNetSDK.NET_DVR_Cleanup();
            return;
        }
        else{
            System.out.println("设备未登录");
            hCNetSDK.NET_DVR_Cleanup();
            return;
        }
    }
}

批量获取人脸库信息

批量获取或设置人脸库信息:(命令:GET /ISAPI/Intelligent/FDLibPUT /ISAPI/Intelligent/FDLib);

  1. SDK初始化

    	// 接口的实例,通过接口实例调用外部dll/so的函数
        static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    
    	// step1:初始化
        boolean initSuc = hCNetSDK.NET_DVR_Init();
        if (initSuc != true) {
            System.out.println("初始化失败");
        }
    
  2. 打印SDK日志

    	/**
         * 启用日志文件写入接口
         *
         * @param bLogEnable 日志的等级(默认为0):0-表示关闭日志,1-表示只输出ERROR错误日志,2-输出ERROR错误信息和DEBUG调试信息,3-输出ERROR错误信息、DEBUG调试信息和INFO普通信息等所有信息
         * @param strLogDir  日志文件的路径,windows默认值为"C:\\SdkLog\\";linux默认值"/home/sdklog/"
         * @param bAutoDel   是否删除超出的文件数,默认值为TRUE
         * @return
         */	
    
    	// step2:打印SDK日志
        hCNetSDK.NET_DVR_SetLogToFile(3, ".\\SDKLog\\", false);
    
  3. 用户登陆操作

        // 登录接口
        int NET_DVR_Login_V40(NET_DVR_USER_LOGIN_INFO pLoginInfo, NET_DVR_DEVICEINFO_V40 lpDeviceInfo);
    
  4. 获取人脸库信息

        //命令 GET /ISAPI/Intelligent/FDLib
    
    	//ISAPI协议命令透传
        boolean NET_DVR_STDXMLConfig(int lUserID, NET_DVR_XML_CONFIG_INPUT lpInputParam, NET_DVR_XML_CONFIG_OUTPUT lpOutputParam);
    

    批量获取人脸库信息方法

        public static final int ISAPI_DATA_LEN = 1024 * 1024;
        public static final int ISAPI_STATUS_LEN = 4 * 4096;
        public static final int BYTE_ARRAY_LEN = 1024;
    
        HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    
        /**
         * 批量获取人脸库信息
         *
         * @param lUserID 登录返回的句柄
         */
        public void getFaceLibInfo(int lUserID) {
            //获取人脸比对库能力集判断设备是否支持相关功能
            //  String url = "GET /ISAPI/Intelligent/FDLib/capabilities";
            //命令
            String url = "GET /ISAPI/Intelligent/FDLib";
            HCNetSDK.BYTE_ARRAY ptrUrl = new HCNetSDK.BYTE_ARRAY(BYTE_ARRAY_LEN);
            System.arraycopy(url.getBytes(), 0, ptrUrl.byValue, 0, url.length());
            // 数据写入到内存
            ptrUrl.write();
            //透传接口输入参数结构体
            HCNetSDK.NET_DVR_XML_CONFIG_INPUT netDvrXmlConfigInput = new HCNetSDK.NET_DVR_XML_CONFIG_INPUT();
            //结构体大小
            netDvrXmlConfigInput.dwSize = netDvrXmlConfigInput.size();
            //请求信令,字符串格式
            netDvrXmlConfigInput.lpRequestUrl = ptrUrl.getPointer();
            //请求信令长度,字符串长度
            netDvrXmlConfigInput.dwRequestUrlLen = url.length();
            //输入参数缓冲区,XML/JSON格式
            netDvrXmlConfigInput.lpInBuffer = null;//ptrInBuffer.getPointer();
            //输入参数缓冲区大小
            netDvrXmlConfigInput.dwInBufferSize = 0;//ptrInBuffer.byValue.length;
            netDvrXmlConfigInput.write();
    
            HCNetSDK.BYTE_ARRAY ptrStatusByte = new HCNetSDK.BYTE_ARRAY(ISAPI_STATUS_LEN);
            HCNetSDK.BYTE_ARRAY ptrOutByte = new HCNetSDK.BYTE_ARRAY(ISAPI_DATA_LEN);
            HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT struXMLOutput = new HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT();
            struXMLOutput.dwSize = struXMLOutput.size();
            struXMLOutput.lpOutBuffer = ptrOutByte.getPointer();
            struXMLOutput.dwOutBufferSize = ptrOutByte.size();
            struXMLOutput.lpStatusBuffer = ptrStatusByte.getPointer();
            struXMLOutput.dwStatusSize = ptrStatusByte.size();
            struXMLOutput.write();
    
            //ISAPI协议命令透传
            if (!hCNetSDK.NET_DVR_STDXMLConfig(lUserID, netDvrXmlConfigInput, struXMLOutput)) {
                System.out.println("NET_DVR_STDXMLConfig失败,错误号:" + hCNetSDK.NET_DVR_GetLastError());
                return;
            } else {
                struXMLOutput.read();
                ptrOutByte.read();
                ptrStatusByte.read();
                String strOutXML = new String(ptrOutByte.byValue).trim();
                System.out.println("获取设备能力集输出结果:" + strOutXML);
                String strStatus = new String(ptrStatusByte.byValue).trim();
                System.out.println("获取设备能力集返回状态:" + strStatus);
            }
        }
    
  5. 用户注销,释放SDK

        // 用户注销
        boolean NET_DVR_Logout(int lUserID);
    
        // 释放SDK资源,在程序结束之前调用
        boolean NET_DVR_Cleanup();
    

创建人脸库

创建人脸库:(命令:POST /ISAPI/Intelligent/FDLib);

  1. SDK初始化

    	// 接口的实例,通过接口实例调用外部dll/so的函数
        static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    
    	// step1:初始化
        boolean initSuc = hCNetSDK.NET_DVR_Init();
        if (initSuc != true) {
            System.out.println("初始化失败");
        }
    
  2. 打印SDK日志

    	/**
         * 启用日志文件写入接口
         *
         * @param bLogEnable 日志的等级(默认为0):0-表示关闭日志,1-表示只输出ERROR错误日志,2-输出ERROR错误信息和DEBUG调试信息,3-输出ERROR错误信息、DEBUG调试信息和INFO普通信息等所有信息
         * @param strLogDir  日志文件的路径,windows默认值为"C:\\SdkLog\\";linux默认值"/home/sdklog/"
         * @param bAutoDel   是否删除超出的文件数,默认值为TRUE
         * @return
         */	
    
    	// step2:打印SDK日志
        hCNetSDK.NET_DVR_SetLogToFile(3, ".\\SDKLog\\", false);
    
  3. 用户登陆操作

        // 登录接口
        int NET_DVR_Login_V40(NET_DVR_USER_LOGIN_INFO pLoginInfo, NET_DVR_DEVICEINFO_V40 lpDeviceInfo);
    
  4. 创建人脸库

        // 命令 POST /ISAPI/Intelligent/FDLib
    
    	// ISAPI协议命令透传
        boolean NET_DVR_STDXMLConfig(int lUserID, NET_DVR_XML_CONFIG_INPUT lpInputParam, NET_DVR_XML_CONFIG_OUTPUT lpOutputParam);
    
    	// 创建成功后
    	// 使用dom4j解析xml,获取FDID
        lpOutputParam.read();
    	String xmlStr = lpOutputParam.lpOutBuffer.getString(0);
        // dom4j解析xml
        try {
            Document document;
            document = DocumentHelper.parseText(xmlStr);
            Element FDLibInfoList = document.getRootElement();
            // 同时迭代当前节点下面的所有子节点
            Iterator<Element> iterator = FDLibInfoList.elementIterator();
            Element FDLibInfo = iterator.next();
            Iterator<Element> iterator2 = FDLibInfo.elementIterator();
            while (iterator2.hasNext()) {
                Element e = iterator2.next();
                if (e.getName().equals("FDID")) {
                    String FDID = e.getText();
                    System.out.println("FDID = " + FDID);
                }
            }
        } catch (DocumentException e1) {
            e1.printStackTrace();
        }
    

    创建人脸库方法

        public static final int ISAPI_DATA_LEN = 1024 * 1024;
        public static final int ISAPI_STATUS_LEN = 4 * 4096;
    	public static final int BYTE_ARRAY_LEN = 1024;
        HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    
    	/**
         * 创建人脸库
         *
         * @param lUserID     登录返回的句柄
         * @param faceId      人脸库ID
         * @param faceLibName 人脸库名称(目前不能是中文)
         */
        public void createFaceLib(int lUserID, String faceId, String faceLibName) {
            //创建人脸库
            String url = "POST /ISAPI/Intelligent/FDLib";
            HCNetSDK.BYTE_ARRAY ptrUrl = new HCNetSDK.BYTE_ARRAY(BYTE_ARRAY_LEN);
            System.arraycopy(url.getBytes(), 0, ptrUrl.byValue, 0, url.length());
            // 数据写入到内存
            ptrUrl.write();
            //透传接口输入参数结构体
            HCNetSDK.NET_DVR_XML_CONFIG_INPUT netDvrXmlConfigInput = new HCNetSDK.NET_DVR_XML_CONFIG_INPUT();
            //结构体大小
            netDvrXmlConfigInput.dwSize = netDvrXmlConfigInput.size();
            //请求信令,字符串格式
            netDvrXmlConfigInput.lpRequestUrl = ptrUrl.getPointer();
            //请求信令长度,字符串长度
            netDvrXmlConfigInput.dwRequestUrlLen = url.length();
            // 人脸库名称
            String strInBuffer = new String("<CreateFDLibList><CreateFDLib><id>" + faceId + "</id><name>" + faceLibName
                    + "</name><thresholdValue>1</thresholdValue><autoUpdata>true</autoUpdata></CreateFDLib></CreateFDLibList>");
            HCNetSDK.BYTE_ARRAY ptrByte = new HCNetSDK.BYTE_ARRAY(ISAPI_DATA_LEN);
            ptrByte.byValue = strInBuffer.getBytes();
            ptrByte.write();
            netDvrXmlConfigInput.lpInBuffer = ptrByte.getPointer();
            netDvrXmlConfigInput.dwInBufferSize = strInBuffer.length();
            netDvrXmlConfigInput.write();
    
            HCNetSDK.BYTE_ARRAY ptrStatusByte = new HCNetSDK.BYTE_ARRAY(ISAPI_STATUS_LEN);
            HCNetSDK.BYTE_ARRAY ptrOutByte = new HCNetSDK.BYTE_ARRAY(ISAPI_DATA_LEN);
            HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT struXMLOutput = new HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT();
            struXMLOutput.dwSize = struXMLOutput.size();
            struXMLOutput.lpOutBuffer = ptrOutByte.getPointer();
            struXMLOutput.dwOutBufferSize = ptrOutByte.size();
            struXMLOutput.lpStatusBuffer = ptrStatusByte.getPointer();
            struXMLOutput.dwStatusSize = ptrStatusByte.size();
            struXMLOutput.write();
    
            //ISAPI协议命令透传
            if (!hCNetSDK.NET_DVR_STDXMLConfig(lUserID, netDvrXmlConfigInput, struXMLOutput)) {
                System.out.println("NET_DVR_STDXMLConfig失败,错误号:" + hCNetSDK.NET_DVR_GetLastError());
                return;
            } else {
                struXMLOutput.read();
                ptrOutByte.read();
                ptrStatusByte.read();
                String strOutXML = new String(ptrOutByte.byValue).trim();
                System.out.println("获取设备能力集输出结果:" + strOutXML);
                String xmlStr = struXMLOutput.lpOutBuffer.getString(0);
                // dom4j解析xml
                try {
                    Document document;
                    document = DocumentHelper.parseText(xmlStr);
                    Element FDLibInfoList = document.getRootElement();
                    // 同时迭代当前节点下面的所有子节点
                    Iterator<Element> iterator = FDLibInfoList.elementIterator();
                    Element FDLibInfo = iterator.next();
                    Iterator<Element> iterator2 = FDLibInfo.elementIterator();
                    while (iterator2.hasNext()) {
                        Element e = iterator2.next();
                        if (e.getName().equals("FDID")) {
                            String FDID = e.getText();
                            System.out.println("FDID = " + FDID);
                        }
                    }
                } catch (DocumentException e1) {
                    e1.printStackTrace();
                }
            }
        }
    
  5. 用户注销,释放SDK

        // 用户注销
        boolean NET_DVR_Logout(int lUserID);
    
        // 释放SDK资源,在程序结束之前调用
        boolean NET_DVR_Cleanup();
    

上传人脸图片到人脸库

人脸对比文档链接

  1. 初始化SDK NET_DVR_Init
  2. 用户注册 NET_DVR_Login_V40
  3. 创建人脸库 NET_DVR_STDXMLConfig 命令: POST /ISAPI/Intelligent/FDLib
  4. 建立人脸数据上传的长链接 NET_DVR_UploadFile_V40(命令:IMPORT_DATA_TO_FACELIB)
  5. 上传人脸数据(人脸图片+图片附加信息)到人脸库 NET_DVR_UploadSend
  6. 获取上传状态和进度 NET_DVR_GetUploadState
  7. 获取结果信息(图片ID) NET_DVR_GetUploadResult
  8. 上传结束,断开链接,释放资源 NET_DVR_UploadClose
  9. 注销用户 NET_DVR_Logout
  10. 释放SDK资源 NET_DVR_Cleanup
  • 上传接口调用流程
    海康NVR设备上传人脸图片到人脸库
    (1) 调用NET_DVR_UploadFile_V40(命令:IMPORT_DATA_TO_FACELIB)开始上传数据。上传条件里面NET_DVR_FACELIB_COND.byConcurrent赋值为0时不开启并发处理,设备会自动对上传的图片进行建模,如果批量上传大量图片,可以赋值为1开启并发处理,提高速度,但是上传之后需要自己建模。

    (2) 调用NET_DVR_UploadSend发送一张人脸图片数据和附加信息。

    (3) 上传过程中循环调用NET_DVR_GetUploadState获取上传状态和进度。

    (4) 上传成功之后调用NET_DVR_GetUploadResult获取结果信息(图片ID等)。

    (5) 重复步骤2、3、4,顺序上传其他人脸数据。

    (6) 调用NET_DVR_UploadClose停止上传,释放资源。

完整代码

HCNetSDK.java

import com.sun.jna.Callback;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.examples.win32.W32API;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;

import java.util.Arrays;
import java.util.List;

// SDK接口说明,HCNetSDK.dll
public interface HCNetSDK extends StdCallLibrary {

    HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary("C:\\Users\\ZhangWanPeng\\Desktop\\HCNetSDK.dll", HCNetSDK.class);

    // 常量(宏)定义
    public static final int NAME_LEN = 32;    //用户名长度
    public static final int MACADDR_LEN = 6;      //mac地址长度

    public static final int NET_DVR_DEV_ADDRESS_MAX_LEN = 129;
    public static final int NET_DVR_LOGIN_USERNAME_MAX_LEN = 64;
    public static final int NET_DVR_LOGIN_PASSWD_MAX_LEN = 64;
    public static final int SERIALNO_LEN = 48;   //序列号长度
    public static final int NET_SDK_CONFIG_STATUS_SUCCESS = 1000;
    public static final int NET_SDK_CONFIG_STATUS_NEEDWAIT = 1001;
    public static final int NET_SDK_CONFIG_STATUS_FINISH = 1002;
    public static final int NET_SDK_CONFIG_STATUS_FAILED = 1003;
    public static final int NET_SDK_CONFIG_STATUS_EXCEPTION = 1004;
    public static final int IMPORT_DATA_TO_FACELIB = 39; //导入人脸数据(人脸图片+图片附加信息)到人脸库
    /**
     * 人脸库ID最大长度
     */
    public static final int NET_SDK_MAX_FDID_LEN = 256;
    // 文件上传URL最大长度
    public static final int MAX_UPLOADFILE_URL_LEN = 240;

    // 动态库中结构体、接口描述
    public static class NET_DVR_USER_LOGIN_INFO extends Structure {
        public byte[] sDeviceAddress = new byte[NET_DVR_DEV_ADDRESS_MAX_LEN];
        public byte byUseTransport;
        public short wPort;
        public byte[] sUserName = new byte[NET_DVR_LOGIN_USERNAME_MAX_LEN];
        public byte[] sPassword = new byte[NET_DVR_LOGIN_PASSWD_MAX_LEN];
        public FLoginResultCallback cbLoginResult;
        public Pointer pUser;
        public boolean bUseAsynLogin;
        public byte byProxyType;   // 0:不使用代理,1:使用标准代理,2:使用EHome代理
        public byte byUseUTCTime;  // 0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换
        public byte byLoginMode;   // 0-Private 1-ISAPI 2-自适应
        public byte byHttps;       // 0-不适用tls,1-使用tls 2-自适应
        public int iProxyID;    // 代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值
        public byte byVerifyMode;  // 认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效;
        public byte[] byRes2 = new byte[119];

        // 结构体中重写getFieldOrder方法,FieldOrder顺序要和结构体中定义的顺序保持一致
        @Override
        protected List getFieldOrder() {
            return Arrays.asList("sDeviceAddress", "byUseTransport", "wPort", "sUserName", "sPassword", "cbLoginResult", "pUser", "bUseAsynLogin", "byProxyType", "byUseUTCTime",
                    "byLoginMode", "byHttps", "iProxyID", "byVerifyMode", "byRes2");
        }

    }

    //NET_DVR_Login_V30()参数结构
    public static class NET_DVR_DEVICEINFO_V30 extends Structure {
        public byte[] sSerialNumber = new byte[SERIALNO_LEN];  //序列号
        public byte byAlarmInPortNum;    //报警输入个数
        public byte byAlarmOutPortNum;   //报警输出个数
        public byte byDiskNum;           //硬盘个数
        public byte byDVRType;         //设备类型, 1:DVR 2:ATM DVR 3:DVS ......
        public byte byChanNum;         //模拟通道个数
        public byte byStartChan;      //起始通道号,例如DVS-1,DVR - 1
        public byte byAudioChanNum;    //语音通道数
        public byte byIPChanNum;     //最大数字通道个数,低位
        public byte byZeroChanNum;    //零通道编码个数 //2010-01-16
        public byte byMainProto;      //主码流传输协议类型 0-private, 1-rtsp,2-同时支持private和rtsp
        public byte bySubProto;        //子码流传输协议类型0-private, 1-rtsp,2-同时支持private和rtsp
        public byte bySupport;        //能力,位与结果为0表示不支持,1表示支持,
        public byte bySupport1;        // 能力集扩充,位与结果为0表示不支持,1表示支持
        public byte bySupport2; /*能力*/
        public short wDevType;              //设备型号
        public byte bySupport3; //能力集扩展
        public byte byMultiStreamProto;//是否支持多码流,按位表示,0-不支持,1-支持,bit1-码流3,bit2-码流4,bit7-主码流,bit-8子码流
        public byte byStartDChan;        //起始数字通道号,0表示无效
        public byte byStartDTalkChan;    //起始数字对讲通道号,区别于模拟对讲通道号,0表示无效
        public byte byHighDChanNum;        //数字通道个数,高位
        public byte bySupport4;        //能力集扩展
        public byte byLanguageType;// 支持语种能力,按位表示,每一位0-不支持,1-支持
        //  byLanguageType 等于0 表示 老设备
        //  byLanguageType & 0x1表示支持中文
        //  byLanguageType & 0x2表示支持英文
        public byte byVoiceInChanNum;   //音频输入通道数
        public byte byStartVoiceInChanNo; //音频输入起始通道号 0表示无效
        public byte byRes3;        //保留
        public byte byMirrorChanNum;    //镜像通道个数,<录播主机中用于表示导播通道>
        public short wStartMirrorChanNo;  //起始镜像通道号
        public byte byRes2;        //保留
    }

    //NET_DVR_Login_V40()参数
    public static class NET_DVR_DEVICEINFO_V40 extends Structure {
        public NET_DVR_DEVICEINFO_V30 struDeviceV30 = new NET_DVR_DEVICEINFO_V30();
        public byte bySupportLock;
        public byte byRetryLoginTime;
        public byte byPasswordLevel;
        public byte byProxyType;
        public int dwSurplusLockTime;
        public byte byCharEncodeType;//字符编码类型:0- 无字符编码信息(老设备),1- GB2312(简体中文),2- GBK,3- BIG5(繁体中文),4- Shift_JIS(日文),5- EUC-KR(韩文),6- UTF-8,7- ISO8859-1,8- ISO8859-2,9- ISO8859-3,…,依次类推,21- ISO8859-15(西欧)
        public byte bySupportDev5; //支持v50版本的设备参数获取,设备名称和设备类型名称长度扩展为64字节
        public byte byLoginMode; //登录模式 0-Private登录 1-ISAPI登录
        public byte[] byRes2 = new byte[253];
    }

    //预览参数结构体
    public static class NET_DVR_PREVIEWINFO extends Structure {
        public int lChannel;//通道号
        public int dwStreamType;    // 码流类型,0-主码流,1-子码流,2-码流3,3-码流4, 4-码流5,5-码流6,7-码流7,8-码流8,9-码流9,10-码流10
        public int dwLinkMode;// 0:TCP方式,1:UDP方式,2:多播方式,3 - RTP方式,4-RTP/RTSP,5-RSTP/HTTP ,6- HRUDP(可靠传输) ,7-RTSP/HTTPS
        public W32API.HWND hPlayWnd;//播放窗口的句柄,为NULL表示不播放图象
        public int bBlocked;  //0-非阻塞取流, 1-阻塞取流, 如果阻塞SDK内部connect失败将会有5s的超时才能够返回,不适合于轮询取流操作.
        public int bPassbackRecord; //0-不启用录像回传,1启用录像回传
        public byte byPreviewMode;//预览模式,0-正常预览,1-延迟预览
        public byte[] byStreamID = new byte[32];//流ID,lChannel为0xffffffff时启用此参数
        public byte byProtoType; //应用层取流协议,0-私有协议,1-RTSP协议
        public byte byRes1;
        public byte byVideoCodingType; //码流数据编解码类型 0-通用编码数据 1-热成像探测器产生的原始数据(温度数据的加密信息,通过去加密运算,将原始数据算出真实的温度值)
        public int dwDisplayBufNum; //播放库播放缓冲区最大缓冲帧数,范围1-50,置0时默认为1
        public byte byNPQMode;    //NPQ是直连模式,还是过流媒体 0-直连 1-过流媒体
        public byte[] byRes = new byte[215];
    }

    //上传文件
    public static class NET_DVR_UploadFile_V40 extends Structure {
        public int lUserID;
        public int dwUploadType;
        public byte[] lpInBuffer;

    }

    public static class BYTE_ARRAY extends Structure {
        public byte[] byValue;

        public BYTE_ARRAY(int iLen) {
            byValue = new byte[iLen];
        }
    }

    //JSON数据配置结构体
    public static class NET_DVR_JSON_DATA_CFG extends Structure {
        public int dwSize;                        //结构体大小
        public Pointer lpJsonData;                //JSON报文
        public int dwJsonDataSize;                //JSON报文大小
        public Pointer lpPicData;                //图片内容
        public int dwPicDataSize;                //图片内容大小
        public int lpInfraredFacePicBuffer;        //红外人脸图片数据缓存
        public Pointer dwInfraredFacePicSize;    //红外人脸图片数据大小,等于0时,代表无人脸图片数据(当JSON报文为当ResponseStatus(JSON)报文时,该字段无意义;当Inbound Data(JSON)报文中没有infraredFaceURL时,该字段需要带上二进制图片内容)
        public byte[] byRes = new byte[248];
    }

    //报警设备信息
    public static class NET_DVR_ALARMER extends Structure {
        public byte byUserIDValid;                 /* userid是否有效 0-无效,1-有效 */
        public byte bySerialValid;                 /* 序列号是否有效 0-无效,1-有效 */
        public byte byVersionValid;                /* 版本号是否有效 0-无效,1-有效 */
        public byte byDeviceNameValid;             /* 设备名字是否有效 0-无效,1-有效 */
        public byte byMacAddrValid;                /* MAC地址是否有效 0-无效,1-有效 */
        public byte byLinkPortValid;               /* login端口是否有效 0-无效,1-有效 */
        public byte byDeviceIPValid;               /* 设备IP是否有效 0-无效,1-有效 */
        public byte bySocketIPValid;               /* socket ip是否有效 0-无效,1-有效 */
        public int lUserID;                       /* NET_DVR_Login()返回值, 布防时有效 */
        public byte[] sSerialNumber = new byte[SERIALNO_LEN];    /* 序列号 */
        public int dwDeviceVersion;                /* 版本信息 高16位表示主版本,低16位表示次版本*/
        public byte[] sDeviceName = new byte[NAME_LEN];            /* 设备名字 */
        public byte[] byMacAddr = new byte[MACADDR_LEN];        /* MAC地址 */
        public short wLinkPort;                     /* link port */
        public byte[] sDeviceIP = new byte[128];                /* IP地址 */
        public byte[] sSocketIP = new byte[128];                /* 报警主动上传时的socket IP地址 */
        public byte byIpProtocol;                  /* Ip协议 0-IPV4, 1-IPV6 */
        public byte[] byRes2 = new byte[11];
    }

    /**
     * 导入人脸数据(人脸图片+图片附件信息)到人脸库的条件参数结构体
     */
    public static class NET_DVR_FACELIB_COND extends Structure {
        public int dwSize;  //结构体大小
        public byte[] szFDID = new byte[256]; //人脸库ID(设备自动生成的FDID或者是自定义的customFaceLibID),唯一标识
        public byte byConcurrent; //设备并发处理:0- 不开启(设备自动会建模),1- 开始(设备不会自动进行建模)
        public byte byCover;  //是否覆盖式导入(人脸库存储满的情况下强制覆盖导入时间最久的图片数据):0- 否,1- 是
        public byte byCustomFaceLibID; //人脸库ID是否是自定义:0- 不是,1- 是
        public byte byRes1; //保留,置为0
        public byte[] byIdentityKey = new byte[64]; //交互操作口令
        public byte[] byRes = new byte[60];  //保留,置为0
    }

    //数据发送输入参数结构体
    public static class NET_DVR_SEND_PARAM_IN extends Structure {
        public Pointer pSendData;             //发送的缓冲区,PicURL == 1 的时候,内存中存储的是 URL 字符串,byUploadModeling == 1 的时候,内存中存储的是 建模base64加密数据
        public int dwSendDataLen;         //发送数据长度,PicURL == 1 的时候,表示的 URL 字符串的长度,byUploadModeling == 1 的时候,表示为建模数据base64后的加密长度
        public NET_DVR_TIME_V30 struTime = new NET_DVR_TIME_V30();   //图片时间
        public byte byPicType;              //图片格式,1-jpg,2-bmp,3-png,4-SWF,5-GIF
        public byte byPicURL;               //图片数据采用URL方式 0-二进制图片数据,1-图片数据走URL方式
        /*是否上传建模数据;
        0-	二进制图片数据方式(pSendData指向二进制图片数据, dwPicDataLen为图片二进制数据长度),
        1-	直接上传建模数据(pSendData指向建模base64加密数据, dwPicDataLen为建模数据base64后的加密长度)。
        注:建模数据采用base64加密方式,选择为建模数据上传后,byPicURL 无需。
        当”/ISAPI/Intelligent/channels/<ID>/faceContrast/capabilities”能力中返回isSupportUploadModeling能力节点时,支持上传建模数据. */
        public byte byUploadModeling;
        public byte byRes1;
        public int dwPicMangeNo;           //图片管理号
        public byte[] sPicName = new byte[NAME_LEN];     //图片名称
        public int dwPicDisplayTime;       //图片播放时长,单位秒
        public Pointer pSendAppendData;       //发送图片的附加信息缓冲区,对应FaceAppendData 的XML描述;
        public int dwSendAppendDataLen;    //发送图片的附加信息数据长度  FaceAppendData  XML的长度;
        public byte[] byRes = new byte[192];
    }

    /**
     * 文件上传结果信息结构体
     */
    public static class NET_DVR_UPLOAD_FILE_RET extends Structure {
        public byte[] sUrl = new byte[MAX_UPLOADFILE_URL_LEN];  //文件上传返回的URL或者ID
        public byte[] byRes = new byte[260];  //保留
    }

    public static class NET_DVR_TIME_V30 extends Structure {
        public short wYear;
        public byte byMonth;
        public byte byDay;
        public byte byHour;
        public byte byMinute;
        public byte bySecond;
        public byte byRes;
        public short wMilliSec;
        public byte[] byRes1 = new byte[2];
    }

    /**
     * 透传接口输入参数结构体
     */
    public static class NET_DVR_XML_CONFIG_INPUT extends Structure {
        public int dwSize; //结构体大小
        public Pointer lpRequestUrl; //请求信令,字符串格式
        public int dwRequestUrlLen; //请求信令长度,字符串长度
        public Pointer lpInBuffer; //输入参数缓冲区,XML/JSON格式
        public int dwInBufferSize; //输入参数缓冲区大小
        public int dwRecvTimeOut; //报文分段个数:0- 无效;  其他- lpInBuffer传入NET_DVR_MIME_UNIT结构体指针,该值即代表结构体个数
        public byte[] byRes = new byte[32]; //保留,置为0
    }

    /**
     * 透传接口输出参数结构体
     */
    public static class NET_DVR_XML_CONFIG_OUTPUT extends Structure {
        public int dwSize; //结构体大小
        public Pointer lpOutBuffer; //输出参数缓冲区,XML/JSON格式,请求信令为“GET”类型时应用层需要事先分配足够大的内存
        public int dwOutBufferSize; //输出参数缓冲区大小(内存大小)
        public int dwReturnedXMLSize; //实际输出的XML/JSON内容大小
        public Pointer lpStatusBuffer; //返回的状态参数(XML/JSON格式:ResponseStatus),获取命令成功时不会赋值,如果不需要,可以置NULL
        public int dwStatusSize; //状态缓冲区大小(内存大小)
        public byte[] byRes = new byte[32]; //保留,置为0
    }

    public static interface FRemoteConfigCallBack extends StdCallCallback {
        public void invoke(int dwType, Pointer lpBuffer, int dwBufLen, Pointer pUserData);
    }

    /*** API函数声明 ***/

    // 初始化SDK,调用其他SDK函数的前提
    boolean NET_DVR_Init();

    /**
     * 启用日志文件写入接口
     *
     * @param bLogEnable 日志的等级(默认为0):0-表示关闭日志,1-表示只输出ERROR错误日志,2-输出ERROR错误信息和DEBUG调试信息,3-输出ERROR错误信息、DEBUG调试信息和INFO普通信息等所有信息
     * @param strLogDir  日志文件的路径,windows默认值为"C:\\SdkLog\\";linux默认值"/home/sdklog/"
     * @param bAutoDel   是否删除超出的文件数,默认值为TRUE
     * @return
     */
    boolean NET_DVR_SetLogToFile(int bLogEnable, String strLogDir, boolean bAutoDel);

    // 返回最后操作的错误码
    int NET_DVR_GetLastError();

    // 释放SDK资源,在程序结束之前调用
    boolean NET_DVR_Cleanup();

    // 登录接口
    int NET_DVR_Login_V40(NET_DVR_USER_LOGIN_INFO pLoginInfo, NET_DVR_DEVICEINFO_V40 lpDeviceInfo);

    // 用户注销
    boolean NET_DVR_Logout(int lUserID);

    // 回调函数申明
    public static interface FLoginResultCallback extends StdCallCallback {

        // 登录状态回调函数
        public int invoke(int lUserID, int dwResult, NET_DVR_DEVICEINFO_V30 lpDeviceinfo, Pointer pUser);
    }

    public static interface FRealDataCallback_V30 extends Callback {
        public void invoke(int lRealHandle, int dwDataType,
                           ByteByReference pBuffer, int dwBufSize, Pointer pUser);
    }

    public static interface FMSGCallBack_V31 extends StdCallCallback {
        public boolean invoke(int lCommand, NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser);
    }

    // 设置网络连接超时时间和连接尝试次数。
    boolean NET_DVR_SetConnectTime(int dwWaitTime, int dwTryTimes);

    // NET_DVR_SetReconnect
    boolean NET_DVR_SetReconnect(int dwInterval, int bEnableRecon);

    /**
     * 上传文件
     *
     * @param lUserID         NET_DVR_Login_V40等登录接口的返回值
     * @param dwUploadType    上传文件类型
     * @param lpInBuffer      输入参数
     * @param dwInBufferSize  输入缓冲区大小
     * @param sFileName       上传文件的路径(包括文件名)
     * @param lpOutBuffer     输出参数
     * @param dwOutBufferSize 输出缓冲区大小
     * @return
     */
    int NET_DVR_UploadFile_V40(int lUserID, int dwUploadType, Pointer lpInBuffer, int dwInBufferSize, String sFileName, Pointer lpOutBuffer, int dwOutBufferSize);

    /**
     * 发送数据
     *
     * @param lUploadHandle    文件上传句柄,NET_DVR_UploadFile_V40的返回值
     * @param pstruSendParamIN 上传的数据内容
     * @param lpOutBuffer      输出参数,保留,置为NULL
     * @return
     */
    int NET_DVR_UploadSend(int lUploadHandle, Pointer pstruSendParamIN, Void lpOutBuffer);


    //启动远程配置
    int NET_DVR_StartRemoteConfig(int lUserID, int dwCommand, Pointer lpInBuffer, int dwInBufferLen, FRemoteConfigCallBack cbStateCallBack, Pointer pUserData);

    int NET_DVR_SendWithRecvRemoteConfig(int lHandle, Pointer lpInBuff, int dwInBuffSize, Pointer lpOutBuff, int dwOutBuffSize, IntByReference dwOutDataLen);

    boolean NET_DVR_StopRemoteConfig(int lHandle);

    //获取设备能力集
    boolean NET_DVR_GetDeviceAbility(int lUserID, int dwAbilityType, Pointer pInBuf, int dwInLength, Pointer pOutBuf, int dwOutLength);

    boolean NET_DVR_SetDVRMessageCallBack_V31(FMSGCallBack_V31 fMessageCallBack, Pointer pUser);

    /**
     * 获取文件上传的进度和状态
     *
     * @param lUploadHandle 文件上传的句柄,NET_DVR_UploadFile_V40的返回值
     * @param pProgress     返回的进度值,0~100
     * @return
     */
    int NET_DVR_GetUploadState(int lUploadHandle, Pointer pProgress);

    /**
     * 获取当前上传的结果信息
     *
     * @param lUploadHandle   文件上传的句柄,NET_DVR_UploadFile_V40的返回值
     * @param lpOutBuffer     结果信息缓冲区
     * @param dwOutBufferSize 缓冲区大小
     * @return
     */
    boolean NET_DVR_GetUploadResult(int lUploadHandle, Pointer lpOutBuffer, int dwOutBufferSize);

    //停止文件上传
    boolean NET_DVR_UploadClose(int lUploadHandle);

    //ISAPI协议命令透传
    boolean NET_DVR_STDXMLConfig(int lUserID, NET_DVR_XML_CONFIG_INPUT lpInputParam, NET_DVR_XML_CONFIG_OUTPUT lpOutputParam);

}

UploadFaceUtil.java

import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author ZWP
 * @date 2022/1/28 14:00
 */
public class UploadFaceUtil {
    HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;

    /**
     * SDK登录
     *
     * @param m_sDeviceIP 设备ip地址
     * @param wPort       端口号,设备网络SDK登录默认端口8000
     * @param m_sUsername 用户名
     * @param m_sPassword 密码
     * @return
     */
    public int login(String m_sDeviceIP, short wPort, String m_sUsername, String m_sPassword) {
        // 初始化
        boolean initSuc = hCNetSDK.NET_DVR_Init();
        if (!initSuc) {
            System.out.println("初始化失败");
            return -1;
        }
        // 打印SDK日志
        hCNetSDK.NET_DVR_SetLogToFile(3, ".\\SDKLog\\", false);
        /* 注册 */
        // 设备登录信息
        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.wPort = wPort;
        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());
        // 是否异步登录:false- 否,true- 是
        m_strLoginInfo.bUseAsynLogin = false;
        // write()调用后数据才写入到内存中
        m_strLoginInfo.write();

        // 设备信息
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
        int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (lUserID == -1) {
            System.out.println("登录失败!,错误码为" + hCNetSDK.NET_DVR_GetLastError());
        } else {
            System.out.println("登录成功!");
            // read()后,结构体中才有对应的数据
            m_strDeviceInfo.read();
        }
        return lUserID;
    }

    /**
     * 设备注销 SDK释放
     */
    public void logout(int lUserID) {
        if (lUserID >= 0) {
            // 注销
            if (!hCNetSDK.NET_DVR_Logout(lUserID)) {
                System.out.println("注销失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
            }
            System.out.println("注销成功");
            // 释放SDK资源
            hCNetSDK.NET_DVR_Cleanup();
        } else {
            System.out.println("设备未登录");
            hCNetSDK.NET_DVR_Cleanup();
        }
    }

    /**
     * 建立图片上传连接
     *
     * @param lUserID 用户句柄(登录的返回值)
     * @param strFDID 人脸库ID(设备自动生成的FDID或者是自定义的customFaceLibID),唯一标识
     */
    public int faceupload(int lUserID, String strFDID) {
        HCNetSDK.NET_DVR_FACELIB_COND struInput = new HCNetSDK.NET_DVR_FACELIB_COND();
        //结构体大小
        struInput.dwSize = struInput.size();
        //设备并发处理:0- 不开启(设备自动会建模),1- 开始(设备不会自动进行建模)
        struInput.byConcurrent = 0;
        //人脸库ID是否是自定义:0- 不是,1- 是
        struInput.byCustomFaceLibID = 0;
        //是否覆盖式导入(人脸库存储满的情况下强制覆盖导入时间最久的图片数据):0- 否,1- 是
        struInput.byCover = 1;
        struInput.szFDID = new byte[HCNetSDK.NET_SDK_MAX_FDID_LEN]; //人脸库ID最大长度 256
        //将指定源数组中的数组从指定位置复制到目标数组的指定位置。
        System.arraycopy(strFDID.getBytes(), 0, struInput.szFDID, 0, strFDID.getBytes().length);
        //数据写入到内存中
        struInput.write();
        // 获取Pointer对象
        Pointer inputPointer = struInput.getPointer();
        // 上传人脸图片
        int uploadFileV40 = hCNetSDK.NET_DVR_UploadFile_V40(lUserID, HCNetSDK.IMPORT_DATA_TO_FACELIB, inputPointer, struInput.size(), null, null, 0);
        if (uploadFileV40 == -1) {
            System.out.println("上传失败!,错误码为" + hCNetSDK.NET_DVR_GetLastError());
        } else {
            System.out.println("上传成功!");
        }
        return uploadFileV40;
    }

    /**
     * 上传图片
     *
     * @param lUploadHandle 文件上传的句柄
     * @param picPath       图片路径
     * @param dataXMLPath   XML文件路径
     */
    public void uploadSend(int lUploadHandle, String picPath, String dataXMLPath) {
        //图片文件
        FileInputStream picfile = null;
        //XML文件(附加消息)
        FileInputStream xmlfile = null;
        int picdataLength = 0;
        int xmldataLength = 0;

        try {
            // 创建文件
            picfile = new FileInputStream(new File(System.getProperty("user.dir") + picPath));
            xmlfile = new FileInputStream(new File(System.getProperty("user.dir") + dataXMLPath));
            // 获取文件的字节数
            picdataLength = picfile.available();
            xmldataLength = xmlfile.available();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (picdataLength < 0 || xmldataLength < 0) {
            System.out.println("上传图片大小/xml文件大小 < 0");
            return;
        }
        HCNetSDK.BYTE_ARRAY ptrpicByte = new HCNetSDK.BYTE_ARRAY(picdataLength);
        HCNetSDK.BYTE_ARRAY ptrxmlByte = new HCNetSDK.BYTE_ARRAY(xmldataLength);
        try {
            // 从内存中读取数据到byte数组
            picfile.read(ptrpicByte.byValue);
            xmlfile.read(ptrxmlByte.byValue);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //数据写入到内存中
        ptrpicByte.write();
        ptrxmlByte.write();

        HCNetSDK.NET_DVR_SEND_PARAM_IN netDvrSendParamIn = new HCNetSDK.NET_DVR_SEND_PARAM_IN();
        //图片格式:1- jpg,2- bmp,3- png,4- SWF,5- GIF
        netDvrSendParamIn.byPicType = 1;
        // 图片管理号,人脸库不支持,设为0
        netDvrSendParamIn.dwPicMangeNo = 0;
        // 图片播放时长,单位:秒,人脸库不支持,设为0
        netDvrSendParamIn.dwPicDisplayTime = 0;
         netDvrSendParamIn.byPicURL = 0;
        // 发送的缓冲区,PicURL == 1 的时候,内存中存储的是 URL 字符串,byUploadModeling == 1 的时候,内存中存储的是 建模base64加密数据
        netDvrSendParamIn.pSendData = ptrpicByte.getPointer();
        // 发送数据长度,PicURL == 1 的时候,表示的 URL 字符串的长度,byUploadModeling == 1 的时候,表示为建模数据base64后的加密长度
        netDvrSendParamIn.dwSendDataLen = picdataLength;
        // 发送图片的附加信息缓冲区,对应FaceAppendData 的XML描述;
        netDvrSendParamIn.pSendAppendData = ptrxmlByte.getPointer();
        // 发送图片的附加信息数据长度  FaceAppendData XML的长度;
        netDvrSendParamIn.dwSendAppendDataLen = xmldataLength;
        //数据写入到内存中
        netDvrSendParamIn.write();

        // 发送数据
        int dvrUploadSend = hCNetSDK.NET_DVR_UploadSend(lUploadHandle, netDvrSendParamIn.getPointer(), null);
        if (dvrUploadSend == -1) {
            System.out.println("发送数据失败!,错误码为" + hCNetSDK.NET_DVR_GetLastError());
            return;
        } else {
            System.out.println("发送数据成功!");
        }
        // 关闭流
        try {
            picfile.close();
            xmlfile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取上传状态和进度
     *
     * @param lUploadHandle 文件上传的句柄
     */
    public int getUploadState(int lUploadHandle) throws InterruptedException {
        Thread.sleep(500);
        // 原生整型引用
        IntByReference pInt = new IntByReference(0);
        int netDvrGetUploadState = hCNetSDK.NET_DVR_GetUploadState(lUploadHandle, pInt.getPointer());
        switch (netDvrGetUploadState) {
            case -1:
                System.out.println("获取文件上传的进度和状态失败!,错误码为" + hCNetSDK.NET_DVR_GetLastError());
                break;
            case 1:
                System.out.println("progress = " + pInt.getValue());
                System.out.println("获取文件上传的进度和状态成功!");
                break;
            case 2:
                System.out.println("正在上传!!!!  progress = " + pInt.getValue());
                break;
            default:
                System.out.println("获取文件上传的进度和状态失败!,接口返回值为 = " + netDvrGetUploadState);
                System.out.println("获取文件上传的进度和状态失败!,错误码为" + hCNetSDK.NET_DVR_GetLastError());
                break;
        }
        return netDvrGetUploadState;
    }

    /**
     * 获取结果信息(图片ID等)
     *
     * @param lUploadHandle 文件上传的句柄
     */
    public String getUploadResult(int lUploadHandle) {
        // 图片ID
        String picID = null;
        // 文件上传结果信息结构体
        HCNetSDK.NET_DVR_UPLOAD_FILE_RET netDvrUploadFileRet = new HCNetSDK.NET_DVR_UPLOAD_FILE_RET();
        // 数据写入到内存中
        netDvrUploadFileRet.write();
        // 获取结果信息
        if (!hCNetSDK.NET_DVR_GetUploadResult(lUploadHandle, netDvrUploadFileRet.getPointer(), netDvrUploadFileRet.size())) {
            System.out.println("获取结果信息失败!,错误码为" + hCNetSDK.NET_DVR_GetLastError());
        } else {
            // 从内存中读取数据
            netDvrUploadFileRet.read();
            // 文件上传返回的URL或者ID
            picID = String.valueOf(netDvrUploadFileRet.sUrl).trim();
            System.out.println("图片上传成功 PicID:" + picID);
        }
        return picID;
    }
}

UploadFace.java

/**
 * @author ZWP
 * @date 2022/1/28 13:58
 */
public class UploadFace {
    static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    static int lUserID = -1;//用户句柄
    static int m_lUploadHandle = -1;//文件上传句柄
    static int m_UploadStatus = -1;//上传进度值

    public static void main(String[] args) throws InterruptedException {
        UploadFaceUtil uploadFaceUtil = new UploadFaceUtil();
        // 用户登陆操作==初始化==打印SDK日志
        lUserID = uploadFaceUtil.login("192.168.7.43", (short) 8000, "admin", "123456");
        // step1:创建人脸库
        // step2:建立图片上传的长连接
        m_lUploadHandle = uploadFaceUtil.faceupload(lUserID, "06CD85AED2FE4F82B7FD7C878EDD91BF");
        if (m_lUploadHandle == -1) {
            return;
        }
        // step3:上传图片
        uploadFaceUtil.uploadSend(m_lUploadHandle, "\\pic\\face.jpg", "\\pic\\data.xml");
        // step4:获取上传状态和进度
        m_UploadStatus = uploadFaceUtil.getUploadState(m_lUploadHandle);
        if (m_UploadStatus == 1) {
            // step5:上传成功之后调用NET_DVR_GetUploadResult获取结果信息(图片ID等)。
            String uploadResult = uploadFaceUtil.getUploadResult(m_lUploadHandle);
            System.out.println("PicID:" + uploadResult);
        }
        if (m_UploadStatus >= 3 || m_UploadStatus == -1) {
            System.out.println("m_UploadStatus = " + m_UploadStatus);
            m_lUploadHandle = -1;
        }
        // step6:停止文件上传
        hCNetSDK.NET_DVR_UploadClose(m_lUploadHandle);
        // 线程睡眠5秒钟
        Thread.sleep(5000);
        // step7:用户注销,释放SDK
        uploadFaceUtil.logout(lUserID);
    }
}

data.xml

<FaceAppendData>
    <bornTime>2022-01-28</bornTime>
    <name>张万鹏</name>
    <sex>male</sex>
    <province>11</province>
    <city>01</city>
    <certificateType>officerID</certificateType>
    <certificateNumber>1123123123</certificateNumber>
    <PersonInfoExtendList>
        <PersonInfoExtend>
            <id>1</id>
            <enable>false</enable>
            <name>test1</name>
            <value>test2</value>
        </PersonInfoExtend>
    </PersonInfoExtendList>
</FaceAppendData>
上一篇:实现标准GB/T28181-2016前端设备(Android、Linux)


下一篇:网络视频录像机(NVR)服务器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告