[Java]大华录像机SDK用法举例(登录、校时、同步抓图)

2021-07-25 111点热度 0人点赞 0条评论

最近使用大华DVR录像机Java二次开发,使用大华录像机的Java的SDK实现以下功能:

  • 设备初始化
  • 登录
  • 校时
  • 按通道采集图片(可同步采集)
  • 退出
  • SDK资源清理

供有需要的参考

添加依赖

大华DVR的SDK使用了JNA,版本是5.4.0,这个可以在maven中找到,当然也可以直接使用jar,我用的是maven

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

代码

用到了其他的工具类,例如NetSDKLib.java ToolKits.java等,请到官网的SDK示例里复制。

LoginModule.java 实现初始化、登录、退出、获得设备时间、校时等功能

public class LoginModule {

    public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;
    public static NetSDKLib configsdk = NetSDKLib.CONFIG_INSTANCE;

    // 设备信息
    public static NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();

    // 登陆句柄
    public static NetSDKLib.LLong m_hLoginHandle = new NetSDKLib.LLong(0);

    private static boolean bInit = false;
    private static boolean bLogopen = false;

    /**
     * \if ENGLISH_LANG
     * Init
     * \else
     * 初始化
     * \endif
     */
    public static boolean init(NetSDKLib.fDisConnect disConnect, NetSDKLib.fHaveReConnect haveReConnect) {
        bInit = netsdk.CLIENT_Init(disConnect, null);
        if (!bInit) {
            System.out.println("Initialize SDK failed");
            return false;
        }

        // 设置断线重连回调接口,设置过断线重连成功回调函数后,当设备出现断线情况,SDK内部会自动进行重连操作
        // 此操作为可选操作,但建议用户进行设置
        netsdk.CLIENT_SetAutoReconnect(haveReConnect, null);

        //设置登录超时时间和尝试次数,可选
        int waitTime = 5000; //登录请求响应超时时间设置为5S
        int tryTimes = 1;    //登录时尝试建立链接1次
        netsdk.CLIENT_SetConnectTime(waitTime, tryTimes);


        // 设置更多网络参数,NET_PARAM的nWaittime,nConnectTryNum成员与CLIENT_SetConnectTime
        // 接口设置的登录设备超时时间和尝试次数意义相同,可选
        NetSDKLib.NET_PARAM netParam = new NetSDKLib.NET_PARAM();
        netParam.nConnectTime = 10000;      // 登录时尝试建立链接的超时时间
        netParam.nGetConnInfoTime = 3000;   // 设置子连接的超时时间
        netsdk.CLIENT_SetNetworkParam(netParam);

        return true;
    }

    /**
     * \if ENGLISH_LANG
     * CleanUp
     * \else
     * 清除环境
     * \endif
     */
    public static void cleanup() {
        if (bLogopen) {
            netsdk.CLIENT_LogClose();
        }

        if (bInit) {
            netsdk.CLIENT_Cleanup();
        }
    }

    /**
     * \if ENGLISH_LANG
     * Login Device
     * \else
     * 登录设备
     * \endif
     */
    public static boolean login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) {
        //IntByReference nError = new IntByReference(0);
        //入参
        NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstInParam.nPort = m_nPort;
        pstInParam.szIP = m_strIp.getBytes();
        pstInParam.szPassword = m_strPassword.getBytes();
        pstInParam.szUserName = m_strUser.getBytes();
        //出参
        NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstOutParam.stuDeviceInfo = m_stDeviceInfo;
        //m_hLoginHandle = netsdk.CLIENT_LoginEx2(m_strIp, m_nPort, m_strUser, m_strPassword, 0, null, m_stDeviceInfo, nError);
        m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        if (m_hLoginHandle.longValue() == 0) {
            System.err.printf("Login Device[%s] Port[%d]Failed. %s\n", m_strIp, m_nPort, ToolKits.getErrorCodePrint());
        } else {
            System.out.println("Login Success [ " + m_strIp + " ]");
        }

        return m_hLoginHandle.longValue() != 0;
    }

    /**
     * 同步时间
     */
    public static boolean syncDeviceTime() {
        if (m_hLoginHandle.longValue() == 0) {
            return false;
        }
        Calendar calendar = Calendar.getInstance();
        NetSDKLib.NET_TIME netTime = new NetSDKLib.NET_TIME();
        netTime.setTime(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH),
                calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND));
       return netsdk.CLIENT_SetupDeviceTime(m_hLoginHandle, netTime);
    }

    /**
     * 获取时间
     */
    public static String getDeviceTime() {
        if (m_hLoginHandle.longValue() == 0) {
            return "";
        }
        NetSDKLib.NET_TIME netTime2 = new NetSDKLib.NET_TIME();
        netsdk.CLIENT_QueryDeviceTime(m_hLoginHandle, netTime2, 3000);
        return netTime2.toStringTimeEx();
    }

    /**
     * \if ENGLISH_LANG
     * Logout Device
     * \else
     * 登出设备
     * \endif
     */
    public static boolean logout() {
        if (m_hLoginHandle.longValue() == 0) {
            return false;
        }

        boolean bRet = netsdk.CLIENT_Logout(m_hLoginHandle);
        if (bRet) {
            m_hLoginHandle.setValue(0);
        }

        return bRet;
    }
}

