web实时预览功能开发 java 海康sdk nvr

这篇具有很好参考价值的文章主要介绍了web实时预览功能开发 java 海康sdk nvr。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.实时视频流解决方案

目录

1.实时视频流解决方案

2.步骤

1.搭建rtmp+flv服务器

2.java预览demo

3.实时预览

1.配置海康sdk库文件

2.修改FPREVIEW_NEWLINK_CB代码,推流

3.修改FPREVIEW_DATA_CB代码,取流

4.javacv的推流

3.部分代码

1.启动项目初始化cms,stream的代码

2.cms代码

3.stream代码



1.前端调用后台接口,
2.后台接口调用海康sdk开启具体的摄像头监听,获取摄像头实时流数据
3.建立管道,海康sdk监听线程和javacv推流线程共享管道
4.sdk线程向管道输出流写数据,javacv推流线程向rtmp发送管道数据。即sdk生产者,javacv是消费者
5.nginx+rtmp+flv模块接收到视频流,可以通过http的路径在浏览器访问

前端->后台->海康sdk—>管道->javacv->nginx+rtmp+flv->http路径

2.步骤

1.搭建rtmp+flv服务器

windows系统下,自己编译比较麻烦,这边有大佬编译好的windows中obs+nginx-http-flv-module的流媒体服务搭建_windows nginx集成http-flv_OneCodeSolvesAll的博客-CSDN博客个人编译好的:链接:https://pan.baidu.com/s/1XKkyYvK5W6yZA1w2mPaAfg
提取码:3ug6

linux环境下,下载nginx-http-flv-module(包含nginx-rtmp-module),添加到nginx重载配置就行,网上有很多教程。

如果不需要flv,也可以单独下载nginx-rtmp-module,添加到nginx重载配置。

2.java预览demo

1.登录海康平台海康开放平台

选择硬件产品的isup sdk下载

海康isupsdk,JAVA,java,实时音视频

2.解压之后

海康isupsdk,JAVA,java,实时音视频

 java的这个demo直接打开,修改一下nvr信息,包括ip端口就可以直接预览。

3.实时预览

1.配置海康sdk库文件

海康文档lib文件夹下的文件就是库文件,JavaISUPDemo\lib下也有,需要注意文档是win还是linux版本的。

2.修改FPREVIEW_NEWLINK_CB代码,推流

每当NET_ECMS_StartGetRealStreamV11,开启预览时,FPREVIEW_NEWLINK_CB便会监听到预览请求。

创建管道,分别用于取流推流。异步开始调用javacv的推流方法。

PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
Stream.streamMap.put("stream:"+lLinkHandle,pos);
pos.connect(pis);
CompletableFuture.runAsync(()-> {
    try {
         PushUtil.grabAndPushRtmp(pis,"rtmp://"+rtmphost+"/live/"+userId+"_"+ dwChannelNo);
    } catch (Exception e) {
         e.printStackTrace();
    }
}, Executors.newFixedThreadPool(1));

3.修改FPREVIEW_DATA_CB代码,取流

