海康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);
}

測試登錄

在這裡插入圖片描述

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
  • 上傳介面調用流程
    在這裡插入圖片描述
    (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>
Tags: