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

Posted 心zui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java SDK调用 海康网络摄像头 多摄像头同时预览 并取流相关的知识,希望对你有一定的参考价值。

写在前面:

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

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

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

具体流程如下:

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

   
   public static List<Integer> 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 登陆设备(只是演示和提供思路 具体实现请各位大佬根据实际业务)

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

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

    //设备登陆
    private static void login()

        //存储登陆设备集合
        List<Device> list = new ArrayList<>();
        Device device = new Device();
        device.setIp("192.168.1.11");
        device.userName("admin");
        device.setPassWord("123456");
        Device device1 = new Device();
        device1.setIp("192.168.1.12");
        device1.userName("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);

        
    


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

  //定义流的map集合 键为用户句柄(也就是你登陆返回的句柄)
 static Map<Integer, FileOutputStream> 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 = 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("取流成功");
    

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);
    

效果如图:

完整代码:

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;

/**
 * @create 2020-12-24-17:55
 */
public class ClinetDemo 


    static HCNetSDK hCNetSDK = null;
    static PlayCtrl playControl = null;
    static int lUserID = 0;//用户句柄
    public static List<Integer> 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<Device> 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);

    

    /**
     * 动态库加载
     *
     * @return
     */
    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;
    

    /**
     * 播放库加载
     *
     * @return
     */
    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;

/**
 * 视频取流预览,下载,抓图
 *
 * @create 2022-03-30-9:48
 */
public class VideoDemo implements Runnable
    Timer Downloadtimer;//下载用定时器
    Timer Playbacktimer;//回放用定时器
    static FRealDataCallBack fRealDataCallBack;//预览回调函数实现
    //定义流的map集合
    static Map<Integer, FileOutputStream> 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("取流成功");
    



    //创建文件
    /**
     *
     *
     * @date 2022/8/31 23:37
     * @param userId:登陆返回的用户句柄
     */
    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;

/**
 * @author lws
 * @date 2022/8/31 23:07
 */
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 对回调函数进行修改 

(小编整理后的第二种思路)

VideoDemo类修改 实现Callable接口 回调函数可以什么都不写 直接调海康实时预览接口 预览成功后生成对应视频文件即可(视频需要解码后才可观看,视频想直接看的话需要使用海康提供的视频播放器打开)。

public class VideoDemo implements Callable<Result> 
    @Inject
    private LawCaseInfoService lawCaseInfoService;

    static FRealDataCallBack fRealDataCallBack;//预览回调函数实现
    static List<Integer> lPlayList = new ArrayList<>();
    static int lPlay;  //预览句柄
    static File file;
    //定义流的map集合
    static Map<Integer, FileOutputStream> outputStreamMap = new HashMap();
    static Map<String, List<Integer>> keyMap = new HashMap<>();
    static IntByReference m_lPort = new IntByReference(-1);
   static StringBuffer buffer =new StringBuffer();
   static HCNetSDK sdk;


    private CameraInfo cameraInfo;

    private String caseNum;

    public Video(Device device,String caseNum) 
        this.Device = device;
        this.caseNum =caseNum;
    
    @Override
    public Result call() throws Exception 
        sdk = HCNetSDK.INSTANCE;
        //设置设备通道号   查看Demo代码  通道号为1
//        Integer channel = 1;
//        cameraInfo.setChannel(channel);
        //初始化HCNetSDK接口 实例化对象
        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) 
            return Result.error("注册设备失败 错误码为:"+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();
                return Result.error("预览失败,错误码为:"+sdk.NET_DVR_GetLastError());
//            System.out.println("预览失败   错误代码为:  " + sdk.NET_DVR_GetLastError());
            

            System.out.println("开始预览成功");


          
            //预览成功后 调用接口使视频资源保存到文件中
            if (!sdk.NET_DVR_SaveRealData(key, "你自己的视频存放路径.mp4")) 
                sdk.NET_DVR_StopRealPlay(key);
                sdk.NET_DVR_Logout(device.getUserId()); //这里报红 实体类就自己加下这个UserId就好了
                sdk.NET_DVR_Cleanup();
                return Result.error("保存文件失败 错误码为:"+sdk.NET_DVR_GetLastError());
//            System.out.println("保存到文件失败 错误码为:  " + sdk.NET_DVR_GetLastError());
            
            return Result.success("录制成功",null);
        
//
//        try 
//            Thread.sleep(999999);
//         catch (Exception e) 
//
//            e.printStackTrace();
//        
        //上面设置的睡眠时间可以当做拍摄时长来使用,然后调用结束预览,注销用户,释放资源就可以了
//        sdk.NET_DVR_StopRealPlay(key);
//        sdk.NET_DVR_Logout(cameraInfo.getUserId());
//        sdk.NET_DVR_Cleanup();
        // 程序运行完毕退出阻塞状态
//        System.exit(0);
//        return null;
    

//    @Override
//    public void run() 
//
//    




    //创建文件,并将文件路径存储进数据库
    public static String setFile(int userId, int i, String caseNum) 
        Parameter p = ParameterService.me.getByCode("DOCUMENTPATH", "FILESAVEPATH");// 存放文件根目录
//        file = new File(p.getRemark() + "/Download/" + caseNum + ")" + "(" + i + ")" + ".mp4");  //保存回调函数的音频数据
        file = new File(p.getRemark() + File.separator + "Download" + File.separator + caseNum + ")" + "(" + i + ")" + ".mp4");  //保存回调函数的音频数据

        System.out.println("存放的路径为" + p.getRemark() + "/Download/" + caseNum + ")" + "(" + i + ")" + ".mp4");
        if (!file.exists()) 
            try 
                file.createNewFile();
                outputStreamMap.put(userId, new FileOutputStream(file));
                return p.getRemark() + File.separator + "Download" + File.separator + caseNum + ")" + "(" + i + ")" + ".mp4";
//                return p.getRemark() + "/" + "Download" + "/" + caseNum + ")" + "(" + i + ")" + ".mp4";
             catch (Exception e) 
                e.printStackTrace();
            
        
        return null;
    

    /**
     * @author lws
     * @date 2022/8/26 16:29
     * @param预览回调接口实现类
     */
    class FRealDataCallBack implements HCNetSDK.FRealDataCallBack_V30 


        @Override
        public void invoke(int lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, Pointer pUser) 

        
    

Result(公共返回数据类)

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);
        

最后Main方法自己改下实现方式就🆗了 这次时间紧 修改的急 就大概说下 有时间了 我再详细将代码整理下

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

以上是关于Java SDK调用 海康网络摄像头 多摄像头同时预览 并取流的主要内容,如果未能解决你的问题,请参考以下文章

海康8600平台提示RTSP返回状态失败

海康摄像SDK开发笔记:海康威视网络摄像头SDK介绍与模块功能

海康摄像SDK开发笔记:海康威视网络摄像头SDK介绍与模块功能

RTSP安防网络摄像头/海康大华硬盘录像机网页无插件直播流媒体服务器EasyNVR之鉴权接口的调用配置说明

JavaCV音视频开发宝典:使用javacv读取GB28181海康大华平台和网络摄像头sdk回调视频码流并转码推流rtmp流媒体服务

JavaCV音视频开发宝典:使用javacv读取GB28181海康大华平台和网络摄像头sdk回调视频码流并转码推流rtmp流媒体服务