項目總結25:海康威視SDK-Java二次開發-客流量分析


項目總結25:海康威視SDK-Java二次開發-客流量分析

前言

  本來一個很簡單的SDK接口對接,折騰了好久;總結下原因有:

  1. 海康的SDK底層使用C++寫的,我不熟悉C++;
  2. 海康Java源碼示例寫的是一個Swing桌面應用,我需要的是嵌入到web項目;
  3. 海康《設備網絡SDK使用手冊》中的示例是用C++寫的;並且會出現使用手冊和Java源碼示例版本不匹配的情況(用手冊版本高於Java源碼示例版)  

我的需求

  1. 統計一個出入口的實時進出客流量;即將攝像頭產生的數據 抓取出來保存到業務數據庫
  2. SDK版本:6.0.2.35

准備工作

  1. 海康攝像頭iDS-2CD681XYZUV-ABD/C;並已經現場安裝成功;
  2. 海康的SDK,下載地址(win64):https://www.hikvision.com/cn/download_more_570.html;后面用到的全部文檔和參考源碼全部在SDK文檔中

代碼處理

  1. 將SDK開發包【庫文件】里的HCNetSDK.dll、HCCore.dll、PlayCtrl.dll、SuperRender.dll、AudioRender.dll、HCNetSDKCom文件夾、ssleay32.dll、libeay32.dll文件均要加載到程序里面,【HCNetSDKCom文件夾】(包含里面的功能組件dll庫文件)需要和HCNetSDK.dll、HCCore.dll一起加載,放在同一個目錄下(我的事springboot項目,放在resources目錄下),且HCNetSDKCom文件夾名不能修改。
  2. 將路徑:Demo示例\4- Java 開發示例\2-報警布防監聽\AlarmJavaDemo\src\alarmjavademo下的HCNetSDK類植入到項目中;
  3. 修改HCNetSDK類中的HCNetSDK加載的路徑,否則會報無法加載HCNetSDK.dll錯誤;
        HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary("HCNetSDK",
                HCNetSDK.class);
    
    
    改成
    
        String path=(HCNetSDK.class.getResource("/").getPath()).replaceAll("%20", " ").substring(1).replace("/", "\\")+"HCNetSDK.dll";
        HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary(path,
                HCNetSDK.class); 
  4. 寫MemberFlowUploadService類,實現數據的抓取(見業務源碼1);代碼邏輯說明,可參考《設備網絡SDK使用手冊》-編程導引-客流量功模塊的示例說明
  5. 寫MemberFlowUPloadCallBackImpl類,即回調函數(見業務源碼2);回調函數的實現,我參考書hideSDK中的Demo示例\4- Java 開發示例\2-報警布防監聽\AlarmJavaDemo\src\alarmjavademo下的AlarmJavaDemoView類
  6. 控制台結果輸出    
進入回調了
sAlarmType---》lCommand=4355:客流量統計,進入人數:78,離開人數:83, byMode:0, dwRelativeTime:1298991096, dwAbsTime:1298991096
進入回調了
sAlarmType---》lCommand=4355:客流量統計,進入人數:0,離開人數:1, byMode:1, tmStart:20190522163123,tmEnd :20190522163200
進入回調了
sAlarmType---》lCommand=4355:客流量統計,進入人數:79,離開人數:83, byMode:0, dwRelativeTime:1298991115, dwAbsTime:1298991115  

 

源碼分析

源碼1:MemberFlowUploadService類

package com.hs.api.service.haikang.meberflow;

import org.springframework.stereotype.Service;
import java.util.Timer;
import java.util.TimerTask;


@Service
public class MemberFlowUploadService{


    static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    static HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//設備登錄信息
    static HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//設備信息
    static String m_sDeviceIP = "192.168.1.X";//已登錄設備的IP地址
    static String m_sUsername = "XXX";//設備用戶名
    static String m_sPassword = "XXXXXX";//設備密碼
    static short m_sPort = 8000;//端口號