每当监听到视频流时,将视频流写入pos管道。注意此处不能使用redis,redis会严重影响此处代码性能,导致取流失败。每监听一次,是一个新的线程。第一块注释的代码是调试时使用,调试完之后要删掉。第二块注释代码pos也可以存到map中,使用时从map取,此处直接构造方法传进来也可以。

    public class FPREVIEW_DATA_CB implements HCISUPStream.PREVIEW_DATA_CB {

        private PipedOutputStream pos;
        public FPREVIEW_DATA_CB(PipedOutputStream pos) {
            this.pos = pos;
        }

        //实时流回调函数/
        @Override
        public void invoke(int iPreviewHandle, HCISUPStream.NET_EHOME_PREVIEW_CB_MSG pPreviewCBMsg, Pointer pUserData) throws Exception {
//            if (Count == 500) {//降低打印频率
//                log.info("FPREVIEW_DATA_CB callback, iPreviewHandle:{}", iPreviewHandle);
//                log.info("FPREVIEW_DATA_CB callback, data length:" + pPreviewCBMsg.dwDataLen);
//                Count = 0;
//            }
//            Count++;

            long offset = 0;
            ByteBuffer buffers = pPreviewCBMsg.pRecvdata.getByteBuffer(offset, pPreviewCBMsg.dwDataLen);
            byte[] bytes = new byte[pPreviewCBMsg.dwDataLen];
            buffers.rewind();
            buffers.get(bytes);

            try{
                //2.将数据读入到内存空间,此处不可用redis,否则执行时间是当前10倍
//                PipedOutputStream pos = Stream.streamMap.get("stream:"+iPreviewHandle);
                pos.write(bytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

4.javacv的推流

关于2.提到的javacv推流,linux和windows环境所需要的依赖包不同。

以下,test的是本地windows环境使用的,runtime是线上使用的,可不写,因为默认就是runtime。

<!-- Linux x86_64 使用 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacpp</artifactId>
    <version>1.5.7</version>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>opencv</artifactId>
    <version>4.5.5-1.5.7</version>
    <classifier>linux-x86_64</classifier>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>openblas</artifactId>
    <version>0.3.19-1.5.7</version>
    <classifier>linux-x86_64</classifier>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.0-1.5.7</version>
    <classifier>linux-x86_64</classifier>
    <scope>runtime</scope>
</dependency>
<!-- Windows x86_64 使用 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>opencv</artifactId>
    <version>4.5.5-1.5.7</version>
    <classifier>windows-x86_64</classifier>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>openblas</artifactId>
    <version>0.3.19-1.5.7</version>
    <classifier>windows-x86_64</classifier>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.0-1.5.7</version>
    <classifier>windows-x86_64</classifier>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>1.5.7</version>
    <exclusions>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>

推流代码原理就是,javacv抓取帧,根据帧率算出间隔时间推送到rtmp服务器。

package com.ei.ambulance.util.video;

import org.bytedeco.ffmpeg.avcodec.AVCodecParameters;
import org.bytedeco.ffmpeg.avformat.AVFormatContext;
import org.bytedeco.ffmpeg.avformat.AVStream;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.FFmpegLogCallback;
import org.bytedeco.javacv.Frame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.PipedInputStream;

/**
 * @author willzhao
 * @version 1.0
 * @description 读取指定的mp4文件,推送到SRS服务器
 * @date 2021/11/19 8:49
 */
public class PushUtil {
    private static final Logger log = LoggerFactory.getLogger(PushUtil.class);

    /**
     * 推送到SRS服务器
     *
     * @param pis
     * @param pushAddress 推流地址
     * @throws Exception
     */
    public static void grabAndPushRtmp(PipedInputStream pis, String pushAddress) throws Exception {
        Thread.sleep(500);
        // ffmepg日志级别
        avutil.av_log_set_level(avutil.AV_LOG_ERROR);
        FFmpegLogCallback.set();
        // 实例化帧抓取器对象,将文件路径传入
        // 1.直接以文件形式实例化帧抓取器,此方式可以推送h264,ps码流格式的MP4
//        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(MP4_FILE_PATH);
        // 2.从文件中取流实例化帧抓取器,此方式只能推送ps码流的MP4
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(pis,0);

        long startTime = System.currentTimeMillis();

        log.info("开始初始化帧抓取器");
        // 下面两行设置可加可不加
        grabber.setOption("analyzeduration", "1000000");
//        grabber.setFormat("h264");
        // 初始化帧抓取器,例如数据结构(时间戳、编码器上下文、帧对象等),
        // 如果入参等于true,还会调用avformat_find_stream_info方法获取流的信息,放入AVFormatContext类型的成员变量oc中
        grabber.start(true);
//        grabber.startUnsafe(true); // 也可以使用此方法
        log.info("帧抓取器初始化完成,耗时[{}]毫秒", System.currentTimeMillis()-startTime);

        // grabber.start方法中,初始化的解码器信息存在放在grabber的成员变量oc中
        AVFormatContext avFormatContext = grabber.getFormatContext();

        // 文件内有几个媒体流(一般是视频流+音频流)
        int streamNum = avFormatContext.nb_streams();

        // 没有媒体流就不用继续了
        if (streamNum<1) {
            log.error("文件内不存在媒体流");
            return;
        }

        // 取得视频的帧率
        int frameRate = (int)grabber.getVideoFrameRate();

        log.info("视频帧率[{}],视频时长[{}]秒,媒体流数量[{}]",
                frameRate,
                avFormatContext.duration()/1000000,
                avFormatContext.nb_streams());

        // 遍历每一个流,检查其类型
        for (int i=0; i< streamNum; i++) {
            AVStream avStream = avFormatContext.streams(i);
            AVCodecParameters avCodecParameters = avStream.codecpar();
            log.info("流的索引[{}],编码器类型[{}],编码器ID[{}]", i, avCodecParameters.codec_type(), avCodecParameters.codec_id());
        }

        // 视频宽度
        int frameWidth = grabber.getImageWidth();
        // 视频高度
        int frameHeight = grabber.getImageHeight();
        // 音频通道数量
        int audioChannels = grabber.getAudioChannels();

        log.info("视频宽度[{}],视频高度[{}],音频通道数[{}]",
                frameWidth,
                frameHeight,
                audioChannels);

        // 实例化FFmpegFrameRecorder,将SRS的推送地址传入
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(pushAddress,
                frameWidth,
                frameHeight,
                audioChannels);

        // 设置编码格式
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);

        // 设置封装格式
        recorder.setFormat("flv");

        // 一秒内的帧数
        recorder.setFrameRate(frameRate);

        // 两个关键帧之间的帧数
        recorder.setGopSize(frameRate);

        // 设置音频通道数,与视频源的通道数相等
        recorder.setAudioChannels(grabber.getAudioChannels());

        startTime = System.currentTimeMillis();
        log.info("开始初始化帧抓取器");

        // 初始化帧录制器,例如数据结构(音频流、视频流指针,编码器),
        // 调用av_guess_format方法,确定视频输出时的封装方式,
        // 媒体上下文对象的内存分配,
        // 编码器的各项参数设置
        recorder.start();

        log.info("帧录制初始化完成,耗时[{}]毫秒", System.currentTimeMillis()-startTime);

        Frame frame;

        startTime = System.currentTimeMillis();

        log.info("开始推流");

        long videoTS = 0;

        int videoFrameNum = 0;
        int audioFrameNum = 0;
        int dataFrameNum = 0;

        // 假设一秒钟15帧,那么两帧间隔就是(1000/15)毫秒
        int interVal = 1000/frameRate;
        // 发送完一帧后sleep的时间,不能完全等于(1000/frameRate),不然会卡顿,
        // 要更小一些,这里取八分之一
        interVal/=8;

        // 持续从视频源取帧
        while (null!=(frame=grabber.grab())) {
            videoTS = 1000 * (System.currentTimeMillis() - startTime);

            // 时间戳
            recorder.setTimestamp(videoTS);

            // 有图像,就把视频帧加一
            if (null!=frame.image) {
                videoFrameNum++;
            }

            // 有声音,就把音频帧加一
            if (null!=frame.samples) {
                audioFrameNum++;
            }

            // 有数据,就把数据帧加一
            if (null!=frame.data) {
                dataFrameNum++;
            }

            // 取出的每一帧,都推送到SRS
            recorder.record(frame);

            // 停顿一下再推送
            Thread.sleep(interVal);
        }

        log.info("推送完成,视频帧[{}],音频帧[{}],数据帧[{}],耗时[{}]秒",
                videoFrameNum,
                audioFrameNum,
                dataFrameNum,
                (System.currentTimeMillis()-startTime)/1000);

        // 关闭帧录制器
        recorder.close();
        // 关闭帧抓取器
        grabber.stop();
        grabber.close();
        pis.close();
    }

}

其中,Thread.sleep(500);是必要的。要保证此线程执行到后面代码时,管道中必须存在流,这样开始初始化帧抓取器才能成功。即取流线程必须先于推流线程执行。否则会报错。

3.部分代码

代码中涉及到部分业务代码,按需修改。文章来源地址https://www.toymoban.com/news/detail-573232.html

1.启动项目初始化cms,stream的代码

package com.ei.ambulance;

import com.ei.ambulance.mapper.BreastpieceMapper;
import com.ei.ambulance.mapper.BreastpieceVideoMapper;
import com.ei.ambulance.mapper.TaskDetailMapper;
import com.ei.ambulance.util.RedisUtil;
import com.ei.ambulance.util.cacheMap.CacheMap;
import com.ei.ambulance.util.isup.Cms;
import com.ei.ambulance.util.isup.Stream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author zhangyd
 * @date 2022/9/20
 */
@Component
@Slf4j
@Order(1)
public class ISUPIniter implements CommandLineRunner {

    @Value("${hik.cmsServerIP}")
    String cmsServerIp;

    @Value("${hik.cmsServerPort}")
    String cmsServerPort;

    @Value("${hik.voiceSmsServerIP}")
    String voiceSmsServerIp;

    @Value("${hik.voiceSmsServerPort}")
    String voiceSmsServerPort;

    @Value("${hik.breastpieceVideoPath}")
    String breastpieceVideoPath;

    @Value("${rtmp.rtmphost}")
    private String rtmphost;

    @Value("${hik.smsServerIP}")
    String smsServerIP;

    @Value("${hik.smsServerPort}")
    String smsServerPort;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    BreastpieceMapper breastpieceMapper;

    @Autowired
    TaskDetailMapper taskDetailMapper;

    @Autowired
    BreastpieceVideoMapper breastpieceVideoMapper;

    @Override
    public void run(String... args) throws Exception {
        Cms cms = new Cms();
        cms.redisUtil = redisUtil;
        cms.breastpieceMapper = breastpieceMapper;
        cms.taskDetailMapper = taskDetailMapper;
        cms.breastpieceVideoMapper = breastpieceVideoMapper;
        cms.cMS_Init();
        cms.startCmsListen(cmsServerIp, cmsServerPort, breastpieceVideoPath);

        Stream stream = new Stream();
        stream.eStream_Init();
        stream.startRealPlayListen(smsServerIP, smsServerPort);
        Stream.redisUtil = redisUtil;
        Stream.rtmphost = rtmphost;
        CacheMap.put("stream", stream);
        CacheMap.put("cms", cms);
        redisUtil.deletePattern("video:*");
    }
}

2.cms代码

package com.ei.ambulance.util.isup;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ei.ambulance.mapper.BreastpieceMapper;
import com.ei.ambulance.mapper.BreastpieceVideoMapper;
import com.ei.ambulance.mapper.TaskDetailMapper;
import com.ei.ambulance.model.Breastpiece;
import com.ei.ambulance.model.BreastpieceVideo;
import com.ei.ambulance.model.ambulanceManage.TaskDetail;
import com.ei.ambulance.util.RedisUtil;
import com.ei.ambulance.util.Xml2JsonUtil;
import com.ei.ambulance.util.cacheMap.CacheMap;
import com.ei.ambulance.util.hik.OsSelect;
import com.ei.ambulance.vo.video.VideoFileInfoVo;
import com.ei.ambulance.vo.video.VideoFilesReq;
import com.sun.istack.internal.NotNull;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.DocumentException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author zhangyd
 * @date 2022/9/20
 */
@Slf4j
public class Cms {

    public static Map<String,Integer> userLoginMap  = new HashMap<>();

    public RedisUtil redisUtil;

    public BreastpieceMapper breastpieceMapper;

    public TaskDetailMapper taskDetailMapper;

    public BreastpieceVideoMapper breastpieceVideoMapper;

    public static HCISUPCMS hCEhomeCMS = null;
    //CMS监听句柄
    public static int CmsHandle = -1;
    //注册回调函数实现
    static FRegisterCallBack fRegisterCallBack;
    HCISUPCMS.NET_EHOME_CMS_LISTEN_PARAM struCMSListenPara = new HCISUPCMS.NET_EHOME_CMS_LISTEN_PARAM();


    /**
     * 根据不同操作系统选择不同的库文件和库路径
     *
     * @return
     */
    private static boolean createSDKInstance() {
        if (hCEhomeCMS == null) {
            synchronized (HCISUPCMS.class) {
                String strDllPath = "";
                try {
                    if (OsSelect.isWindows()) {
                        //win系统加载库路径(路径不要带中文)
                        strDllPath = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCISUPCMS.dll";
                    } else if (OsSelect.isLinux()) {
                        //Linux系统加载库路径(路径不要带中文)
                        strDllPath = System.getProperty("user.dir") + "/lib/isupsdkLinux/libHCISUPCMS.so";
                        log.info("===============1{}", strDllPath);
//                        strDllPath = "/usr/soft/java-service/ambulance/lib/isupsdkLinux/libHCISUPCMS.so";
                    }
                    hCEhomeCMS = (HCISUPCMS) Native.loadLibrary(strDllPath, HCISUPCMS.class);
                } catch (Exception ex) {
                    log.info("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * cms服务初始化,开启监听
     *
     * @throws IOException
     */
    public void cMS_Init() throws IOException {

        if (hCEhomeCMS == null) {
            if (!createSDKInstance()) {
                log.info("Load CMS SDK fail");
                return;
            }
        }
        if (OsSelect.isWindows()) {
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCrypto = System.getProperty("user.dir") + "\\lib\\isupsdk\\libeay32.dll"; //Linux版本是libcrypto.so库文件的路径
            System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
            ptrByteArrayCrypto.write();
            hCEhomeCMS.NET_ECMS_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer());

            //设置libssl.so所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathSsl = System.getProperty("user.dir") + "\\lib\\isupsdk\\ssleay32.dll";    //Linux版本是libssl.so库文件的路径
            System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
            ptrByteArraySsl.write();
            hCEhomeCMS.NET_ECMS_SetSDKInitCfg(1, ptrByteArraySsl.getPointer());
            //注册服务初始化
            boolean binit = hCEhomeCMS.NET_ECMS_Init();
            //设置HCAapSDKCom组件库文件夹所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCom = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCAapSDKCom";        //只支持绝对路径,建议使用英文路径
            System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
            ptrByteArrayCom.write();
            hCEhomeCMS.NET_ECMS_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer());

        } else if (OsSelect.isLinux()) {
            //todo linux版本的sdk
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCrypto = System.getProperty("user.dir") + "/lib/isupsdkLinux/libcrypto.so"; //Linux版本是libcrypto.so库文件的路径
            log.info("===============2{}", strPathCrypto);
            System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
            ptrByteArrayCrypto.write();
            hCEhomeCMS.NET_ECMS_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer());

            //设置libssl.so所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathSsl = System.getProperty("user.dir") + "/lib/isupsdkLinux/libssl.so";    //Linux版本是libssl.so库文件的路径
            log.info("===============3{}", strPathSsl);
            System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
            ptrByteArraySsl.write();
            hCEhomeCMS.NET_ECMS_SetSDKInitCfg(1, ptrByteArraySsl.getPointer());
            //注册服务初始化
            boolean binit = hCEhomeCMS.NET_ECMS_Init();
            //设置HCAapSDKCom组件库文件夹所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCom = System.getProperty("user.dir") + "/lib/isupsdkLinux/HCAapSDKCom/";        //只支持绝对路径,建议使用英文路径
            log.info("===============4{}", strPathCom);
            System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
            ptrByteArrayCom.write();
            hCEhomeCMS.NET_ECMS_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer());

        }
        hCEhomeCMS.NET_ECMS_SetLogToFile(3, System.getProperty("user.dir") + "/EHomeSDKLog", false);
    }

    public void startCmsListen(String cmsServerIp, String cmsServerPort, String breastpieceVideoPath) {
        if (fRegisterCallBack == null) {
            fRegisterCallBack = new FRegisterCallBack();
            fRegisterCallBack.ip = cmsServerIp;
            fRegisterCallBack.port = "8007";
            fRegisterCallBack.breastpieceVideoPath = breastpieceVideoPath;
        }
        System.arraycopy(cmsServerIp.getBytes(), 0, struCMSListenPara.struAddress.szIP, 0, cmsServerIp.length());
        struCMSListenPara.struAddress.wPort = Short.parseShort(cmsServerPort);
        struCMSListenPara.fnCB = fRegisterCallBack;
        struCMSListenPara.write();
        //启动监听,接收设备注册信息
        CmsHandle = hCEhomeCMS.NET_ECMS_StartListen(struCMSListenPara);
        if (CmsHandle < -1) {
            log.info("NET_ECMS_StartListen failed, error code:" + hCEhomeCMS.NET_ECMS_GetLastError());
            hCEhomeCMS.NET_ECMS_Fini();
            return;
        }
        String cmsListenInfo = new String(struCMSListenPara.struAddress.szIP).trim() + "_" + struCMSListenPara.struAddress.wPort;
        log.info("注册服务器:" + cmsListenInfo + ",NET_ECMS_StartListen succeed!\n");
    }

    public boolean setHeart(int lUserID, long dwKeepAliveSec, long dwTimeOutCount) {
        boolean result = hCEhomeCMS.NET_ECMS_SetAliveTimeout(lUserID, dwKeepAliveSec, dwTimeOutCount);
        if (result) {
            log.info("device NET_ECMS_SetAliveTimeout success");
        } else {
            log.info("device NET_ECMS_SetAliveTimeout failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
        }
        return result;
    }

    public String channels(int channel, int lUserID) throws DocumentException {
        HCISUPCMS.NET_EHOME_PTXML_PARAM m_struParam = new HCISUPCMS.NET_EHOME_PTXML_PARAM();
        m_struParam.read();
        String url = "GET /ISAPI/ContentMgmt/InputProxy/channels";
        HCISUPCMS.BYTE_ARRAY ptrUrl = new HCISUPCMS.BYTE_ARRAY(1024);
        System.arraycopy(url.getBytes(), 0, ptrUrl.byValue, 0, url.length());
        ptrUrl.write();
        m_struParam.pRequestUrl = ptrUrl.getPointer();
        m_struParam.dwRequestUrlLen = url.length();

        HCISUPCMS.BYTE_ARRAY ptrOutByte = new HCISUPCMS.BYTE_ARRAY(100 * 1024);
        m_struParam.pOutBuffer = ptrOutByte.getPointer();
        m_struParam.dwOutSize = 100 * 1024;
        m_struParam.write();

        if (!hCEhomeCMS.NET_ECMS_ISAPIPassThrough(lUserID, m_struParam)) {
            int iErr = hCEhomeCMS.NET_ECMS_GetLastError();
            log.info("NET_ECMS_ISAPIPassThrough failed, error:{}", iErr);
            m_struParam.read();
            ptrOutByte.read();
            log.info("ptrOutByte:{}", new String(ptrOutByte.byValue).trim());
        }
        String xml = new String(m_struParam.pOutBuffer.getByteArray(0, m_struParam.dwOutSize));
        xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml;
        JSONObject result = Xml2JsonUtil.xml2Json(xml);
        JSONArray jsonArray = result.getJSONArray("inputproxychannel");
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject j = jsonArray.getJSONObject(i);
            if (j.getInteger("id") == channel) {
                return j.getJSONObject("sourceinputportdescriptor").getString("ipaddress");
            }
        }
        return null;
    }

    public List<Integer> cameraList(int lUserID) throws DocumentException {
        HCISUPCMS.NET_EHOME_PTXML_PARAM m_struParam = new HCISUPCMS.NET_EHOME_PTXML_PARAM();
        m_struParam.read();
        String url = "GET /ISAPI/ContentMgmt/InputProxy/channels";
        HCISUPCMS.BYTE_ARRAY ptrUrl = new HCISUPCMS.BYTE_ARRAY(1024);
        System.arraycopy(url.getBytes(), 0, ptrUrl.byValue, 0, url.length());
        ptrUrl.write();
        m_struParam.pRequestUrl = ptrUrl.getPointer();
        m_struParam.dwRequestUrlLen = url.length();

        HCISUPCMS.BYTE_ARRAY ptrOutByte = new HCISUPCMS.BYTE_ARRAY(100 * 1024);
        m_struParam.pOutBuffer = ptrOutByte.getPointer();
        m_struParam.dwOutSize = 100 * 1024;
        m_struParam.write();

        if (!hCEhomeCMS.NET_ECMS_ISAPIPassThrough(lUserID, m_struParam)) {
            int iErr = hCEhomeCMS.NET_ECMS_GetLastError();
            log.info("NET_ECMS_ISAPIPassThrough failed, error:{}", iErr);
            m_struParam.read();
            ptrOutByte.read();
            log.info("ptrOutByte:{}", new String(ptrOutByte.byValue).trim());
        }
        String xml = new String(m_struParam.pOutBuffer.getByteArray(0, m_struParam.dwOutSize));
        xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml;
        JSONObject resultJson = Xml2JsonUtil.xml2Json(xml);
        JSONArray jsonArray = resultJson.getJSONArray("inputproxychannel");
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject j = jsonArray.getJSONObject(i);
            result.add(j.getInteger("id"));
        }
        return result;
    }

    public void playBack(int lUserID, String ip, String port, @NotNull Date start, @NotNull Date end, String fileName, Integer taskId, Integer breastpieceId) {
        HCISUPCMS.NET_EHOME_PLAYBACK_INFO_IN pPlaybackInfoIn = new HCISUPCMS.NET_EHOME_PLAYBACK_INFO_IN();
        pPlaybackInfoIn.read();
        pPlaybackInfoIn.dwSize = pPlaybackInfoIn.size();
        pPlaybackInfoIn.dwChannel = 1;

        pPlaybackInfoIn.byPlayBackMode = 1;
        pPlaybackInfoIn.unionPlayBackMode.setType(HCISUPCMS.NET_EHOME_PLAYBACKBYTIME.class);
        Calendar cal = Calendar.getInstance();
        cal.setTime(start);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.wYear = (short) cal.get(Calendar.YEAR);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byMonth = (byte) (cal.get(Calendar.MONTH) + 1);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byDay = (byte) cal.get(Calendar.DAY_OF_MONTH);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byHour = (byte) cal.get(Calendar.HOUR_OF_DAY);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byMinute = (byte) cal.get(Calendar.MINUTE);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.bySecond = (byte) cal.get(Calendar.SECOND);

        cal.setTime(end);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.wYear = (short) cal.get(Calendar.YEAR);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byMonth = (byte) (cal.get(Calendar.MONTH) + 1);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byDay = (byte) cal.get(Calendar.DAY_OF_MONTH);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byHour = (byte) cal.get(Calendar.HOUR_OF_DAY);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byMinute = (byte) cal.get(Calendar.MINUTE);
        pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.bySecond = (byte) cal.get(Calendar.SECOND);

        System.arraycopy(ip.getBytes(), 0, pPlaybackInfoIn.struStreamSever.szIP, 0, ip.length());
        pPlaybackInfoIn.struStreamSever.wPort = Short.parseShort(port);
        pPlaybackInfoIn.write();
        HCISUPCMS.NET_EHOME_PLAYBACK_INFO_OUT pPlaybackInfoOut = new HCISUPCMS.NET_EHOME_PLAYBACK_INFO_OUT();
        pPlaybackInfoOut.write();
        log.info("NET_ECMS_StartPlayBack接口参数:{}", pPlaybackInfoIn);
        if (hCEhomeCMS.NET_ECMS_StartPlayBack(lUserID, pPlaybackInfoIn, pPlaybackInfoOut)) {
            pPlaybackInfoOut.read();
            log.info("NET_ECMS_StartPlayBack success");
        } else {
            log.info("NET_ECMS_StartPlayBack failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
            return;
        }
        HCISUPCMS.NET_EHOME_PUSHPLAYBACK_IN m_struPushPlayBackIn = new HCISUPCMS.NET_EHOME_PUSHPLAYBACK_IN();
        m_struPushPlayBackIn.read();
        m_struPushPlayBackIn.dwSize = m_struPushPlayBackIn.size();
        m_struPushPlayBackIn.lSessionID = pPlaybackInfoOut.lSessionID;
        m_struPushPlayBackIn.write();

        HCISUPCMS.NET_EHOME_PUSHPLAYBACK_OUT m_struPushPlayBackOut = new HCISUPCMS.NET_EHOME_PUSHPLAYBACK_OUT();
        m_struPushPlayBackOut.read();
        m_struPushPlayBackOut.dwSize = m_struPushPlayBackOut.size();
        m_struPushPlayBackOut.write();
        log.info("NET_ECMS_StartPushPlayBack接口参数:{}", m_struPushPlayBackIn);
        if (hCEhomeCMS.NET_ECMS_StartPushPlayBack(lUserID, m_struPushPlayBackIn, m_struPushPlayBackOut)) {
            log.info("NET_ECMS_StartPushPlayBack success");
            redisUtil.set("downloadHandle:" + m_struPushPlayBackOut.lHandle, fileName);
            BreastpieceVideo breastpieceVideo = new BreastpieceVideo();
            String[] names = fileName.split(OsSelect.isLinux()? "/" : "\\\\");
            breastpieceVideo.setTaskId(taskId);
            breastpieceVideo.setBreastpieceId(breastpieceId);
            breastpieceVideo.setName(names[names.length - 1] + ".mp4");
            breastpieceVideo.setAddress("http://47.101.185.231/ambulance-pc/video/breast/");
            breastpieceVideo.setStartTime(start);
            breastpieceVideo.setEndTime(end);
            breastpieceVideoMapper.insert(breastpieceVideo);
        } else {
            log.info("NET_ECMS_StartPushPlayBack failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
        }

    }

    //注册回调函数
    public class FRegisterCallBack implements HCISUPCMS.DEVICE_REGISTER_CB {
        public String ip, port, breastpieceVideoPath;


        @Override
        public boolean invoke(int lUserID, int dwDataType, Pointer pOutBuffer, int dwOutLen, Pointer pInBuffer, int dwInLen, Pointer pUser) {
            log.info("FRegisterCallBack, dwDataType:" + dwDataType + ", lUserID:" + lUserID);
            HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12 strDevRegInfo;
            Pointer pDevRegInfo;
            if (dwDataType == 0 || dwDataType == 7) {
                strDevRegInfo = new HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12();
                strDevRegInfo.write();
                pDevRegInfo = strDevRegInfo.getPointer();
                pDevRegInfo.write(0, pOutBuffer.getByteArray(0, strDevRegInfo.size()), 0, strDevRegInfo.size());
                strDevRegInfo.read();
                HCISUPCMS.NET_EHOME_SERVER_INFO_V50 strEhomeServerInfo = new HCISUPCMS.NET_EHOME_SERVER_INFO_V50();
                strEhomeServerInfo.read();
                byte[] byCmsIP = new byte[0];
                log.info(new String(byCmsIP));
                String nvrCode = new String(strDevRegInfo.struRegInfo.byDeviceID).trim();
                String nvrIp = new String(strDevRegInfo.struRegInfo.struDevAdd.szIP).trim();
                log.info("Device online, DeviceID is:" + nvrCode);
                log.info("Device online, DeviceIP is:" + nvrIp);
                // 设备注册上线标志
                userLoginMap.put(nvrCode,lUserID);
                redisUtil.set("ip:" + nvrCode, nvrIp);
                redisUtil.set("lUserID:" + nvrCode, lUserID);
                redisUtil.set("carNo:" + lUserID, nvrCode);
                if (nvrCode.startsWith("xp")) {
                    UpdateWrapper<Breastpiece> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.eq("name", nvrCode);
                    Breastpiece breastpiece = new Breastpiece();
                    breastpiece.setIsOnline(1);
                    breastpieceMapper.update(breastpiece, updateWrapper);
                    QueryWrapper<Breastpiece> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("name", nvrCode);
                    Breastpiece breastpieceL = breastpieceMapper.selectOne(queryWrapper);
                    //异步配置心跳监听。100秒没有收到心跳,设备离线
                    ExecutorService executorService = Executors.newSingleThreadExecutor();
                    executorService.submit(() -> {
                        try {
                            Thread.sleep(2000);
                            boolean heart = hCEhomeCMS.NET_ECMS_SetAliveTimeout(lUserID, 100L, 1L);
                            if (heart) {
                                log.info("device {} NET_ECMS_SetAliveTimeout success", nvrCode);
                            } else {
                                log.info("device {} NET_ECMS_SetAliveTimeout failed, error code: {}", nvrCode, hCEhomeCMS.NET_ECMS_GetLastError());
                            }
                            Stream stream = CacheMap.get("stream");

                            stream.startListenPlayBack(ip, port);
                            List<TaskDetail> taskList = taskDetailMapper.selectListByDeviceCode(nvrCode);
                            if (taskList != null && taskList.size() > 0) {
                                taskList.forEach(t -> {
                                    QueryWrapper<BreastpieceVideo> wrapper = new QueryWrapper<>();
                                    wrapper.eq("task_id", t.getId());
                                    Integer c = breastpieceVideoMapper.selectCount(wrapper);
                                    if (c <= 0) {
                                        playBack(lUserID, "47.101.185.231", port, t.getReceiveTime(), t.getDeliveryTime(), breastpieceVideoPath + t.getId(), t.getId(), breastpieceL.getId());
                                    }
                                });
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    });
                    executorService.shutdown();
                }
                return true;
            } else if (dwDataType == 3) {
                strDevRegInfo = new HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12();
                strDevRegInfo.write();
                pDevRegInfo = strDevRegInfo.getPointer();
                pDevRegInfo.write(0, pOutBuffer.getByteArray(0, strDevRegInfo.size()), 0, strDevRegInfo.size());
                strDevRegInfo.read();
                String szEHomeKey = "12345678";
                byte[] bs = szEHomeKey.getBytes();
                pInBuffer.write(0, bs, 0, szEHomeKey.length());
            } else if (dwDataType == 4) {
                strDevRegInfo = new HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12();
                strDevRegInfo.write();
                pDevRegInfo = strDevRegInfo.getPointer();
                pDevRegInfo.write(0, pOutBuffer.getByteArray(0, strDevRegInfo.size()), 0, strDevRegInfo.size());
                strDevRegInfo.read();

                log.info("byDeviceID:" + new String(strDevRegInfo.struRegInfo.byDeviceID).trim());
                log.info("bySessionKey:" + new String(strDevRegInfo.struRegInfo.bySessionKey).trim());

                HCISUPCMS.NET_EHOME_DEV_SESSIONKEY struSessionKey = new HCISUPCMS.NET_EHOME_DEV_SESSIONKEY();
                System.arraycopy(strDevRegInfo.struRegInfo.byDeviceID, 0, struSessionKey.sDeviceID, 0, strDevRegInfo.struRegInfo.byDeviceID.length);
                System.arraycopy(strDevRegInfo.struRegInfo.bySessionKey, 0, struSessionKey.sSessionKey, 0, strDevRegInfo.struRegInfo.bySessionKey.length);
                struSessionKey.write();

                Pointer pSessionKey = struSessionKey.getPointer();

                hCEhomeCMS.NET_ECMS_SetDeviceSessionKey(pSessionKey);
//                mHCEHomeAlarm.NET_EALARM_SetDeviceSessionKey(pSessionKey);
            } else if (dwDataType == 5) {
                String dasInfo = "{\n" +
                        "    \"Type\":\"DAS\",\n" +
                        "    \"DasInfo\":{\n" +
                        "        \"Address\":\"47.101.185.231\",\n" +
                        "        \"Domain\":\"\",\n" +
                        "        \"ServerID\":\"\",\n" +
                        "        \"Port\":20000,\n" +
                        "        \"UdpPort\":\n" +
                        "    }\n" +
                        "}";
                byte[] bs1 = dasInfo.getBytes();
                pInBuffer.write(0, bs1, 0, dasInfo.length());
            } else if (dwDataType == 1) {
                //设备离线
                String deviceName = redisUtil.get("carNo:" + lUserID);
                log.info("设备{}离线", deviceName);
                if (deviceName.startsWith("xp")) {
                    //胸牌
                    UpdateWrapper<Breastpiece> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.eq("name", deviceName);
                    Breastpiece breastpiece = new Breastpiece();
                    breastpiece.setIsOnline(0);
                    breastpieceMapper.update(breastpiece, updateWrapper);
                }
                redisUtil.delete("carNo:" + lUserID);
                redisUtil.delete("ip:" + deviceName);
                redisUtil.delete("lUserID:" + deviceName);
                userLoginMap.remove(deviceName);
            } else if (dwDataType == 8) {
                //心跳
                log.info("__心跳___");
                log.info("FRegisterCallBack default type:" + dwDataType);
            } else {
                log.info("FRegisterCallBack default type:" + dwDataType);
            }
            return true;
        }
    }

    public List<VideoFileInfoVo> findFile(int lLoginID, VideoFilesReq req) throws InterruptedException {
        List<VideoFileInfoVo> result = new ArrayList<>();
        HCISUPCMS.NET_EHOME_REC_FILE_COND strufindCond = new HCISUPCMS.NET_EHOME_REC_FILE_COND();
        strufindCond.dwChannel = 1;
        strufindCond.dwRecType = 0xff;
        strufindCond.dwStartIndex = 0;
        strufindCond.dwMaxFileCountPer = 10;

        Calendar c = Calendar.getInstance();
        c.setTime(req.getStart());
        strufindCond.struStartTime.wYear = (short) c.get(Calendar.YEAR);
        strufindCond.struStartTime.byMonth = (byte) (c.get(Calendar.MONTH) + 1);
        strufindCond.struStartTime.byDay = (byte) c.get(Calendar.DAY_OF_MONTH);
        strufindCond.struStartTime.byHour = (byte) c.get(Calendar.HOUR_OF_DAY);
        strufindCond.struStartTime.byMinute = (byte) c.get(Calendar.MINUTE);
        strufindCond.struStartTime.bySecond = (byte) c.get(Calendar.SECOND);
        c.setTime(req.getEnd());
        strufindCond.struStopTime.wYear = (short) c.get(Calendar.YEAR);
        strufindCond.struStopTime.byMonth = (byte) (c.get(Calendar.MONTH) + 1);
        strufindCond.struStopTime.byDay = (byte) c.get(Calendar.DAY_OF_MONTH);
        strufindCond.struStopTime.byHour = (byte) c.get(Calendar.HOUR_OF_DAY);
        strufindCond.struStopTime.byMinute = (byte) c.get(Calendar.MINUTE);
        strufindCond.struStopTime.bySecond = (byte) c.get(Calendar.SECOND);

        int lHandle = hCEhomeCMS.NET_ECMS_StartFindFile_V11(lLoginID, 0, strufindCond, strufindCond.size());
        if (lHandle < 0) {
            log.info("NET_ECMS_StartFindFile_V11 failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
        } else {
            log.info("NET_ECMS_StartFindFile_V11 success!");
            while (true) {
                HCISUPCMS.NET_EHOME_REC_FILE struFileInfo = new HCISUPCMS.NET_EHOME_REC_FILE();
                int lRet = hCEhomeCMS.NET_ECMS_FindNextFile_V11(lHandle, struFileInfo, struFileInfo.size());
                if (lRet == 1000) {
                    //保存获取到的文件
                    VideoFileInfoVo vo = new VideoFileInfoVo();
                    vo.setFileName(new String(struFileInfo.sFileName));
                    log.info(vo.getFileName());
                    String fileSize;
                    if (struFileInfo.dwFileSize / 1024 == 0) {
                        fileSize = String.valueOf(struFileInfo.dwFileSize);
                    } else if (struFileInfo.dwFileSize / 1024 > 0 && struFileInfo.dwFileSize / (1024 * 1024) == 0) {
                        fileSize = struFileInfo.dwFileSize / 1024 + "K";
                    } else {
                        fileSize = struFileInfo.dwFileSize / (1024 * 1024) + "M";
                    }
                    vo.setSize(fileSize);
                    vo.setStart(String.format("%04d-%02d-%02d %02d:%02d:%02d", struFileInfo.struStartTime.wYear, struFileInfo.struStartTime.byMonth, struFileInfo.struStartTime.byDay, struFileInfo.struStartTime.byHour, struFileInfo.struStartTime.byMinute, struFileInfo.struStartTime.bySecond));
                    vo.setEnd(String.format("%04d-%02d-%02d %02d:%02d:%02d", struFileInfo.struStopTime.wYear, struFileInfo.struStopTime.byMonth, struFileInfo.struStopTime.byDay, struFileInfo.struStopTime.byHour, struFileInfo.struStopTime.byMinute, struFileInfo.struStopTime.bySecond));
                    result.add(vo);
                } else if (lRet == 1002) {
                    Thread.sleep(5L);
                } else {
                    break;
                }
            }
            hCEhomeCMS.NET_ECMS_StopFindFile(lHandle);

        }
        return result;
    }

}

3.stream代码

package com.ei.ambulance.util.isup;

import com.ei.ambulance.util.RedisUtil;
import com.ei.ambulance.util.hik.HCNetSDK;
import com.ei.ambulance.util.hik.OsSelect;
import com.ei.ambulance.util.video.PushUtil;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;

@Slf4j
public class Stream {
    public static Map<String,PipedOutputStream> streamMap = new HashMap<>();
    public static RedisUtil redisUtil;
    public static String rtmphost;
    public static HCISUPStream hCEhomeStream = null;
    public static PlayCtrl playCtrl = null;
    static int m_lPlayBackLinkHandle = -1;   //回放句柄
    public static int m_lPlayBackListenHandle = -1; //回放监听句柄

    public static int StreamHandle = -1;   //预览监听句柄
    public static Map<String,Integer> sessionMap = new HashMap<>(); //预览sessionID
    public static Map<String,Integer> playHandleMap = new HashMap<>();
    static int backSessionID = -1;  //回放sessionID
    static int Count = 0;
    static int iCount = 0;
    static IntByReference m_lPort = new IntByReference(-1);//回调预览时播放库端口指针

    HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM struPlayBackListen = new HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM();
//    HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG struPreviewListen = new HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG();
    static FPREVIEW_NEWLINK_CB fPREVIEW_NEWLINK_CB;//预览监听回调函数实现
//    static FPREVIEW_DATA_CB fPREVIEW_DATA_CB;//预览回调函数实现
    public static Map<String,FPREVIEW_DATA_CB> dataMap = new HashMap<>();


    static PLAYBACK_NEWLINK_CB fPLAYBACK_NEWLINK_CB; //回放监听回调函数实现
    static PLAYBACK_DATA_CB fPLAYBACK_DATA_CB;   //回放回调实现

    /**
     * 动态库加载
     *
     * @return
     */
    private static boolean CreateSDKInstance() {
        if (hCEhomeStream == null) {
            synchronized (HCISUPStream.class) {
                String strDllPath = "";
                try {
                    if (OsSelect.isWindows())
                        //win系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCISUPStream.dll";

                    else if (OsSelect.isLinux())
                        //Linux系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "/lib/isupsdkLinux/libHCISUPStream.so";
                    hCEhomeStream = (HCISUPStream) Native.loadLibrary(strDllPath, HCISUPStream.class);
                } catch (Exception ex) {
                    log.info("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    public void eStream_Init() {
        if (hCEhomeStream == null) {
            if (!CreateSDKInstance()) {
                log.info("Load Stream SDK fail");
                return;
            } else {
                log.info("Load Stream SDK success");
            }
        }
//        if (playCtrl == null) {
//            if (!CreatePlayInstance()) {
//                log.info("Load PlayCtrl fail");
//                return;
//            } else {
//                log.info("Load PlayCtrl SDK success");
//            }
//
//        }
        if (OsSelect.isWindows()) {
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCrypto = System.getProperty("user.dir") + "\\lib\\isupsdk\\libeay32.dll"; //Linux版本是libcrypto.so库文件的路径
            System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
            ptrByteArrayCrypto.write();
            if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer())) {
                log.info("NET_ESTREAM_SetSDKInitCfg 0 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
            }
            HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathSsl = System.getProperty("user.dir") + "\\lib\\isupsdk\\ssleay32.dll";    //Linux版本是libssl.so库文件的路径
            System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
            ptrByteArraySsl.write();
            if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(1, ptrByteArraySsl.getPointer())) {
                log.info("NET_ESTREAM_SetSDKInitCfg 1 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
            }
            //流媒体初始化
            hCEhomeStream.NET_ESTREAM_Init();
            //设置HCAapSDKCom组件库文件夹所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCom = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCAapSDKCom";      //只支持绝对路径,建议使用英文路径
            System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
            ptrByteArrayCom.write();
            if (!hCEhomeStream.NET_ESTREAM_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer())) {
                log.info("NET_ESTREAM_SetSDKLocalCfg 5 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
            }
            hCEhomeStream.NET_ESTREAM_SetLogToFile(3, System.getProperty("user.dir") + "/EHomeSDKLog", false);
        } else if (OsSelect.isLinux()) {
            //设置libcrypto.so所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCrypto = System.getProperty("user.dir") + "/lib/libcrypto.so"; //Linux版本是libcrypto.so库文件的路径
            System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
            ptrByteArrayCrypto.write();
            if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer())) {
                log.info("NET_ESTREAM_SetSDKInitCfg 0 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
            }
            //设置libssl.so所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathSsl = System.getProperty("user.dir") + "/lib/libssl.so";    //Linux版本是libssl.so库文件的路径
            System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
            ptrByteArraySsl.write();
            if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(1, ptrByteArraySsl.getPointer())) {
                log.info("NET_ESTREAM_SetSDKInitCfg 1 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
            }
            hCEhomeStream.NET_ESTREAM_Init();
            //设置HCAapSDKCom组件库文件夹所在路径
            HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
            String strPathCom = System.getProperty("user.dir") + "/lib/HCAapSDKCom/";      //只支持绝对路径,建议使用英文路径
            System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
            ptrByteArrayCom.write();
            if (!hCEhomeStream.NET_ESTREAM_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer())) {
                log.info("NET_ESTREAM_SetSDKLocalCfg 5 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
            }
            hCEhomeStream.NET_ESTREAM_SetLogToFile(3, System.getProperty("user.dir") + "/EHomeSDKLog", false);
        }

    }

    public void startRealPlayListen(String smsServerListenIP, String smsServerListenPort) {
        //预览监听
        if (fPREVIEW_NEWLINK_CB == null) {
            fPREVIEW_NEWLINK_CB = new FPREVIEW_NEWLINK_CB();
        }
        HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG struPreviewListen = new HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG();
        System.arraycopy(smsServerListenIP.getBytes(), 0, struPreviewListen.struIPAdress.szIP, 0, smsServerListenIP.length());
        struPreviewListen.struIPAdress.wPort = Short.parseShort(smsServerListenPort); //流媒体服务器监听端口
        struPreviewListen.fnNewLinkCB = fPREVIEW_NEWLINK_CB; //预览连接请求回调函数
        struPreviewListen.pUser = null;
        struPreviewListen.byLinkMode = 0; //0- TCP方式,1- UDP方式
        struPreviewListen.write();

        if (StreamHandle < 0) {
            StreamHandle = hCEhomeStream.NET_ESTREAM_StartListenPreview(struPreviewListen);
            if (StreamHandle == -1) {

                System.out.println("NET_ESTREAM_StartListenPreview failed, error code:" + hCEhomeStream.NET_ESTREAM_GetLastError());
                hCEhomeStream.NET_ESTREAM_Fini();
                return;
            } else {
                String StreamListenInfo = new String(struPreviewListen.struIPAdress.szIP).trim() + "_" + struPreviewListen.struIPAdress.wPort;
                System.out.println("流媒体服务:" + StreamListenInfo + ",NET_ESTREAM_StartListenPreview succeed");
            }
        }
    }


    /**
     * 开启预览,
     *
     * @param carId
     * @param lChannel 预览通道号
     */
    public void realPlay(int lLoginId, String carId, int lChannel, String smsServerIP, String smsServerPort) throws Exception {
//        JPanelDemo.jRealWinInit();
        HCISUPCMS.NET_EHOME_PREVIEWINFO_IN_V11 struPreviewIn = new HCISUPCMS.NET_EHOME_PREVIEWINFO_IN_V11();
        struPreviewIn.iChannel = lChannel; //通道号
        struPreviewIn.dwLinkMode = 0; //0- TCP方式,1- UDP方式
        struPreviewIn.dwStreamType = 0; //码流类型:0- 主码流,1- 子码流, 2- 第三码流
        struPreviewIn.struStreamSever.szIP = smsServerIP.getBytes();//流媒体服务器IP地址,公网地址
        struPreviewIn.struStreamSever.wPort = Short.parseShort(smsServerPort); //流媒体服务器端口,需要跟服务器启动监听端口一致
        struPreviewIn.write();
        //预览请求
        HCISUPCMS.NET_EHOME_PREVIEWINFO_OUT struPreviewOut = new HCISUPCMS.NET_EHOME_PREVIEWINFO_OUT();
        boolean getRS = Cms.hCEhomeCMS.NET_ECMS_StartGetRealStreamV11(lLoginId, struPreviewIn, struPreviewOut);
//        boolean getRS = Cms.hCEhomeCMS.NET_ECMS_StartGetRealStream(Cms.lLoginID, struPreviewIn, struPreviewOut);
        //Thread.sleep(10000);
        if (!getRS) {
            log.error("NET_ECMS_StartGetRealStream failed, error code:{}", Cms.hCEhomeCMS.NET_ECMS_GetLastError());
            throw new Exception("摄像头不存在");
        } else {
            struPreviewOut.read();
            log.info("NET_ECMS_StartGetRealStream succeed, sessionID:{}", struPreviewOut.lSessionID);
            sessionMap.put("session:"+carId+"_"+lChannel,struPreviewOut.lSessionID);
        }
        HCISUPCMS.NET_EHOME_PUSHSTREAM_IN struPushInfoIn = new HCISUPCMS.NET_EHOME_PUSHSTREAM_IN();
        struPushInfoIn.read();
        struPushInfoIn.dwSize = struPushInfoIn.size();
        struPushInfoIn.lSessionID = sessionMap.get("session:"+carId+"_"+lChannel);
        struPushInfoIn.write();
        HCISUPCMS.NET_EHOME_PUSHSTREAM_OUT struPushInfoOut = new HCISUPCMS.NET_EHOME_PUSHSTREAM_OUT();
        struPushInfoOut.read();
        struPushInfoOut.dwSize = struPushInfoOut.size();
        struPushInfoOut.write();
        if (!Cms.hCEhomeCMS.NET_ECMS_StartPushRealStream(lLoginId, struPushInfoIn, struPushInfoOut)) {
            sessionMap.remove("session:"+carId+"_"+lChannel);
            log.error("NET_ECMS_StartPushRealStream failed, error code:" + Cms.hCEhomeCMS.NET_ECMS_GetLastError());
        } else {
            log.info("NET_ECMS_StartPushRealStream succeed, sessionID:" + struPushInfoIn.lSessionID);
        }
    }

    /**
     * 停止预览,Stream服务停止实时流转发,CMS向设备发送停止预览请求
     */
    public void StopRealPlay(String carNo, Integer channel) {

        Integer lPreviewHandle = playHandleMap.get("realPlayHandle:" + carNo+channel);
        if (lPreviewHandle == null) {
            return;
        }
        if (!hCEhomeStream.NET_ESTREAM_StopPreview(lPreviewHandle)) {
            System.out.println("NET_ESTREAM_StopPreview failed,err = " + hCEhomeStream.NET_ESTREAM_GetLastError());
            return;
        }

        Integer loginId = Cms.userLoginMap.get(carNo);
        if (loginId == null) {
            return;
        }
        Integer sessionId = sessionMap.get("session:"+carNo+"_"+channel);
        if (sessionId == null) {
            return;
        }

        if (!Cms.hCEhomeCMS.NET_ECMS_StopGetRealStream(loginId, sessionId)) {
            log.info("NET_ECMS_StopGetRealStream failed,err = " + Cms.hCEhomeCMS.NET_ECMS_GetLastError());
            return;
        }
        log.info("停止Stream的实时流转发");
        Stream.dataMap.remove(carNo + "_" + channel);
        Stream.sessionMap.remove("session:"+carNo+"_"+channel);
        PipedOutputStream pos = streamMap.get("stream:" + lPreviewHandle);
        if (pos != null) {
            try {
                pos.close();
            } catch (IOException exception) {
                exception.printStackTrace();
            }
            Stream.streamMap.remove("stream:"+ lPreviewHandle);
            Stream.playHandleMap.remove("realPlayHandle:" + carNo+channel);
        }
        log.info("CMS发送预览停止请求");
    }

    /**
     * 播放库加载
     *
     * @return
     */
    private static boolean CreatePlayInstance() {
        if (playCtrl == null) {
            synchronized (PlayCtrl.class) {
                String strPlayPath = "";
                try {
                    if (OsSelect.isWindows())
                        //win系统加载库路径(路径不要带中文)
                        strPlayPath = System.getProperty("user.dir") + "\\lib\\isupsdk\\PlayCtrl.dll";
                    else if (OsSelect.isLinux())
                        //Linux系统加载库路径(路径不要带中文)
                        strPlayPath = System.getProperty("user.dir") + "/lib/libPlayCtrl.so";
                    playCtrl = (PlayCtrl) Native.loadLibrary(strPlayPath, PlayCtrl.class);

                } catch (Exception ex) {
                    log.info("loadLibrary: " + strPlayPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    public void startListenPlayBack(String ip, String port) {
        if (fPLAYBACK_NEWLINK_CB == null) {
            fPLAYBACK_NEWLINK_CB = new PLAYBACK_NEWLINK_CB();
        }
        HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM param = new HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM();
        System.arraycopy(ip.getBytes(), 0, param.struIPAdress.szIP, 0, ip.length());
        param.struIPAdress.wPort = Short.parseShort(port);
        param.fnNewLinkCB = fPLAYBACK_NEWLINK_CB;
        param.byLinkMode = 0;//tcp-0;udp-1
        m_lPlayBackListenHandle = hCEhomeStream.NET_ESTREAM_StartListenPlayBack(param);
        if (m_lPlayBackListenHandle < -1) {
            log.info("NET_ESTREAM_StartListenPlayBack failed, error code: {}", hCEhomeStream.NET_ESTREAM_GetLastError());
        } else {
            log.info("回放服务:{}_{}, NET_ESTREAM_StartListenPlayBack success", ip, port);
        }

    }


    public class FPREVIEW_NEWLINK_CB implements HCISUPStream.PREVIEW_NEWLINK_CB {

        @Override
        public boolean invoke(int lLinkHandle, HCISUPStream.NET_EHOME_NEWLINK_CB_MSG pNewLinkCBMsg, Pointer pUserData) throws IOException {
            // 监听,每realPlay调用时,此方法监听到,开始执行
            String userId = new String(pNewLinkCBMsg.szDeviceID).trim();
            int dwChannelNo = pNewLinkCBMsg.dwChannelNo;

            PipedInputStream pis = new PipedInputStream();
            PipedOutputStream pos = new PipedOutputStream();
            Stream.streamMap.put("stream:"+lLinkHandle,pos);
            pos.connect(pis);
            CompletableFuture.runAsync(()-> {
                try {
                    PushUtil.grabAndPushRtmp(pis,"rtmp://"+rtmphost+"/live/"+userId+"_"+ dwChannelNo);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, Executors.newFixedThreadPool(1));

            log.info("FPREVIEW_NEWLINK_CB callback");
            log.info("FPREVIEW_NEWLINK_CB callback byStreamType : {}", pNewLinkCBMsg.byStreamType);
            //预览数据回调参数
            playHandleMap.put("realPlayHandle:" + userId + dwChannelNo , lLinkHandle );
            HCISUPStream.NET_EHOME_PREVIEW_DATA_CB_PARAM struDataCB = new HCISUPStream.NET_EHOME_PREVIEW_DATA_CB_PARAM();

            FPREVIEW_DATA_CB fPREVIEW_DATA_CB = dataMap.get(userId + "_" + dwChannelNo);
            if (fPREVIEW_DATA_CB == null) {
                fPREVIEW_DATA_CB = new FPREVIEW_DATA_CB(pos);
                dataMap.put(userId + "_" + dwChannelNo,fPREVIEW_DATA_CB);
            }
            struDataCB.fnPreviewDataCB = fPREVIEW_DATA_CB;

            if (!hCEhomeStream.NET_ESTREAM_SetPreviewDataCB(lLinkHandle, struDataCB)) {
                log.info("NET_ESTREAM_SetPreviewDataCB failed err::" + hCEhomeStream.NET_ESTREAM_GetLastError());
                return false;
            }
            return true;
        }
    }

    public class FPREVIEW_DATA_CB implements HCISUPStream.PREVIEW_DATA_CB {

        private PipedOutputStream pos;
        public FPREVIEW_DATA_CB(PipedOutputStream pos) {
            this.pos = pos;
        }

        //实时流回调函数/
        @Override
        public void invoke(int iPreviewHandle, HCISUPStream.NET_EHOME_PREVIEW_CB_MSG pPreviewCBMsg, Pointer pUserData) throws Exception {
//            if (Count == 500) {//降低打印频率
//                log.info("FPREVIEW_DATA_CB callback, iPreviewHandle:{}", iPreviewHandle);
//                log.info("FPREVIEW_DATA_CB callback, data length:" + pPreviewCBMsg.dwDataLen);
//                Count = 0;
//            }
//            Count++;

            long offset = 0;
            ByteBuffer buffers = pPreviewCBMsg.pRecvdata.getByteBuffer(offset, pPreviewCBMsg.dwDataLen);
            byte[] bytes = new byte[pPreviewCBMsg.dwDataLen];
            buffers.rewind();
            buffers.get(bytes);

            try{
                //2.将数据读入到内存空间,此处不可用redis,否则执行时间是当前10倍
//                PipedOutputStream pos = Stream.streamMap.get("stream:"+iPreviewHandle);
                pos.write(bytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    byte[] allEsBytes = null;

    public void writeESH264(final byte[] outputData) throws IOException {
        if (outputData.length <= 0) {
            return;
        }
        if ((outputData[0] & 0xff) == 0x00
                && (outputData[1] & 0xff) == 0x00
                && (outputData[2] & 0xff) == 0x01
                && (outputData[3] & 0xff) == 0xBA) {
            if (allEsBytes != null && allEsBytes.length > 0) {
                return;
//                allEsBytes = null;
            }
        }
        if ((outputData[0] & 0xff) == 0x00
                && (outputData[1] & 0xff) == 0x00
                && (outputData[2] & 0xff) == 0x01
                && (outputData[3] & 0xff) == 0xE0) {
            int from = 9 + outputData[8] & 0xff;
            int len = outputData.length - 9 - (outputData[8] & 0xff);

            byte[] esBytes = new byte[len];
            System.arraycopy(outputData, from, esBytes, 0, len);

            if (allEsBytes == null) {
                allEsBytes = esBytes;
            } else {
                byte[] newEsBytes = new byte[allEsBytes.length + esBytes.length];
                System.arraycopy(allEsBytes, 0, newEsBytes, 0, allEsBytes.length);
                System.arraycopy(esBytes, 0, newEsBytes, allEsBytes.length, esBytes.length);
                allEsBytes = newEsBytes;
            }
        } else {
            allEsBytes = outputData;
        }
    }

    void ffmpegConvetor(String videoInputPath, String videoOutPath) throws Exception {
        if (OsSelect.isWindows()) {
            String ffmpegExe = "E:\\chromeDowload\\ffmpeg.exe";
            List<String> command = new ArrayList<>();
            command.add(ffmpegExe);
            command.add("-i");
            command.add(videoInputPath);
            command.add("-c");
            command.add("copy");
            command.add("-an");
            command.add(videoOutPath);
            ProcessBuilder builder = new ProcessBuilder(command);
            Process process = null;
            try {
                process = builder.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理
            try {
                InputStream errorStream = process.getErrorStream();
                InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
                BufferedReader br = new BufferedReader(inputStreamReader);
                String line = "";
                while ((line = br.readLine()) != null) {
                }
                if (br != null) {
                    br.close();
                }
                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
                if (errorStream != null) {
                    errorStream.close();
                }
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        } else if (OsSelect.isLinux()) {
            //todo linux的ffmpeg使用
        }
    }


    public static class PLAYBACK_NEWLINK_CB implements HCISUPStream.PLAYBACK_NEWLINK_CB {
        @Override
        public boolean invoke(int lPlayBackLinkHandle, HCISUPStream.NET_EHOME_PLAYBACK_NEWLINK_CB_INFO pNewLinkCBInfo, Pointer pUserData) {
            pNewLinkCBInfo.read();
            log.info("PLAYBACK_NEWLINK_CB callback, szDeviceID:" + new String(pNewLinkCBInfo.szDeviceID).trim()
                    + ",lSessionID:" + pNewLinkCBInfo.lSessionID + ",dwChannelNo:" + pNewLinkCBInfo.dwChannelNo);
            m_lPlayBackLinkHandle = lPlayBackLinkHandle;
            HCISUPStream.NET_EHOME_PLAYBACK_DATA_CB_PARAM struCBParam = new HCISUPStream.NET_EHOME_PLAYBACK_DATA_CB_PARAM();
            //预览数据回调参数
            if (fPLAYBACK_DATA_CB == null) {
                fPLAYBACK_DATA_CB = new PLAYBACK_DATA_CB();
            }
//            pNewLinkCBInfo.fnPlayBackDataCB = fPLAYBACK_DATA_CB;
//            pNewLinkCBInfo.byStreamFormat = 0;
            struCBParam.fnPlayBackDataCB = fPLAYBACK_DATA_CB;
            struCBParam.byStreamFormat = 0;
            struCBParam.write();
//            pNewLinkCBInfo.write();
            if (!hCEhomeStream.NET_ESTREAM_SetPlayBackDataCB(lPlayBackLinkHandle, struCBParam)) {
                log.info("NET_ESTREAM_SetPlayBackDataCB failed");
            }
            return true;
        }
    }

    public static class PLAYBACK_DATA_CB implements HCISUPStream.PLAYBACK_DATA_CB {
        //实时流回调函数
        @Override
        public boolean invoke(int iPlayBackLinkHandle, HCISUPStream.NET_EHOME_PLAYBACK_DATA_CB_INFO pDataCBInfo, Pointer pUserData) {
            if (iCount == 500) {//降低打印频率
                log.info("PLAYBACK_DATA_CB callback , dwDataLen:" + pDataCBInfo.dwDataLen + ",dwType:" + pDataCBInfo.dwType);
                iCount = 0;
            }
            iCount++;
            //播放库SDK解码显示在win窗口上,
            switch (pDataCBInfo.dwType) {
                case HCNetSDK.NET_DVR_SYSHEAD: //系统头
//                    boolean b_port = playCtrl.PlayM4_GetPort(m_lPort);
//                    if (b_port == false) //获取播放库未使用的通道号
//                    {
//                        break;
//                    }
//                    if (pDataCBInfo.dwDataLen > 0) {
//                        if (!playCtrl.PlayM4_SetOverlayMode(m_lPort.getValue(), false, 0)) {
//                            break;
//                        }
//
//                        if (!playCtrl.PlayM4_SetStreamOpenMode(m_lPort.getValue(), PlayCtrl.STREAME_FILE))  //设置文件流播放模式
//                        {
//                            break;
//                        }
//
//                        if (!playCtrl.PlayM4_OpenStream(m_lPort.getValue(), pDataCBInfo.pData, pDataCBInfo.dwDataLen, 2 * 1024 * 1024)) //打开流接口
//                        {
//                            break;
//                        }
//                        W32API.HWND hwnd = new W32API.HWND(Native.getComponentPointer(IsupTest.panelRealplay));
//                        if (!playCtrl.PlayM4_Play(m_lPort.getValue(), hwnd)) //播放开始
//                        {
//                            break;
//                        }
//                    }
                case HCNetSDK.NET_DVR_STREAMDATA:   //码流数据
                    if (pDataCBInfo.dwDataLen > 0) {
//                        for (int i = 0; i < 1000; i++) {
//                            boolean bRet = playCtrl.PlayM4_InputData(m_lPort.getValue(), pDataCBInfo.pData, pDataCBInfo.dwDataLen);
//                            if (!bRet) {
//                                if (i >= 999) {
//                                    log.info("PlayM4_InputData,failed err:" + playCtrl.PlayM4_GetLastError(m_lPort.getValue()));
//                                }
//                                try {
//                                    Thread.sleep(1000);
//                                } catch (InterruptedException e) {
//                                    e.printStackTrace();
//                                }
//                            } else {
//                                break;
//                            }
//                        }
                        try {
                            String fileName = redisUtil.get("downloadHandle:" + iPlayBackLinkHandle);
                            FileOutputStream m_file = new FileOutputStream(fileName, true);
                            long offset = 0;
                            ByteBuffer buffers = pDataCBInfo.pData.getByteBuffer(offset, pDataCBInfo.dwDataLen);
                            byte[] bytes = new byte[pDataCBInfo.dwDataLen];
                            buffers.rewind();
                            buffers.get(bytes);
                            m_file.write(bytes);
                            m_file.close();
//                           if (pDataCBInfo.dwDataLen < 1024)
//                                VideoUtil.convetor(fileName, fileName + ".mp4");

                        } catch (FileNotFoundException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                //如果仅需保存回放的视频流文件,参考一下注释的代码
			/*try {

				m_file = new FileOutputStream(file, true);
				long offset = 0;
	             ByteBuffer buffers = pDataCBInfo.pData.getByteBuffer(offset, pDataCBInfo.dwDataLen);
	             byte [] bytes = new byte[pDataCBInfo.dwDataLen];
	             buffers.rewind();
	             buffers.get(bytes);
	             m_file.write(bytes);
	             m_file.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}*/
                case 3: //结束
                    String fileName = redisUtil.get("downloadHandle:" + iPlayBackLinkHandle);
                    try {
                        if (OsSelect.isLinux()) {
                            convetorLinux(fileName, fileName + ".mp4");
                        } else {
                            convetorWindows(fileName, fileName + ".mp4");
                        }
                        break;
                    }catch (Exception ex) {
                        ex.printStackTrace();
                    }
            }
            return true;
        }
    }

    public static void convetorWindows(String videoInputPath, String videoOutPath) throws Exception{
        String ffmpegExe = "E:\\software\\ffmpeg-5.0.1-essentials_build\\bin\\ffmpeg.exe";
        List<String> command = new ArrayList<>();
        command.add(ffmpegExe);
        command.add("-i");
        command.add(videoInputPath);
        command.add("-c");
        command.add("copy");
        command.add("-an");
        command.add(videoOutPath);
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理
        try {
            InputStream errorStream = process.getErrorStream();
            InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
            BufferedReader br = new BufferedReader(inputStreamReader);
            String line = "";
            while ((line = br.readLine()) != null) {
            }
            if (br != null) {
                br.close();
            }
            if (inputStreamReader != null) {
                inputStreamReader.close();
            }
            if (errorStream != null) {
                errorStream.close();
            }
            Path p = Paths.get(videoInputPath);
            Files.delete(p);
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }

    public static void convetorLinux(String videoInputPath, String videoOutPath) throws Exception {
        String ffmpegExe = "/usr/local/ffmpeg/bin/ffmpeg";
        String videoCommend = ffmpegExe + " -i " +  videoInputPath + " -c copy -an "  + videoOutPath;
        try {
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(videoCommend);
            InputStream stderr = proc.getErrorStream();
            InputStreamReader isr = new InputStreamReader(stderr);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null){
            }
            if (br != null) {
                br.close();
            }
            if (isr != null) {
                isr.close();
            }
            if (stderr != null) {
                stderr.close();
            }
            int exitVal = proc.waitFor();
            Path p = Paths.get(videoInputPath);
            Files.delete(p);
        } catch (Throwable t) {
            t.printStackTrace();
        }

    }


}



到了这里,关于web实时预览功能开发 java 海康sdk nvr的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 海康实时监控预览视频流接入web

            我们采取的方案是后端获取视频流返回给前端,然后前端播放 根据官方文档传输对应的参数  官方接口限制:为保证数据的安全性,取流URL设有有效时间,有效时间为5分钟。 注意不同协议的限制不同,rtsp没得限制但前端播放麻烦,web端展示的话ws比较好 海康开放平

    2024年04月17日
    浏览(46)
  • vue3实现海康威视根据海康插件进行监控实时预览和回放功能

    因为我的文章已经写过基于vue实现海康web插件进行视频播放开箱即用文章,这个文章是利用 vite+vue3+js 进行编写的,大致内容跟vue2一样,拿过去能直接用。 至于我为什么要用js而不用ts,因为海康提供的三个脚本为js语言的,ts尝试过一次,我道行太浅,没搞明白。 这些代码是

    2024年02月05日
    浏览(87)
  • vue2实现海康威视根据海康插件进行监控实时预览和回放功能,全套代码,开箱即用。

     这是一套拿到手就能直接用的根据海康提供的摄像机节点实时预览和回放的全步骤代码,开箱即用。  我的是基于vue2写的,vue3可以看我下一篇文章。 很多人在开发vue项目的时候,不知道怎么去开发视频实时预览和回放功能,然后一直查文档,再去看别人写的项目,就是无

    2023年04月15日
    浏览(71)
  • JavaCV音视频开发宝典:使用JavaCV读取海康平台或海康网络摄像头sdk回调视频TS码流并解析预览图像

    《JavaCV音视频开发宝典》专栏目录导航 《JavaCV音视频开发宝典》专栏介绍和目录 ​ 两年前博主写了如何利用JavaCV解析各种h264裸流,《JavaCV音视频开发宝典:使用javacv读取GB28181、海康大华平台和网络摄像头sdk回调视频码流并解析预览图像》,但是随着时间变化,各个厂商s

    2024年02月14日
    浏览(46)
  • 记录对接海康威视摄像头web端实时预览:Linux+ffmpeg+nginx转换RTSP视频流(完整版实现)

            需求:web端实现海康摄像头实时预览效果         由于市面上大部分网络摄像头都支持RTSP协议视频流,web端一般无法直接使用RTSP实现视频预览,本篇使用ffmpeg对视频流进行转换,最终实现web端实时预览。         工具介绍:ffmpeg、nginx、vue         介

    2024年01月25日
    浏览(54)
  • JavaCV音视频开发宝典:使用JavaCV读取海康平台或海康网络摄像头sdk回调录像回放视频PS码流并解析预览图像

    《JavaCV音视频开发宝典》专栏目录导航 《JavaCV音视频开发宝典》专栏介绍和目录 ​ 上一章中《JavaCV音视频开发宝典:使用JavaCV读取海康平台或海康网络摄像头sdk回调视频TS流并解析预览图像》已经详细介绍了针对海康SDK实时视频流回调的TS流解析实现,并且也提到了PS流和

    2024年02月16日
    浏览(53)
  • 海康威视摄像头二次开发_云台控制_视频画面实时预览(基于Qt实现)

    需求:需要在公司的产品里集成海康威视摄像头的SDK,用于控制海康威视的摄像头。 拍照抓图、视频录制、云台控制、视频实时预览等等功能。 开发环境: windows-X64(系统) + Qt5.12.6(Qt版本) + MSVC2017_X64(使用的编译器) 海康威视提供了 设备网络SDK ,设备网络SDK是基于设备私有网

    2024年02月13日
    浏览(55)
  • 通过java解码web前端直接预览海康威视摄像头

            最近进行项目开发时遇到了需要前端直接调用摄像头,并直接进行播放的需求。原本计划通过海康威视官网的《WEB无插件开发包 V3.2》直接进行控制、交互,实现摄像头直接登录以及取流预览。但是前端人员现场驻场开发后反映各种兼容性问题频发,反正就是不能友

    2024年02月01日
    浏览(54)
  • 海康威视相机SDK二次开发(JAVA语言)

    前言 有个项目需要使用java程序读取海康威视的相机图片。相机通过以太网连接服务器,部署在服务器上的java程序将相机拍摄的画面保存在指定路径下。 海康威视提供了sdk开发包,可以在官网中下载,windows和linux系统都有。但是开发包中给出的示例代码,无法满足实际需要,

    2024年04月29日
    浏览(46)
  • 海康WEB3.3控件开发包 V3.3 前端vue项目调用实时监控画面

    公司业务迭代, 需要前端vue项目里增加一个查看实时监控模块, 这个需求是之前离职的前端小哥没有研究明白的, 现在落在了我的肩上, 压力还是有的. 但是压力归压力, 问题还是要解决的. 第一步: 调研大佬们已经实现的方案, 找设备对接. 公司后端大佬提出用官方SDK稍加修改即

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包