海康威视SDK基于JAVA二次开发

在这里插入图片描述

项目背景

项目中用到了海康威视的摄像机视频服务器。项目要求,要将海康威视的摄像视频同步按时间至我们自己的服务器,并且在项目中记录文件信息。

项目环境

  • SpringBoot + JDK1.8
  • 海康威视设备型号:DS-7608N-K2/8P

引入SDK

首先在海康卫视下载对应的SDK包。

笑小枫网站直接下载:https://www.xiaoxiaofeng.com/resource/14
官网下载地址:https://www.hikvision.com/cn/download_61.html

解压下载的SDK文件,如下图:
在这里插入图片描述

  • Demo示例:其中有java的一个demo,大家也可以参考一下
  • 开发文档:包含了海康威视不同设备的SDK对接文档
  • 库文件:需要部分dll文件引用,通过dll文件去调用海康威视的服务器,需要的文件下文详细介绍

打开我们的SpringBoot项目

  • 首先将demo示例中java例子的HCNetSDK.java文件拷贝至我们项目,项目位置没有特殊要求。

  • 然后将库文件中的HCNetSDKCom文件夹及下面的所有文件、AudioRender.dll、HCCore.dll、HCNetSDK.dll、PlayCtrl.dll、SuperRender.dll文件放置指定的文件夹
    在这里插入图片描述

  • 修改HCNetSDK.java文件的HCNetSDK加载dll文件的位置。如下:D:\HKSDK\HCNetSDK为dll文件存放的位置。

 HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary("D:\\HKSDK\\HCNetSDK", HCNetSDK.class);
  • pom文件引入SDK二次开发所需要的jar包。jar包均手动引入,不是通过maven网上下载。官方示例中的javaDemo中有相应的jar包。
<dependency>
    <groupId>net.java.jna</groupId>
    <artifactId>jna</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>net.java.jna</groupId>
    <artifactId>examples</artifactId>
    <version>1.0.0</version>
</dependency>

编写程序代码

import com.sun.jna.NativeLong;
import com.sun.jna.ptr.IntByReference;
import com.urgentlogistic.util.HCNetSDK;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;

/**
 * @author ZhangFZ
 * @date 2020/4/20 20:23
 **/
public class VideoDowload {

    private static Logger logger = LoggerFactory.getLogger(VideoDowload.class);
    private static HCNetSDK hcNetSDK = HCNetSDK.INSTANCE;
    private NativeLong userId;//用户句柄
    private NativeLong loadHandle;//下载句柄
    private Timer downloadTimer;

    /**
     * 按时间下载视频
     */
    private boolean downloadVideo(Dvr dvr, Date startTime, Date endTime, String filePath, int channel) {
        boolean initFlag = hcNetSDK.NET_DVR_Init();
        if (!initFlag) { //返回值为布尔值 fasle初始化失败
            logger.warn("hksdk(视频)-海康sdk初始化失败!");
            return false;
        }
        HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
        userId = hcNetSDK.NET_DVR_Login_V30(dvr.getDvrip(), (short) dvr.getDvrport(), dvr.getDvrusername(), dvr.getDvrpassword(), deviceInfo);
        logger.info("hksdk(视频)-登录海康录像机信息,状态值:" + hcNetSDK.NET_DVR_GetLastError());
        long lUserId = userId.longValue();
        if (lUserId == -1) {
            logger.warn("hksdk(视频)-海康sdk登录失败!");
            return false;
        }
        loadHandle = new NativeLong(-1);
        if (loadHandle.intValue() == -1) {
            loadHandle = hcNetSDK.NET_DVR_GetFileByTime(userId, new NativeLong(channel), getHkTime(startTime), getHkTime(endTime), filePath);
            logger.info("hksdk(视频)-获取播放句柄信息,状态值:" + hcNetSDK.NET_DVR_GetLastError());
            if (loadHandle.intValue() >= 0) {
                // 判断文件夹是否存在
                File files = new File(filePath);
                if(!files.exists()){
                    files.mkdirs();
                }
                boolean downloadFlag = hcNetSDK.NET_DVR_PlayBackControl(loadHandle, hcNetSDK.NET_DVR_PLAYSTART, 0, null);
                int tmp = -1;
                IntByReference pos = new IntByReference();
                while (true) {
                    boolean backFlag = hcNetSDK.NET_DVR_PlayBackControl(loadHandle, hcNetSDK.NET_DVR_PLAYGETPOS, 0, pos);
                    if (!backFlag) {//防止单个线程死循环
                        return downloadFlag;
                    }
                    int produce = pos.getValue();
                    if ((produce % 10) == 0 && tmp != produce) {//输出进度
                        tmp = produce;
                        logger.info("hksdk(视频)-视频下载进度:" + "==" + produce + "%");
                    }
                    if (produce == 100) {//下载成功
                        hcNetSDK.NET_DVR_StopGetFile(loadHandle);
                        loadHandle.setValue(-1);
                        hcNetSDK.NET_DVR_Logout(userId);//退出录像机
                        logger.info("hksdk(视频)-退出状态" + hcNetSDK.NET_DVR_GetLastError());
                        //hcNetSDK.NET_DVR_Cleanup();
                        return true;
                    }
                    if (produce > 100) {//下载失败
                        hcNetSDK.NET_DVR_StopGetFile(loadHandle);
                        loadHandle.setValue(-1);
                        logger.warn("hksdk(视频)-海康sdk由于网络原因或DVR忙,下载异常终止!错误原因:" + hcNetSDK.NET_DVR_GetLastError());
                        //hcNetSDK.NET_DVR_Logout(userId);//退出录像机
                        //logger.info("hksdk(视频)-退出状态"+hcNetSDK.NET_DVR_GetLastError());
                        return false;
                    }
                }
            } else {
                System.out.println("hksdk(视频)-下载失败" + hcNetSDK.NET_DVR_GetLastError());
                return false;
            }
        }
        return false;
    }