CapturePictureModule.java 实现抓图

public class CapturePictureModule {

    /**
     * \if ENGLISH_LANG
     * Local Capture Picture
     * \else
     * 本地抓图
     * \endif
     */
    public static boolean localCapturePicture(NetSDKLib.LLong hPlayHandle, String picFileName) {
                
        if (!LoginModule.netsdk.CLIENT_CapturePictureEx(hPlayHandle, picFileName, NetSDKLib.NET_CAPTURE_FORMATS.NET_CAPTURE_JPEG)) {
            System.err.println("CLIENT_CapturePicture Failed!" + ToolKits.getErrorCodePrint());
            return false;
        } else { 
            System.out.println("CLIENT_CapturePicture success"); 
        }
        return true;
    }
    
    /**
     * \if ENGLISH_LANG
     * Remote Capture Picture
     * \else
     * 远程抓图
     * \endif
     */
    public static boolean remoteCapturePicture(int chn) {
        return snapPicture(chn, 0, 0);
    }
    
    /**
     * \if ENGLISH_LANG
     * Timer Capture Picture
     * \else
     * 定时抓图
     * \endif
     */
    public static boolean timerCapturePicture(int chn) {
        return snapPicture(chn, 1, 2);
    }
    
    /**
     * \if ENGLISH_LANG
     * Stop Timer Capture Picture
     * \else
     * 停止定时抓图
     * \endif
     */
    public static boolean stopCapturePicture(int chn) {
        return snapPicture(chn, -1, 0);
    }
    
    /**
     * \if ENGLISH_LANG
     * Capture Picture (except local capture picture, others all call this interface)
     * \else
     * 抓图 (除本地抓图外, 其他全部调用此接口)
     * \endif
     */
    private static boolean snapPicture(int chn, int mode, int interval) {
        // send caputre picture command to device
        NetSDKLib.SNAP_PARAMS stuSnapParams = new NetSDKLib.SNAP_PARAMS(); 
        stuSnapParams.Channel = chn;  			// channel
        stuSnapParams.mode = mode;    			// capture picture mode
        stuSnapParams.Quality = 3;				// picture quality
        stuSnapParams.InterSnap = interval; 	// timer capture picture time interval
        stuSnapParams.CmdSerial = chn;  			// request serial
        
        IntByReference reserved = new IntByReference(0);
        if (!LoginModule.netsdk.CLIENT_SnapPictureEx(LoginModule.m_hLoginHandle, stuSnapParams, reserved)) {
            System.err.println("CLIENT_SnapPictureEx Failed!" + ToolKits.getErrorCodePrint());
            return false;
        }
//		else {
//			System.out.println("CLIENT_SnapPictureEx success");
//		}
        return true;
    }
    
    /**
     * \if ENGLISH_LANG
     * Set Capture Picture Callback
     * \else
     * 设置抓图回调函数
     * \endif
     */
    public static void setSnapRevCallBack(NetSDKLib.fSnapRev cbSnapReceive){ 
        LoginModule.netsdk.CLIENT_SetSnapRevCallBack(cbSnapReceive, null);
    }
}

DHNetDeviceUtil.java 我自己写的抓图工具类,实现同步抓图。官方给的示例是异步抓图(采用的是callback回调的方式),我需要的是同步,因为我的API要执行抓图功能,并返回抓到的图,这边稍微改造了一下

public class DHNetDeviceUtil {

    private static final Log log = LogFactory.getLog(IndexController.class);

    /**
     * 大华录像机设备初始化(程序启动的时候运行一次)
     */
    public static void dhInit() {
        LoginModule.init((lLoginID, pchDVRIP, nDVRPort, dwUser) -> {
            LoginModule.m_hLoginHandle = new NetSDKLib.LLong(0);
            log.warn("DH Device[" + pchDVRIP + "] Port[" + nDVRPort + "] DisConnected, lLoginID: " + lLoginID.longValue());
        }, (lLoginID, pchDVRIP, nDVRPort, dwUser) -> {
            LoginModule.m_hLoginHandle = lLoginID;
            log.warn("DH Device[" + pchDVRIP + "] Port[" + nDVRPort + "] ReConnected, lLoginID: " + lLoginID.longValue());
        });
    }