    public  void initMemberFlowUpload(int remainMinuteTime){
        // 初始化
        hCNetSDK.NET_DVR_Init();
        //設置連接時間與重連時間
        hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
        hCNetSDK.NET_DVR_SetReconnect(10000, true);
        // 注冊設備-登錄參數,包括設備地址、登錄用戶、密碼等
        m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
        m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
        System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());
        m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
        System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());
        m_strLoginInfo.wPort = m_sPort;
        m_strLoginInfo.bUseAsynLogin = false; //是否異步登錄:0- 否,1- 是
        m_strLoginInfo.write();
        //設備信息, 輸出參數
        int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo,m_strDeviceInfo);
        System.out.println("lUserID.size-->" + lUserID);
        if(lUserID< 0){
            System.out.println("hCNetSDK.NET_DVR_Login_V30()"+"\n" +hCNetSDK.NET_DVR_GetErrorMsg(null));
            hCNetSDK.NET_DVR_Cleanup();
            return;
        }
        //設置報警回調函數
        hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(new MemberFlowUPloadCallBackImpl(),null );
        //啟用布防-其他報警布防參數不需要設置,不支持
        HCNetSDK.NET_DVR_SETUPALARM_PARAM lpSetupParam = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
        lpSetupParam.dwSize = 0;
        int lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID,lpSetupParam);
        if (lAlarmHandle< 0)
        {
            System.out.println("NET_DVR_SetupAlarmChan_V41 error, %d\n"+hCNetSDK.NET_DVR_GetLastError());
            hCNetSDK.NET_DVR_Logout(lUserID);
            hCNetSDK.NET_DVR_Cleanup();
            return;
        }
        //等待過程中,如果設備上傳報警信息,在報警回調函數里面接收和處理報警信息
        Timer timer = new Timer();// 實例化Timer類
        timer.schedule(new TimerTask() {
            public void run() {
                //撤銷布防上傳通道
                if (! hCNetSDK.NET_DVR_CloseAlarmChan_V30(lAlarmHandle))
                {
                    System.out.println("! hCNetSDK.NET_DVR_CloseAlarmChan_V31(lAlarmHandle)\n"+ hCNetSDK.NET_DVR_GetLastError() +"\n" +hCNetSDK.NET_DVR_GetErrorMsg(null) );
                    hCNetSDK.NET_DVR_Logout(lUserID);
                    hCNetSDK. NET_DVR_Cleanup();
                    return;
                }

                //注銷用戶
                hCNetSDK.NET_DVR_Logout(lUserID);
                //釋放SDK資源
                hCNetSDK.NET_DVR_Cleanup();
                this.cancel();
                System.gc();//主動回收垃圾
            }
        }, remainMinuteTime * 60 * 1000 );// 這里毫秒
    }
}

 

 源碼2:MemberFlowUPloadCallBackImpl類

package com.hs.api.service.haikang.meberflow;

import com.hs.dao.entity.saichang.statistics.StatisticsMemberInOut;
import com.hs.dao.service.impl.saichang.statistics.StatisticsMemberInOutService;
import com.sun.jna.Pointer;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;


public class MemberFlowUPloadCallBackImpl implements HCNetSDK.FMSGCallBack_V31 {

    @Autowired
    private StatisticsMemberInOutService statisticsMemberInOutService;


    @Override
    public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
        System.out.println("進入回調了");
        try {
                String sAlarmType = new String();
                //報警時間
                Date today = new Date();
                DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                String[] sIP = new String[2];

                sAlarmType = new String("lCommand=") + lCommand;
                //lCommand是傳的報警類型
                HCNetSDK.NET_DVR_PDC_ALRAM_INFO strPDCResult = new HCNetSDK.NET_DVR_PDC_ALRAM_INFO();
                strPDCResult.write();
                Pointer pPDCInfo = strPDCResult.getPointer();
                pPDCInfo.write(0, pAlarmInfo.getByteArray(0, strPDCResult.size()), 0, strPDCResult.size());
                strPDCResult.read();

                if (strPDCResult.byMode == 0) {
                    strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATFRAME.class);
                    sAlarmType = sAlarmType + ":客流量統計,進入人數:" + strPDCResult.dwEnterNum + ",離開人數:" + strPDCResult.dwLeaveNum +
                            ", byMode:" + strPDCResult.byMode + ", dwRelativeTime:" + strPDCResult.uStatModeParam.struStatFrame.dwRelativeTime +
                            ", dwAbsTime:" + strPDCResult.uStatModeParam.struStatFrame.dwAbsTime;
                }
                if (strPDCResult.byMode == 1) {
                    strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATTIME.class);
                    //在這里實現數據的保存等業務邏輯,下面注釋的代碼是SDK提供的參考示例

/*                    String strtmStart = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwYear) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMonth) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwDay) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwHour) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMinute) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwSecond);
                    String strtmEnd = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwYear) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMonth) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwDay) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwHour) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMinute) +
                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwSecond);
                    sAlarmType = sAlarmType + ":客流量統計,進入人數:" + strPDCResult.dwEnterNum + ",離開人數:" + strPDCResult.dwLeaveNum +
                            ", byMode:" + strPDCResult.byMode + ", tmStart:" + strtmStart + ",tmEnd :" + strtmEnd;*/
                }
                System.out.println("sAlarmType---》" +sAlarmType);
                //報警類型
                //報警設備IP地址
                sIP = new String(strPDCResult.struDevInfo.struDevIP.sIpV4).split("\0", 2);
                    return true;
            } catch (Exception ex) {
                Logger.getLogger(MemberFlowUPloadCallBackImpl.class.getName()).log(Level.SEVERE, null, ex);
                return false;
            }
    }
}

 其他問題解決

  1. 項目開發沒有問題,最后用maven打包項目時,HCNetSDK的加載出了問題,分析錯誤日志,發現是因為maven打包時進行了test,無法找到HCNetSDK,只要打包時不test就可以了;
  2. windows server 2008 在jdk1.8.0_131下可以加載到HCNetSDK.dll(這里JDK默認在C:\Program Files );  在更新的JDK版本中就不行(這里JDK默認在C:\Program Files (x86))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM