文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java SDK调用 海康网络摄像头 多摄像头同时预览 并取流

2023-08-31 16:22

关注

(修改前言:最近公司需求又对接海康的人脸设备,也就刚刚好有时间重新整理写的这篇博客,看评论也有很多人说有问题 demo无法跑通 小编在这呢 也重新测一遍 也会将一些细节更详细的列出来吗 同时呢  除了之前写的这套方案,小编在这也会再提供一个方案)

写在前面:

最近也遇到了调用海康多个摄像头实现同时预览的需求,不`过官方demo里并没详细的案例,上网查了下资料,也找不到对应的解决方案 ,电话咨询海康技术,没接过,信息没回过。这里就不对海康技术支持多作评价了,废话不多说。上方案!

小编首先整理了文档和获取流程(如图)

然后小编根据这个思路将SDK的Demo流程整个看了一遍,终于发现了问题的所在,接下来直接上代码(个人是根据海康提供的demo进行简单的修改,将部分公共代码给抽了出来,另外小编只用到了预览录制和停止录制功能,解码和其他功能小编没用到,所以小编在这里都干掉了。尽量能简洁易懂就简介易懂,大佬勿喷!仅供参考和提供思路!!!!!!)

1 首先去官网下载海康的demo和文档,地址不知道?没关系 我给你啦!

https://open.hikvision.com/download/5cda567cf47ae80dd41a54b3?type=10

选择立即下载

2  选择java开发示例,然后选择预览回放和下载

 官网的demo示例就在这啦 不过 要注意官方的提示文件 根据上面的注意事项 导入文件到你的项目中

(然后就可以开始进行Demo调试啦)

具体流程如下:

1 初始化设备 并定义一个list集合存储用户句柄 

      public static List lUserIDList = new ArrayList<>();//用户句柄集合         //初始化    private static   void init() {        //SDK初始化,一个程序只需要调用一次        boolean initSuc = hCNetSDK.NET_DVR_Init();        if (initSuc != true) {            System.out.println("初始化失败");        }        //异常消息回调        if (fExceptionCallBack == null) {            fExceptionCallBack = new FExceptionCallBack_Imp();        }        Pointer pUser = null;        if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) {            return;        }        System.out.println("设置异常消息回调成功");        //启动SDK写日志        hCNetSDK.NET_DVR_SetLogToFile(3, "..\\sdkLog\\", false);    }

 2 登陆设备(只是演示和提供思路 具体实现请各位大佬根据实际业务)

登陆一台设备就会返回一个用户句柄也可称登陆句柄,后续调用预览是根据用户句柄来区分和管理的。

唯一注意的是,设备登陆后的返回值需要保存!登陆完后创建保存回调函数的音频数据文件

(注意:你的设备要和你自己的网络在同一个网段!!!!!!!查看电脑的网段 win+R 输入cmd  你的电脑是192.16.0段的 把摄像头的ip地址和网关也改成同段的 不然会报错误码7或错误码8等)

      //登陆    private static void login(){        //存储登陆设备集合        List list = new ArrayList<>();        Device device = new Device();        device.setIp("192.168.1.16"); //改成自己设备的ip 用户名和密码        device.setUserName("admin");        device.setPassWord("Admin123");        Device devic1 = new Device();        device.setIp("192.168.1.17");        device.setUserName("admin");        device.setPassWord("Admin123");        list.add(device);        list.add(devic1);        //登录设备,每一台设备分别登录; 登录句柄是唯一的,可以区分设备        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo;//设备登录信息        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo;//设备信息        for (Device d : list) {            m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息            m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息            String m_sDeviceIP = d.getIp();//设备ip地址            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());            String m_sUsername = d.getUserName();//设备用户名            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());            String m_sPassword = d.getPassWord();//设备密码            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 = 8000; //SDK端口            m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是            m_strLoginInfo.write();            lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);            //将登陆返回的用户句柄保存!(这里很重要 是原先官网没有的,这里保存句柄是为了预览使用)            lUserIDList.add(lUserID);            if (lUserID==-1) {                System.out.println("登录失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());            } else {                System.out.println("设备登录成功! " + "设备序列号:" + new String(m_strDeviceInfo.struDeviceV30.sSerialNumber).trim());                m_strDeviceInfo.read();            }            //保存回调函数的音频数据            VideoDemo.setFile(lUserID);        }    }

3 创建保存回调函数的音频数据文件  同时创建一个map集合 保存对应的文件输出流 键为登陆后返回的用户句柄

  //定义流的map集合 键为用户句柄(也就是你登陆返回的句柄) static Map outputStreamMap = new HashMap(); public static void setFile(int userId) {        file = new File("/Download/" + new Date().getTime() + "(" + userId + ")" + ".mp4");  //保存回调函数的音频数据        if (!file.exists()) {            try {                file.createNewFile();            } catch (Exception e) {                e.printStackTrace();            }        }//            FileOutputStream outputStream=new FileOutputStream(file);        try {            outputStreamMap.put(userId, new FileOutputStream(file));        } catch (FileNotFoundException e) {            e.printStackTrace();        }    }

4 线程run中执行预览代码 通过调用NET_DVR_RealPlay_V40实现预览

   @Override    public void run() {        fRealDataCallBack = null;        if (userId == -1) {            System.out.println("请先注册");            return;        }    HCNetSDK.NET_DVR_PREVIEWINFO strClientInfo = new HCNetSDK.NET_DVR_PREVIEWINFO();        strClientInfo.read();        strClientInfo.hPlayWnd =null;  //窗口句柄,从回调取流不显示一般设置为空        strClientInfo.lChannel = 1;  //通道号        strClientInfo.dwStreamType = 0; //0-主码流,1-子码流,2-三码流,3-虚拟码流,以此类推        strClientInfo.dwLinkMode = 0; //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4- RTP/RTSP,5- RTP/HTTP,6- HRUDP(可靠传输) ,7- RTSP/HTTPS,8- NPQ        strClientInfo.bBlocked = 1;        strClientInfo.write();        if (fRealDataCallBack == null) {            fRealDataCallBack = new FRealDataCallBack();        }        //开启预览        lPlay = hCNetSDK.NET_DVR_RealPlay_V40(userId, strClientInfo, fRealDataCallBack, null);        if (lPlay == -1) {            int iErr = hCNetSDK.NET_DVR_GetLastError();            System.out.println("取流失败" + iErr);            return;        }        System.out.println("取流成功");    }

5 修改回调函数 这里的回调函数参数都是sdk规定好的 在回调中取出集合中对应的流进行文件输出

    static class FRealDataCallBack implements HCNetSDK.FRealDataCallBack_V30 {        //预览回调        public void invoke(int lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, Pointer pUser) {//            System.out.println(lRealHandle + "码流数据回调" + pBuffer + ", 数据类型: " + dwDataType + ", 数据长度:" + dwBufSize + "puser:" + pUser);            long offset = 0;            ByteBuffer buffers = pBuffer.getPointer().getByteBuffer(offset, dwBufSize);            byte[] bytes = new byte[dwBufSize];            buffers.rewind();            buffers.get(bytes);            try {                //根据lRealHandle从map中取出对应的流读取数据                outputStreamMap.get(lRealHandle).write(bytes);            } catch (Exception e) {                e.printStackTrace();            }        }    }

6 开启线程 

   public static void main(String[] args) throws InterruptedException {        if (hCNetSDK == null && playControl == null) {            if (!CreateSDKInstance()) {                System.out.println("Load SDK fail");                return;            }            if (!CreatePlayInstance()) {                System.out.println("Load PlayCtrl fail");                return;            }        }        //linux系统建议调用以下接口加载组件库        if (osSelect.isLinux()) {            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);            //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限            String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1";            String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1";            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());            ptrByteArray1.write();            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());            ptrByteArray2.write();            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());            String strPathCom = System.getProperty("user.dir") + "/lib";            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());            struComPath.write();            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());        }        //初始化        init();        //登陆        login();        // 创建线程池对象指定线程数量        ExecutorService tp = Executors.newFixedThreadPool(2);        VideoDemo video1=new VideoDemo(lUserIDList.get(0), 1);        VideoDemo video2=new VideoDemo(lUserIDList.get(1),1) ;        tp.submit(video1);        tp.submit(video2);    }

以上代码生成的视频在你盘符+Download 文件夹里面去找(如图所示) 

 注意:你现在生成的视频是无法直接查看的 需要用到海康的播放软件解码查看! 啥软件? 我把链接给你啦

https://www.hikvision.com/cn/support/Downloads/Desktop-Application/Hikvision-Player/

插件打开效果如图:

方案一 完整代码:

package com.NetSDKDemo;import Common.osSelect;import com.Device;import com.sun.jna.Native;import com.sun.jna.Pointer;import java.util.ArrayList;import java.util.List;import java.util.Timer;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ClinetDemo {    static HCNetSDK hCNetSDK = null;    static PlayCtrl playControl = null;    static int lUserID = 0;//用户句柄    public static List lUserIDList = new ArrayList<>();//用户句柄    static FExceptionCallBack_Imp fExceptionCallBack;    static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack {        public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {            System.out.println("异常事件类型:" + dwType);            return;        }    }    public static void main(String[] args) throws InterruptedException {        if (hCNetSDK == null && playControl == null) {            if (!CreateSDKInstance()) {                System.out.println("Load SDK fail");                return;            }            if (!CreatePlayInstance()) {                System.out.println("Load PlayCtrl fail");                return;            }        }        //linux系统建议调用以下接口加载组件库        if (osSelect.isLinux()) {            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);            //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限            String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1";            String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1";            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());            ptrByteArray1.write();            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());            ptrByteArray2.write();            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());            String strPathCom = System.getProperty("user.dir") + "/lib";            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());            struComPath.write();            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());        }        //初始化        init();        //登陆        login();        // 创建线程池对象指定线程数量        ExecutorService tp = Executors.newFixedThreadPool(2);        VideoDemo video1=new VideoDemo(lUserIDList.get(0), 1);        VideoDemo video2=new VideoDemo(lUserIDList.get(1),1) ;        tp.submit(video1);        tp.submit(video2);    }    //登陆    private static void login(){        //存储登陆设备集合        List list = new ArrayList<>();        Device device = new Device();        device.setIp("192.168.1.11");        device.setPassWord("admin");        device.setPassWord("123456");        Device device1 = new Device();        device1.setIp("192.168.1.12");        device1.setPassWord("admin");        device1.setPassWord("123456");        list.add(device);        list.add(device1);        //登录设备,每一台设备分别登录; 登录句柄是唯一的,可以区分设备        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo;//设备登录信息        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo;//设备信息        for (Device d : list) {            m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息            m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息            String m_sDeviceIP = d.getIp();//设备ip地址            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());            String m_sUsername = d.getUserName();//设备用户名            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());            String m_sPassword = d.getPassWord();//设备密码            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 = 8000; //SDK端口            m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是            m_strLoginInfo.write();            lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);            //将登陆返回的用户句柄保存!(这里很重要 是原先官网没有的,这里保存句柄是为了预览使用)            lUserIDList.add(lUserID);            if (lUserID==-1) {                System.out.println("登录失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());            } else {                System.out.println("设备登录成功! " + "设备序列号:" + new String(m_strDeviceInfo.struDeviceV30.sSerialNumber).trim());                m_strDeviceInfo.read();            }            //保存回调函数的音频数据            VideoDemo.setFile(lUserID);        }    }    //初始化    private static   void init() {        //SDK初始化,一个程序只需要调用一次        boolean initSuc = hCNetSDK.NET_DVR_Init();        if (initSuc != true) {            System.out.println("初始化失败");        }        //异常消息回调        if (fExceptionCallBack == null) {            fExceptionCallBack = new FExceptionCallBack_Imp();        }        Pointer pUser = null;        if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) {            return;        }        System.out.println("设置异常消息回调成功");        //启动SDK写日志        hCNetSDK.NET_DVR_SetLogToFile(3, "..\\sdkLog\\", false);    }        private static boolean CreateSDKInstance() {        if (hCNetSDK == null) {            synchronized (HCNetSDK.class) {                String strDllPath = "";                try {                    if (osSelect.isWindows())                        //win系统加载库路径                        //strDllPath = System.getProperty("user.dir") + "\\lib\\HCNetSDK.dll";                        strDllPath = "E:\\eclipse2019work\\ClientDemo-NetBeansPro\\HCNetSDK.dll";                    else if (osSelect.isLinux())                        //Linux系统加载库路径                        //  strDllPath = System.getProperty("user.dir") + "/lib/libhcnetsdk.so";                        strDllPath = "/usr/local/lib/libhcnetsdk.so";                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);                } catch (Exception ex) {                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());                    return false;                }            }        }        return true;    }        private static boolean CreatePlayInstance() {        if (playControl == null) {            synchronized (PlayCtrl.class) {                String strPlayPath = "";                try {                    if (osSelect.isWindows())                        //win系统加载库路径                        strPlayPath = System.getProperty("user.dir") + "\\lib\\PlayCtrl.dll";                    else if (osSelect.isLinux())                        //Linux系统加载库路径                        strPlayPath = System.getProperty("user.dir") + "/lib/libPlayCtrl.so";                    playControl = (PlayCtrl) Native.loadLibrary("E:\\eclipse2019work\\ClientDemo-NetBeansPro\\PlayCtrl.dll", PlayCtrl.class);                } catch (Exception ex) {                    System.out.println("loadLibrary: " + strPlayPath + " Error: " + ex.getMessage());                    return false;                }            }        }        return true;    }   //注销设备    public void videoWrite() {        //退出程序时调用,每一台设备分别注销        for (int id : lUserIDList) {            if (hCNetSDK.NET_DVR_Logout(id)) {                System.out.println("注销成功");            }        }        lUserIDList.clear();        //SDK反初始化,释放资源,只需要退出时调用一次        hCNetSDK.NET_DVR_Cleanup();        VideoDemo.outputStreamMap.clear();    }}
package com.NetSDKDemo;import com.sun.jna.Pointer;import com.sun.jna.ptr.ByteByReference;import com.sun.jna.ptr.IntByReference;import java.io.*;import java.lang.reflect.Parameter;import java.nio.ByteBuffer;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.Timer;import static com.NetSDKDemo.ClinetDemo.hCNetSDK;import static com.NetSDKDemo.ClinetDemo.playControl;public class VideoDemo implements Runnable{    Timer Downloadtimer;//下载用定时器    Timer Playbacktimer;//回放用定时器    static FRealDataCallBack fRealDataCallBack;//预览回调函数实现    //定义流的map集合    static Map outputStreamMap = new HashMap();    static int lPlay = -1;  //预览句柄    static File file;    private Integer userId;    private Integer iChannelNo;    public VideoDemo(Integer userId, Integer iChannelNo) {        this.userId = userId;        this.iChannelNo = iChannelNo;    }    @Override    public void run() {        fRealDataCallBack = null;        if (userId == -1) {            System.out.println("请先注册");            return;        }        HCNetSDK.NET_DVR_PREVIEWINFO strClientInfo = new HCNetSDK.NET_DVR_PREVIEWINFO();        strClientInfo.read();        strClientInfo.hPlayWnd = null;  //窗口句柄,从回调取流不显示一般设置为空        strClientInfo.lChannel = iChannelNo;  //通道号        strClientInfo.dwStreamType = 0; //0-主码流,1-子码流,2-三码流,3-虚拟码流,以此类推        strClientInfo.dwLinkMode = 0; //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4- RTP/RTSP,5- RTP/HTTP,6- HRUDP(可靠传输) ,7- RTSP/HTTPS,8- NPQ        strClientInfo.bBlocked = 1;        strClientInfo.write();        if (fRealDataCallBack == null) {            fRealDataCallBack = new FRealDataCallBack();        }        //开启预览        lPlay = hCNetSDK.NET_DVR_RealPlay_V40(userId, strClientInfo, fRealDataCallBack, null);        if (lPlay == -1) {            int iErr = hCNetSDK.NET_DVR_GetLastError();            System.out.println("取流失败" + iErr);            return;        }        System.out.println("取流成功");    }    //创建文件        public static void setFile(int userId) {        file = new File("/Download/" + new Date().getTime() + "(" + userId + ")" + ".mp4");  //保存回调函数的音频数据        if (!file.exists()) {            try {                file.createNewFile();            } catch (Exception e) {                e.printStackTrace();            }        }//            FileOutputStream outputStream=new FileOutputStream(file);        try {            outputStreamMap.put(userId, new FileOutputStream(file));        } catch (FileNotFoundException e) {            e.printStackTrace();        }    }    static class FRealDataCallBack implements HCNetSDK.FRealDataCallBack_V30 {        //预览回调        public void invoke(int lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, Pointer pUser) {            long offset = 0;            ByteBuffer buffers = pBuffer.getPointer().getByteBuffer(offset, dwBufSize);            byte[] bytes = new byte[dwBufSize];            buffers.rewind();            buffers.get(bytes);            try {                //从map中取出对应的流读取数据                outputStreamMap.get(lRealHandle).write(bytes);            } catch (Exception e) {                e.printStackTrace();            }        }    }}

实体类

package com;public class Device {    private String ip;    private String userName;    private String passWord;    public String getIp() {        return ip;    }    public void setIp(String ip) {        this.ip = ip;    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getPassWord() {        return passWord;    }    public void setPassWord(String passWord) {        this.passWord = passWord;    }}

小编的代码目录结构

简单总结:

1 初始化

2 登陆设备 并保存登陆设备的用户句柄

3 创建保存回调函数的音频文件

4 创建map集合 存储对应的文件输出流,键为用户句柄

5 对回调函数进行修改 

(啊啊啊 博主给的代码有时候录制不同步!!!! 博主给的代码没有视频转码代码!!! 别急啦,往下个方案看看啦。注释就都在代码里了,这里就懒得写了哈)

改造后的代码(名字就叫TwoClientDemo)

public class TwoClientDemo {    public static void main(String[] args) throws ExecutionException, InterruptedException {        List devices = addDevice();        TwoVideoDemo video;        CameraInfo cameraInfo;        FutureTask ft;        for (int i = 0; i < devices.size(); i++) {            cameraInfo = new CameraInfo();            cameraInfo.setAddress(devices.get(i).getIp());            cameraInfo.setPort((short) 8000);            cameraInfo.setUserName(devices.get(i).getUserName());            cameraInfo.setPwd(devices.get(i).getPassWord());            video = new TwoVideoDemo(cameraInfo);            ft = new FutureTask<>(video);            new Thread(ft).start();            //模拟录制过程            Thread.sleep(5000);            ft.get();            System.out.println("取流成功");        }//                renderSuccess(result);}    //存储登陆设备集合    public static List addDevice() {        List list = new ArrayList<>();        Device device = new Device();        device.setIp("192.168.1.16"); //改成自己设备的ip 用户名和密码        device.setUserName("admin");        device.setPassWord("Admin123");        list.add(device);//        Device devic1 = new Device();//        device.setIp("192.168.1.17");//        device.setUserName("admin");//        device.setPassWord("Admin123");//        list.add(devic1);        return list;    }}

(值得注意的一点哈!!! 方案二自己改下这里的路径) 

然后线程实现类 改改 回调函数啥也别写了 直接调海康sdk接口取流即可 

线程实现类

public class TwoVideoDemo implements Callable {    //初始化    public static final HCNetSDK INSTANCE = HCNetSDK.INSTANCE;    static HCNetSDK sdk;    private CameraInfo cameraInfo;    public TwoVideoDemo(CameraInfo cameraInfo) {        this.cameraInfo = cameraInfo;    }  @Override    public Result call() throws Exception {        sdk = INSTANCE;        if (!sdk.NET_DVR_Init()) {            System.out.println("初始化失败..................");        }        //创建设备        HCNetSDK.NET_DVR_DEVICEINFO_V30 deInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();        //注册用户设备        Integer id = sdk.NET_DVR_Login_V30(cameraInfo.getAddress(), cameraInfo.getPort(),                cameraInfo.getUserName(), cameraInfo.getPwd(), deInfo);        cameraInfo.setUserId(id);        //判断是否注册成功        if (cameraInfo.getUserId().intValue() < 0) {            System.out.println("注册设备失败 错误码为:"+sdk.NET_DVR_GetLastError());        } else {            System.out.println("注册成功  Id为:      " + cameraInfo.getUserId().intValue());        }        //判断是否获取到设备能力        HCNetSDK.NET_DVR_WORKSTATE_V30 devWork = new HCNetSDK.NET_DVR_WORKSTATE_V30();        if (!sdk.NET_DVR_GetDVRWorkState_V30(cameraInfo.getUserId(), devWork)) {            System.out.println("获取设备能力集失败,返回设备状态失败..............." + "错误码为:" + sdk.NET_DVR_GetLastError());        }        //启动实时预览功能  创建clientInfo对象赋值预览参数        HCNetSDK.NET_DVR_CLIENTINFO clientInfo = new HCNetSDK.NET_DVR_CLIENTINFO();        clientInfo.lChannel = 1;   //设置通道号        clientInfo.lLinkMode = 0;  //TCP取流        clientInfo.sMultiCastIP = null;                   //不启动多播模式        //创建窗口句柄        clientInfo.hPlayWnd = null;        FRealDataCallBack fRealDataCallBack = new FRealDataCallBack();//预览回调函数实现        while (true){            //开启实时预览            Integer key = sdk.NET_DVR_RealPlay_V30(cameraInfo.getUserId(), clientInfo, fRealDataCallBack, null, true);            //判断是否预览成功            if (key.intValue() == -1) {                sdk.NET_DVR_Logout(cameraInfo.getUserId());                sdk.NET_DVR_Cleanup();            System.out.println("预览失败   错误代码为:  " + sdk.NET_DVR_GetLastError());            }            System.out.println("开始预览成功");//            预览成功后 调用接口使视频资源保存到文件中            if (!sdk.NET_DVR_SaveRealData(key, "/Download/" + new Date().getTime()  + ".mp4")) {                sdk.NET_DVR_StopRealPlay(key);                sdk.NET_DVR_Logout(cameraInfo.getUserId());                sdk.NET_DVR_Cleanup();            System.out.println("保存到文件失败 错误码为:  " + sdk.NET_DVR_GetLastError());            }            return Result.success("录制成功",null);        }    }        class FRealDataCallBack implements HCNetSDK.FRealDataCallBack_V30 {        @Override        public void invoke(int lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, Pointer pUser) {        }    }    //停止录制    static void stopRecord(Integer i) {        sdk.NET_DVR_Logout(i);        sdk.NET_DVR_StopRealPlay(i);        sdk.NET_DVR_Cleanup();    }}

Result(公共返回数据类)

package com.NetSDKDemo.comm;public class Result {    private boolean flag;    private Integer code;    private String message;    private Object data;    public Result() {    }    public Result(boolean flag, Integer code, String message, Object data) {        super();        this.flag = flag;        this.code = code;        this.message = message;        this.data = data;    }    public Result(boolean flag, Integer code, String message) {        super();        this.flag = flag;        this.code = code;        this.message = message;    }    public boolean isFlag() {        return flag;    }    public void setFlag(boolean flag) {        this.flag = flag;    }    public Integer getCode() {        return code;    }    public void setCode(Integer code) {        this.code = code;    }    public String getMessage() {        return message;    }    public void setMessage(String message) {        this.message = message;    }    public Object getData() {        return data;    }    public void setData(Object data) {        this.data = data;    }    public static Result success(String msg, Object data) {        return new Result(true, 200, msg, data);    }    public static Result error(String msg) {        return new Result(false, 500, msg, null);    }    public static Result error(String msg, Object data,Integer code) {        return new Result(true, code, msg, data);    }}
CameraInfo实体类
public class CameraInfo {    private String address;    private String userName;    private String pwd;    private short port;    private Integer userId;    private Integer channel;    private Integer key;    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getPwd() {        return pwd;    }    public void setPwd(String pwd) {        this.pwd = pwd;    }    public short getPort() {        return port;    }    public void setPort(short port) {        this.port = port;    }    public Integer getUserId() {        return userId;    }    public void setUserId(Integer userId) {        this.userId = userId;    }    public Integer getChannel() {        return channel;    }    public void setChannel(Integer channel) {        this.channel = channel;    }    public Integer getKey() {        return key;    }    public void setKey(Integer key) {        this.key = key;    }}

结果

解码工具类

public class FormatConverterUtils {        //视频解码配置    //linux下,路径肯定不是这样,是/root/xx这样子//    public String outputPath = "/usr/local/tobaccocasedoc/Download/";//    public String FFMPEG_PATH = "D:ffmpeg-master-latest-win64-gpl\\bin\\"; //linux中,路径为 /root/moch/ffmpeg-4.4-amd64-static/ 你自己在linux服务器上安装的路径    public static String FFMPEG_PATH = "/usr/local/ffmpeg/ffmpeg-git-20220910-amd64-static/"; //linux中,路径为 /root/moch/ffmpeg-4.4-amd64-static/ 你自己在linux服务器上安装的路径        public static void audioConverter(String resourcePath, String targetPath) {        formatConverter(new File(resourcePath), new File(targetPath), false);    }        public static void videoConverter(String resourcePath, String targetPath) {        formatConverter(new File(resourcePath), new File(targetPath), true);    }        public static void formatConverter(File fileInput, File fileOutPut, boolean isVideo) {        fileInput.setExecutable(true);//设置可执行权限        fileInput.setReadable(true);//设置可读权限        fileInput.setWritable(true);//设置可写权限        fileOutPut.setExecutable(true);//设置可执行权限        fileOutPut.setReadable(true);//设置可读权限        fileOutPut.setWritable(true);//设置可写权限        if (null == fileInput || !fileInput.exists()) {            throw new RuntimeException("源文件不存在,请检查源路径");        }        if (null == fileOutPut) {            throw new RuntimeException("转换后的路径为空,请检查转换后的存放路径是否正确");        }        if (!fileOutPut.exists()) {            try {                fileOutPut.createNewFile();            } catch (IOException e) {                System.out.println("转换时新建输出文件失败");            }        }        List commond = new ArrayList();        //输出直接覆盖文件        commond.add("-y");        commond.add("-i");        commond.add(fileInput.getAbsolutePath());        if (isVideo) {            commond.add("-vcodec");            commond.add("libx264");            commond.add("-mbd");            commond.add("0");            commond.add("-c:a");            commond.add("aac");            commond.add("-s");            commond.add("720*720");            commond.add("-threads");  //指定同时启动线程执行数, 经测试到10再大速度几无变化            commond.add("25");            commond.add("-preset");            commond.add("ultrafast");            commond.add("-strict");            commond.add("-2");            commond.add("-pix_fmt");            commond.add("yuv420p");            commond.add("-movflags");            commond.add("faststart");        }        commond.add(fileOutPut.getAbsolutePath());        //执行命令        executeCommand(commond);    }        public static String executeCommand(List commonds) {        if (CollectionUtils.isEmpty(commonds)) {            System.out.println("--- 指令执行失败,因为要执行的FFmpeg指令为空! ---");            return null;        }        LinkedList ffmpegCmds = new LinkedList<>(commonds);        ffmpegCmds.addFirst(FFMPEG_PATH); // 设置ffmpeg程序所在路径        System.out.println("--- 待执行的FFmpeg指令为:---" + ffmpegCmds);        Runtime runtime = Runtime.getRuntime();        Process ffmpeg = null;        try {            // 执行ffmpeg指令            ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c");            builder.command(ffmpegCmds);            ffmpeg = builder.start();            System.out.println("--- 开始执行FFmpeg指令:--- 执行线程名:" + builder.toString());            // 取出输出流和错误流的信息            // 注意:必须要取出ffmpeg在执行命令过程中产生的输出信息,如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时,线程就回阻塞住            PrintStream errorStream = new PrintStream(ffmpeg.getErrorStream());            PrintStream inputStream = new PrintStream(ffmpeg.getInputStream());            errorStream.start();            inputStream.start();            // 等待ffmpeg命令执行完            ffmpeg.waitFor();            // 获取执行结果字符串            String result = errorStream.stringBuffer.append(inputStream.stringBuffer).toString();            // 输出执行的命令信息            String cmdStr = Arrays.toString(ffmpegCmds.toArray()).replace(",", "");            String resultStr = StringUtils.isBlank(result) ? "【异常】" : "正常";            System.out.println("--- 已执行的FFmepg命令: ---" + cmdStr + " 已执行完毕,执行结果: " + resultStr);            return result;        } catch (Exception e) {            System.out.println("--- FFmpeg命令执行出错! --- 出错信息: " + e.getMessage());            return null;        } finally {            if (null != ffmpeg) {                ProcessKiller ffmpegKiller = new ProcessKiller(ffmpeg);                // JVM退出时,先通过钩子关闭FFmepg进程                runtime.addShutdownHook(ffmpegKiller);            }        }    }        static class PrintStream extends Thread {        InputStream inputStream = null;        BufferedReader bufferedReader = null;        StringBuffer stringBuffer = new StringBuffer();        public PrintStream(InputStream inputStream) {            this.inputStream = inputStream;        }        @Override        public void run() {            try {                if (null == inputStream) {                    System.out.println("--- 读取输出流出错!因为当前输出流为空!---");                }                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));                String line = null;                while ((line = bufferedReader.readLine()) != null) {                    System.out.println(line);                    stringBuffer.append(line);                }            } catch (Exception e) {                System.out.println("--- 读取输入流出错了!--- 错误信息:" + e.getMessage());            } finally {                try {                    if (null != bufferedReader) {                        bufferedReader.close();                    }                    if (null != inputStream) {                        inputStream.close();                    }                } catch (IOException e) {                    System.out.println("--- 调用PrintStream读取输出流后,关闭流时出错!---");                }            }        }    }        private static class ProcessKiller extends Thread {        private Process process;        public ProcessKiller(Process process) {            this.process = process;        }        @Override        public void run() {            this.process.destroy();            System.out.println("--- 已销毁FFmpeg进程 --- 进程名: " + process.toString());        }    }        public static MultimediaInfo testMediaInfo(String path) throws EncoderException, MalformedURLException {        MultimediaObject instance;        if (path.startsWith("http")) {            instance = new MultimediaObject(new URL(path));        } else {            instance = new MultimediaObject(new File(path));        }        return instance.getInfo();    }        public static void testFFmpeg(String urlPath) {        ProcessLocator processLocator = new DefaultFFMPEGLocator();        ProcessWrapper ffmpeg = processLocator.createExecutor();        ffmpeg.addArgument("-i");        ffmpeg.addArgument(urlPath);        try {            ffmpeg.execute();            String res = IOUtils.toString(ffmpeg.getErrorStream(), "UTF-8");        } catch (Exception e) {            e.printStackTrace();        } finally {            ffmpeg.destroy();        }    }        public static void codecToMp4(String sourceFile, String distFile, EncoderProgressListener pListener) throws EncoderException {        File source = new File(sourceFile);        File target = new File(distFile);        if (target.exists()) {            target.delete();        }        AudioAttributes audioAttr = new AudioAttributes();        VideoAttributes videoAttr = new VideoAttributes();        EncodingAttributes encodingAttr = new EncodingAttributes();        audioAttr.setChannels(2);        audioAttr.setCodec("aac");        audioAttr.setBitRate(128000);        audioAttr.setSamplingRate(44100);        videoAttr.setCodec("libx264");        videoAttr.setBitRate(2 * 1024 * 1024);        videoAttr.setSize(new VideoSize(1080, 720));        videoAttr.setFaststart(true);        videoAttr.setFrameRate(29);        encodingAttr.setAudioAttributes(audioAttr);        encodingAttr.setVideoAttributes(videoAttr);        encodingAttr.setOutputFormat("mp4");        Encoder encoder = new Encoder();        encoder.encode(new MultimediaObject(source), target, encodingAttr, pListener);    }        public static void codecToMp4WithText(String sourceFile, String distFile, String textWaterMark, EncoderProgressListener pListener) throws EncoderException {        File sourceVideo = new File(sourceFile);        File target = new File(distFile);        if (target.exists()) {            target.delete();        }        DrawtextFilter vf = new DrawtextFilter(textWaterMark, "(w-text_w)/2", "(h-text_h)/2", "宋体", 30.0, new Color("ffffff", "44"));        vf.setShadow(new Color("000000", "44"), 2, 2);        VideoAttributes videoAttributes = new VideoAttributes();        videoAttributes.addFilter(vf);        EncodingAttributes attrs = new EncodingAttributes();        attrs.setVideoAttributes(videoAttributes);        Encoder encoder = new Encoder();        encoder.encode(new MultimediaObject(sourceVideo), target, attrs, pListener);    }//    public static void main(String[] args) throws EncoderException, MalformedURLException {        String videoPath = "D:\\usr\\local\\tobaccocasedoc\\Download\\test(0).mp4";        String wavPath = "D:\\usr\\local\\tobaccocasedoc\\Download\\test(0).mp4";        String mp3Path = "D:\\usr\\local\\tobaccocasedoc\\Download\\result.mp4";        //测试获取视频信息        MultimediaInfo info = testMediaInfo(videoPath);        System.out.println(JSON.toJSONString(info));        //测试音频转码        codecToMp4(wavPath, mp3Path, new EncoderProgressListener() {            @Override            public void sourceInfo(MultimediaInfo info) {                System.out.println(JSON.toJSONString(info));            }            @Override            public void progress(int permil) {                System.out.println(permil);            }            @Override            public void message(String message) {                System.out.println(message);            }        });    }

(注: 因为官方的sdk不定时更新,一些接口参数也可能发生改变 大家可以根据返回的错误码判断错误信息 这篇文章仅供大家参考,如需要和我版本一致的sdk,源码下载类替换就好啦)

源码地址:(晚点上传)

对应的jar和maven需要大佬们自己去找找了

大佬勿喷!!!!!!!!!!!!!!!!!!!!! 写这个博客只是希望可以帮到大家

来源地址:https://blog.csdn.net/qq_46380138/article/details/126634069

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