    /**
     * 大华录像机设备资源清理(程序关闭时运行一次)
     */
    public static void dhDeInit() {
        LoginModule.cleanup();
    }

    public boolean capturePicture(String ip, int port, String username, String password, List<Integer> channels, File folder) {
        boolean login = LoginModule.m_hLoginHandle.longValue() > 0;
        if (!login) {
            login = LoginModule.login(ip, port, username, password);
            if (login) {//同步时间
                boolean syncDeviceTimeResult = LoginModule.syncDeviceTime();
                log.info("sync device time result: " + syncDeviceTimeResult + ", device time: " + LoginModule.getDeviceTime());
            }
        }
        if (login) {
            log.info("snapPicture started, channels: " + channels.size());
            for (int channel : channels) {
                int byChanNum = channel - 1;
                if (byChanNum >= 0 && byChanNum < LoginModule.m_stDeviceInfo.byChanNum) {
                    byte[] buf = capturePicture(channel, 8);
                    if (buf == null || buf.length == 0) {
                        continue;
                    }
                    ByteArrayInputStream byteArrInput = new ByteArrayInputStream(buf);
                    try {
                        BufferedImage bufferedImage = ImageIO.read(byteArrInput);
                        if (bufferedImage == null) {
                            log.warn("snapPicture error for channel: " + channel + ", buffered image empty.");
                            continue;
                        }

                        long now = System.currentTimeMillis();

//                        if (!useLastImage) {
                            //CmdSerial改成了Channel
                            File file = new File(folder, channel + "_" + now + ".jpg");
                            ImageIO.write(bufferedImage, "jpg", file);
//                            if (histogramFilterData != null) {
//                                imageDatas.put(channel, new ImageData(now, histogramFilterData));
//                            }
                            log.info("snapPicture saved: " + file.getAbsolutePath() + ", file size: " + Utils.formatFileSize(buf.length));
//                        }
                    } catch (IOException e) {
                        log.error("snapPicture error for channel: " + channel + ", file size: " + Utils.formatFileSize(buf.length), e);
                    }
                }
            }
        } else {
            log.error("error login: " + ToolKits.getErrorCodeShow());
            return false;
        }
        return true;
    }

    /**
     * 采集图像
     * @param channel 从1开始,同步返回
     */
    private byte[] capturePicture(int channel, int timeoutInSeconds) {
        LimitedTimeCondition condition = new LimitedTimeCondition(timeoutInSeconds);

        NetSDKLib.fSnapRev m_SnapReceiveCB = (lLoginID, pBuf, RevLen, EncodeType, CmdSerial, dwUser) -> {
            if (pBuf != null && RevLen > 0) {
                byte[] buf = pBuf.getByteArray(0, RevLen);
                if (buf == null || buf.length == 0) {
                    log.warn("snapPicture error for channel: " + (CmdSerial + 1) + ", bytes empty.");
                } else {
                    condition.setContent(buf);
                }
                condition.conditionWasMet();
            } else {
                log.warn("snapPicture error for channel: " + (CmdSerial + 1) + ", bytes empty.");
            }

            condition.conditionWasMet();
        };


        Native.setCallbackThreadInitializer(m_SnapReceiveCB,
                new CallbackThreadInitializer(false, false, "snapPicture callback thread"));
        CapturePictureModule.setSnapRevCallBack(m_SnapReceiveCB);

        CapturePictureModule.remoteCapturePicture(channel - 1);

        if (!condition.waitForConditionToBeMet()) {
            log.warn("timeout while wait for capturePicture callback, channel: " + channel);
        }
        return (byte[]) condition.getContent();
    }

    public void logout() {
        LoginModule.logout();
    }

}

使用到的LimitedTimeCondition.java 采用了CountDownLatch实现异步转同步(Java11以上)

public class LimitedTimeCondition {
    private final CountDownLatch conditionMetLatch;
    private final Integer timeoutSeconds;

    private Object content;

    public LimitedTimeCondition(final Integer timeoutSeconds) {
        conditionMetLatch = new CountDownLatch(1);
        this.timeoutSeconds = timeoutSeconds;
    }

    public boolean waitForConditionToBeMet() {
        try {
            return conditionMetLatch.await(timeoutSeconds, TimeUnit.SECONDS);
        } catch (final InterruptedException e) {
            //被打断了
            return false;
        }
    }

    public void conditionWasMet() {
        conditionMetLatch.countDown();
    }

    public Object getContent() {
        return content;
    }

    public void setContent(Object content) {
        this.content = content;
    }
}

 

 

admin

这个人很懒,什么都没留下

文章评论

*

code