美文网首页
[日常总结] 大华SDK基于Java的二次开发实现Restful

[日常总结] 大华SDK基于Java的二次开发实现Restful

作者: Colors_boy | 来源:发表于2020-12-07 10:35 被阅读0次

最近半个月在对接大华摄像头,要实现摄像头的实时预览、云台控制和截图等功能。在网上找了很多资源也没有找到想要的,所以自己写了工具类。简单陈述一下基于大华的官网SDK实现摄像头的云台控制和抓图。无非就是调用SDK提供的一些函数来实现。

1. 首先先看看大华给的开发流程

image.png

开发可以顺着这个流程图的步骤,就会变得简单明了,开发其他功能也一样,下面是我封装好的工具类。至于一些引用类都是在大华官网的SDK里面。

大华SDK下载点这

  • 云台控制
/**
 * @author : colors
 * @date : 11:04 2020/12/3
 * 云台控制工具类
 */
public class PTZControlUtil {

    // 初始化sdk
    public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;

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

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

    // 网络断线处理
    private static DisConnect disConnect = new DisConnect();

    // 设备连接恢复,实现设备连接恢复接口
    private static HaveReConnect haveReConnect = new HaveReConnect();


    /**
     * 云台控制
     * 向上移动
     *
     * @param m_strIp       ip
     * @param m_nPort       端口
     * @param m_strUser     登录名
     * @param m_strPassword 密码
     * @param nChannelID    通道id 默认为0
     * @param lParam1       默认 0,当有左上或左下等操作时才会传值 (1-8) 
     * @param lParam2       垂直/水平 移动速度 (1-8) 
     */
    public static void upControlPtz(String m_strIp, int m_nPort, String m_strUser, String m_strPassword, int nChannelID, int lParam1, int lParam2) {
        // 初始化
        LoginModule.init(disConnect, haveReConnect);
        // 若未登录,先登录。
        if (m_hLoginHandle.longValue() == 0) {
            login(m_strIp, m_nPort, m_strUser, m_strPassword);
        }
        // 开始向上移动,若超过角度则会变为左右移动
        if (m_hLoginHandle.longValue() != 0) {
            startUpControl(nChannelID, lParam1, lParam2);
        }
        System.out.println("操作完成");
        // 停止移动
        stopUpControl(nChannelID);
        // 退出
        logout();
        System.out.println("退出登录...");
        // 释放资源
        LoginModule.cleanup();

    }

    // 向上
    private static void startUpControl(int nChannelID, int lParam1, int lParam2) {
        if (m_hLoginHandle.longValue() != 0) {
            netsdk.CLIENT_DHPTZControlEx(m_hLoginHandle, nChannelID,
                    NetSDKLib.NET_PTZ_ControlType.NET_PTZ_UP_CONTROL,
                    lParam1, lParam2, 0, 0);
        } else {
            System.err.println("登录句柄不存在!");
        }
    }

    private static void stopUpControl(int nChannelID) {
        netsdk.CLIENT_DHPTZControlEx(m_hLoginHandle, nChannelID,
                NetSDKLib.NET_PTZ_ControlType.NET_PTZ_UP_CONTROL,
                0, 0, 0, 1);
    }


    // 上下左右等其他一些操作只是指令不同 ,此处就省略了


    /**
     * 登录
     *
     * @param m_strIp       ip
     * @param m_nPort       端口号
     * @param m_strUser     账号
     * @param m_strPassword 密码
     * @return 成功则 true
     */
    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_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        System.out.println(netsdk.getClass());
        if (m_hLoginHandle.longValue() == 0) {
            System.err.printf("登录失败!\n", m_strIp, m_nPort, ToolKits.getErrorCodePrint());
        } else {
            System.out.println("登录成功: [ " + m_strIp + " ]");
        }

        return m_hLoginHandle.longValue() == 0 ? false : true;
    }

    /**
     * 退出登录
     */
    private 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;
    }

    // 设备断线回调: 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK会调用该函数
    private static class DisConnect implements NetSDKLib.fDisConnect {
        public void invoke(NetSDKLib.LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) {
            System.out.printf("Device[%s] Port[%d] DisConnect!\n", pchDVRIP, nDVRPort);
        }
    }

    // 网络连接恢复,设备重连成功回调
    // 通过 CLIENT_SetAutoReconnect 设置该回调函数,当已断线的设备重连成功时,SDK会调用该函数
    private static class HaveReConnect implements NetSDKLib.fHaveReConnect {
        public void invoke(NetSDKLib.LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) {
            System.out.printf("ReConnect Device[%s] Port[%d]\n", pchDVRIP, nDVRPort);
        }
    }

2. 抓图功能

先看看官网给的流程图,步骤3 看自己需求来调用函数

image.png

下面是封装好的工具类,可直接食用。

public class CapturePictureUtil {

    private static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;

    private static NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();

    private static NetSDKLib.LLong m_hLoginHandle = new NetSDKLib.LLong(0);

    private static DisConnect disConnect = new DisConnect();

    private static HaveReConnect haveReConnect = new HaveReConnect();