    /**
     * 获取海康录像机格式的时间
     */
    private HCNetSDK.NET_DVR_TIME getHkTime(Date time) {
        HCNetSDK.NET_DVR_TIME structTime = new HCNetSDK.NET_DVR_TIME();
        String str = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(time);
        String[] times = str.split("-");
        structTime.dwYear = Integer.parseInt(times[0]);
        structTime.dwMonth = Integer.parseInt(times[1]);
        structTime.dwDay = Integer.parseInt(times[2]);
        structTime.dwHour = Integer.parseInt(times[3]);
        structTime.dwMinute = Integer.parseInt(times[4]);
        structTime.dwSecond = Integer.parseInt(times[5]);
        return structTime;
    }

    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        Date startTime = null;
        Date endTime = null;
        try {
            startTime = sdf.parse("20200422170000");   //开始时间
            endTime = sdf.parse("20200422180000");      //结束时间
        } catch (ParseException e) {
            e.printStackTrace();
        }
        VideoDowload test = new VideoDowload();
        Dvr dvr = new Dvr("http://192.168.0.167",80,"admin","123456");
        int channel = 33;//通道
        System.out.print(test.downloadVideo(dvr, startTime, endTime, "D:\\testhk\\test.mp4", channel));
    }
}

Dvr类:

import lombok.Data;

/**
 * @author ZhangFZ
 * @date 2020/4/21 9:32
 **/
@Data
public class Dvr {

    // 视频服务器ip地址
    private String dvrip;
    // 视频服务器端口号
    private int dvrport;
    // 视频服务器用户名
    private String dvrusername;
    // 视频服务器密码
    private String dvrpassword;

    public Dvr(String dvrip, int dvrport, String dvrusername, String dvrpassword) {
        this.dvrip = dvrip;
        this.dvrport = dvrport;
        this.dvrusername = dvrusername;
        this.dvrpassword = dvrpassword;
    }
}

注意事项:

  • 自己的服务器信息请手动修改,保存目录等信息请手动修改
  • channel通道号是32起,比如你的通道为1,这里需要写33,原因咨询海康威视的技术。
  • 这里只是一个简单的demo,具体操作根据自己业务的实际情况来。

下图是定时5分钟取一次数据的结果

视频无法播放的问题

因为你的音频不是mpeg4容器支持的音频格式。通过mediainfo分析可知,你的音频格式是pcm_alaw,并且还有一行警告信息:
FileExtension_Invalid : mpeg mpg m2p vob vro pss evo
你的视频格式应该是MPEG-PS格式,但是后缀却是mp4,其实是一个非法的MP4。mediainfo还会告诉你合法的后缀应该是上述那几个。由于你的音频格式根本不被浏览器支持,但是视频格式是被浏览器支持的(H.264/AVC)。那么解决方案其实也简单,抽调音频即可。参考ffmpeg命令行(不转码,直接复制流):
ffmpeg -i demo.mp4 -c copy -an demp_enc.mp4
速度很快,使用-an参数屏蔽掉音频流,将封装格式转为mp4。再次用mediainfo查看,格式已经显示MPEG-4,是一个标准的mp4容器封装了,在当今主流的浏览器都能直接播放。

下载ffmpeg解码工具官网下载ffmpeg,解压安装找到ffmpeg.exe。