    private static fCaptureReceiveCB m_CaptureReceiveCB = new fCaptureReceiveCB();

    /**
     * 封装抓图方法
     *
     * @param m_strIp       设备ip
     * @param m_nPort       设备端口 
     * @param m_strUser     账号
     * @param m_strPassword 密码
     * @param chn           通道id
     * @param mode          请求一帧  默认 0
     * @param interval      时间单位秒:默认 0 
     */
    public static void capturePicture(String m_strIp, int m_nPort, String m_strUser, String m_strPassword, int chn, int mode, int interval) {

        // 初始化sdk
        LoginModule.init(disConnect, haveReConnect);

        // 登录
        if (m_hLoginHandle.longValue() == 0) {
            login(m_strIp, m_nPort, m_strUser, m_strPassword);
        }
        // 截图
        if (m_hLoginHandle.longValue() != 0) {
            snapPicture(chn, mode, interval);
        }
        try {
            synchronized (fCaptureReceiveCB.class) {
                // 默认等待 3s, 防止设备断线时抓拍回调没有被触发,而导致死等
                fCaptureReceiveCB.class.wait(3000L); 
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("--> " + Thread.currentThread().getName() + " CLIENT_SnapPictureEx Success." + System.currentTimeMillis());
        logout();
        LoginModule.cleanup();
    }

    /*
     * 登录
     */
    public static boolean login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) {

        //入参
        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_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        System.out.println(netsdk.getClass());
        if (m_hLoginHandle.longValue() == 0) {
            System.err.printf("登录失败!\n", m_strIp, m_nPort, ToolKits.getErrorCodePrint());
        } else {
            System.out.println("登录成功: [ " + m_strIp + " ]");

        }

        return m_hLoginHandle.longValue() == 0 ? false : true;
    }

    /**
     * 退出登录
     */
    private 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;
    }

    /**
     * 抓图方法
     *
     * @param chn      通道号
     * @param mode     默认 0
     * @param interval 默认0
     * @return 成功返回ture
     */
    private static boolean snapPicture(int chn, int mode, int interval) {
        setSnapRevCallBack(m_CaptureReceiveCB);
        // 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 = 0;            // request serial

        IntByReference reserved = new IntByReference(0);
        if (!netsdk.CLIENT_SnapPictureEx(m_hLoginHandle, stuSnapParams, reserved)) {
            System.err.printf("CLIENT_SnapPictureEx Failed!" + ToolKits.getErrorCodePrint());
            return false;
        } else {
            System.out.println("CLIENT_SnapPictureEx success");
        }
        return true;
    }

    /**
     * 保存图片
     */
    private static class fCaptureReceiveCB implements NetSDKLib.fSnapRev {
        BufferedImage bufferedImage = null;

        public void invoke(NetSDKLib.LLong lLoginID, Pointer pBuf, int RevLen, int EncodeType, int CmdSerial, Pointer dwUser) {
            if (pBuf != null && RevLen > 0) {
                String strFileName = SavePath.getSavePath().getSaveCapturePath();
                System.out.println("strFileName = " + strFileName);
                byte[] buf = pBuf.getByteArray(0, RevLen);
                ByteArrayInputStream byteArrInput = new ByteArrayInputStream(buf);
                try {
                    bufferedImage = ImageIO.read(byteArrInput);
                    if (bufferedImage == null) {
                        return;
                    }
                    ImageIO.write(bufferedImage, "jpg", new File(strFileName));
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    /**
     * 抓图回调函数
     *
     * @param cbSnapReceive
     */
    private static void setSnapRevCallBack(NetSDKLib.fSnapRev cbSnapReceive) {
        netsdk.CLIENT_SetSnapRevCallBack(cbSnapReceive, null);
    }


    // 设备断线回调: 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK会调用该函数
    private static class DisConnect implements NetSDKLib.fDisConnect {
        public void invoke(NetSDKLib.LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) {
            System.out.printf("Device[%s] Port[%d] DisConnect!\n", pchDVRIP, nDVRPort);
        }
    }

    // 网络连接恢复,设备重连成功回调
    // 通过 CLIENT_SetAutoReconnect 设置该回调函数,当已断线的设备重连成功时,SDK会调用该函数
    private static class HaveReConnect implements NetSDKLib.fHaveReConnect {
        public void invoke(NetSDKLib.LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) {
            System.out.printf("ReConnect Device[%s] Port[%d]\n", pchDVRIP, nDVRPort);
        }
    }

结果:


image.png

更新

记录一下踩到的坑:大华SDK部署在windows 环境和 Linux环境不一样,在Linux环境中需要从环境变量里面去加载库文件且 NetSDKLib 接口中的 fDisConnect 继承的类不一样,需要更换,不然会报异常:lang.IllegalArgumentException:Invalid calling convention 63。

注意资源的释放、登录和登出。

欢迎留言交流,你的关注是对我最大的支持。

相关文章

网友评论

      本文标题:[日常总结] 大华SDK基于Java的二次开发实现Restful

      本文链接:https://www.haomeiwen.com/subject/afmiwktx.html