添加一下工具类

// ffmpeg.exe存放的位置
private static String ffmpegEXE = "D:\\software\\ffmpg\\bin\\ffmpeg.exe";

//ffmpeg -i demo.mp4 -c copy -an demp_enc.mp4
public static void convetor(String videoInputPath, String videoOutPath) throws Exception {
    List<String> command = new ArrayList<String>();
    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) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    // 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理
    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();
    }

}

下载视频成功后,调用该方法进行转码,修改VideoDowload.java代码为以下:

if (produce == 100) {//下载成功
    hcNetSDK.NET_DVR_StopGetFile(loadHandle);
    loadHandle.setValue(-1);
    hcNetSDK.NET_DVR_Logout(userId);//退出录像机
    logger.info("hksdk(视频)-退出状态" + hcNetSDK.NET_DVR_GetLastError());
    hcNetSDK.NET_DVR_Cleanup();

    Media media = new Media();
    media.setDisasterId(disasterId);
    media.setType(MediaType.VIDEO);
    media.setCreateDate(new Date());
    media.setUploadTime(new Date());
    media.setAttachmentName("z" + fileName);
    media.setIsDeleted(false);
    media.setUpdate_rhtx(1);
    media.setFlag("OTHER");
    media.setNewsFeedId(0);
    String http_path = restUrlLocalhost;
    media.setUrl(http_path + "/urgentlogistic/file/mp4/" + newDate + "/z" +fileName);
    mediaService.create(media);

    try {
        // 视频进行转码
        convetor(filePath + fileName,filePath + "z" +fileName);
        File file = new File(filePath + fileName);
        // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
        file.delete();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return true;
}

运行完就会多一个视频文件,然后就可以用通用播放器播放这个新的视频了,至于老的视频任凭自己需求处理掉就行啦

使用微信关注下方公众号,回复《海康威视》获取海康威视下载中心地址、海康威视的错误码NET_DVR_GetLastError对应的错误描述、海康威视官方开发人员联系方式

海康威视硬盘录像机SDK二次开发C#专用封装包,基于农民伯伯的源码修改,因之前有很多错误的地址,目前完成了一半左右 目前修改完成结构体如下: 获取设备参数:NET_DVR_DEVICECFG ok 获取时间参数:NET_DVR_TIME ok 获取网络参数:NET_DVR_NETCFG_V30 ok 网络参数相关: NET_DVR_IPADDR ok NET_DVR_PPPOECFG ok NET_DVR_ETHERNET_V30 ok 获取图像参数:NET_DVR_PICCFG_V30 ok 图像参数相关: NET_DVR_COLOR ok NET_DVR_VILOST_V30 ok NET_DVR_HANDLEEXCEPTION_V30 okv NET_DVR_SCHEDTIME okv NET_DVR_MOTION_V30 okv NET_DVR_HANDLEEXCEPTION_V30 okv NET_DVR_SCHEDTIME okv NET_DVR_HIDEALARM_V30 okv NET_DVR_HIDEALARM_V30 okv NET_DVR_SHELTER okv 获取压缩参数:NET_DVR_COMPRESSIONCFG_V30 okv NET_DVR_COMPRESSION_INFO_V30 okv 获取录像参数:NET_DVR_RECORD_V30 okv NET_DVR_RECORDDAY okv NET_DVR_RECORDSCHED okv 获取云台参数:NET_DVR_DECODERCFG_V30 okv 获取232串口参数:NET_DVR_RS232CFG_V30 ok 串口参数相关: NET_DVR_SINGLE_RS232 ok NET_DVR_PPPCFG_V30 ok NET_DVR_IPADDR ok NET_DVR_PPPCFG ok ---------------------------------------------------------------------------------------------------- 获取报警输入参数:NET_DVR_ALARMINCFG_V30 ok 报警输入参数相关: NET_DVR_HANDLEEXCEPTION_V30 ok ---------------------------------------------------------------------------------------------------- 获取报警输出参数:NET_DVR_ALARMOUTCFG_V30 ok 报警输出参数相关: NET_DVR_SCHEDTIME ok ---------------------------------------------------------------------------------------------------- 获取本地预览参数:NET_DVR_PREVIEWCFG_V30 ok ---------------------------------------------------------------------------------------------------- 获取视频输出参数:NET_DVR_VIDEOOUT_V30 ok ---------------------------------------------------------------------------------------------------- 获取用户参数: NET_DVR_USER_V30 ----------------------------------------------------------------------------------------------------- 获取异常参数: NET_DVR_EXCEPTION_V30 ok -----------------------------------------------------------------------------------------------------
评论 60
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑小枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值