海康威视SDK视频录制及强制I帧操作

一、NET_DVR_SaveRealData方法

使用下面方法可以实现视频录像功能。

    private HCNetSDK sdk = HCNetSDK.INSTANCE;
    sdk.NET_DVR_SaveRealData_V30(cameraInfo.getKey(), file.getPath() + "/" + fileName + ".mp4")

该方法有个问题,视频可以录制,但是不能被前端页面直接加载播放,因为视频编码格式问题,虽然可以用FFMPEG工具进行格式转化,但是引入第三方的库,无疑会使代码的维护性降低。

FFMPEG工具 地址 提取码 zc14
使用FFmpeg进行转换的方法如下:

ffmpeg -i  in.mp4  out.mp4

该方法网络上有大量的帖子,我直接放连接过来,可以自行前往学习
大牛博客地址

二、NET_DVR_SaveRealData_V30方法

这个方法是问海康的工程师得到的,跟海康的工程师交流还是挺美好的,工程师很耐心,直到自己的问题得到解答,代码测试通过,所以还是必须给点个赞。

附上该方法的SDK文档

NET_DVR_SaveRealData_V30 SDK

按照SDK文档的说明,第二个参数传2,就可以了

  //预览成功后 调用接口使视频资源保存到文件中
     if (!sdk.NET_DVR_SaveRealData_V30(cameraInfo.getKey(), 2,file.getPath() + "/" + fileName + ".mp4")) {
         log.error("保存视频文件到文件夹失败 错误码为:  " + sdk.NET_DVR_GetLastError());
         logoutHIK(cameraInfo);
         return;
     }

到这里会发现一个问题,官方下载的SDK HCNetSDK.java文件中没有NET_DVR_SaveRealData_V30这个方法,尴尬了。
这就是官方SDK的坑点,SDK中有,但是HCNetSDK.java文件中没有,好多同学可能都会懵一下,这里可以将SDK中的方法直接复制进HCNetSDK.java文件即可。SDK是按照C语言来描述的,JAVA要做响应的适配改变。

 boolean  NET_DVR_SaveRealData_V30(NativeLong lRealHandle,int STREAM_TYPE,String sFileName);

OK,到此视频已经可以存储,播放也正常,但是你又会发现一个新的问题,就是保存的视频,设定1分钟,但是只有51秒 ,52秒,57秒等,就是没有1分钟的,甚至59秒的都很少,如果要求不那么高还好,到这里就可以结束了,如果要求的高,那就得做出处理了。

三、强制I帧

这里面其实是有一个 I帧的定义

录像数据解码播放必须从I帧开始,而客户端录像的时候开始时间点不一定是I帧,比如帧率25fps、I帧间隔100帧的情况下,每4秒才一个I帧,录像播放可能存在1~4秒的延时,所以录像的时候可以强制设备生成一个I帧。
NET_DVR_MakeKeyFrame强制主码流生成一个I帧,NET_DVR_MakeKeyFrameSub强制子码流生成一个I帧,z这两个是老的接口。
后来因为设备不只有主码流和子码流,还有三码流、虚拟码流等,因此增加了NET_DVR_RemoteControl(命令:NET_DVR_MAKE_I_FRAME)接口,兼容前面的两个接口,输入参数NET_DVR_I_FRAME中byStreamType表示码流类型。建议使用该接口。

可以看到,如果I帧没有到,也是不录视频的,但是I帧一般会慢几秒中,所以视频长度不够自己配置的长度

需要用到NET_DVR_RemoteControl 这个方法,会发现 HCNetSDK.java文件中并没有NET_DVR_RemoteControl 这个方法,继续添加上。

附上NET_DVR_RemoteControl 的SDK
NET_DVR_RemoteControl SDK

同样,在 HCNetSDK.java文件中增加这个方法(根据java做了语法转换,如果不好转,请参考原HCNetSDK.java文件中的数据类型)

 boolean NET_DVR_RemoteControl(NativeLong lUserID, int dwCommand, Pointer pointer, int dwInBufferSize);

官方SDK简直了,有些方法没有,就连结构体也没有,都需要自己新增,没办法,谁让咱要用人家的产品么
lpInBuffer参数对应结构体 NET_DVR_I_FRAME
看SDK手册 NET_DVR_I_FRAME 结构体的官方文档

NET_DVR_I_FRAME SDK

//强制I帧参数结构体。
public static class NET_DVR_I_FRAME extends Structure{
    public int dwSize;
    public byte[] sStreamID = new byte[32];  //流IDs    SDK 中对  STREAM_ID_LEN进行了定义,赋值32
    public int dwChannel;//通道号
    public byte byStreamType; //码流类型:0-主码流,1-子码流,2-码流3,3-虚拟码流,以此类推
    public byte[] byRes = new byte[63];  //保留,置为0    按照SDK要求进行对应赋值
}
//新建结构体对象
        HCNetSDK.NET_DVR_I_FRAME netDvrIFrame = new HCNetSDK.NET_DVR_I_FRAME();   //新建结构体对象
        netDvrIFrame.read();
        netDvrIFrame.dwChannel = 1;          //因为上文代码中设置了通道号,按照上文中的设置
        netDvrIFrame.byStreamType = 0;
        netDvrIFrame.dwSize = netDvrIFrame.size();
        netDvrIFrame.write();

        if(!sdk.NET_DVR_RemoteControl(cameraInfo.getUserId(),3402,netDvrIFrame.getPointer(),netDvrIFrame.dwSize)){
            log.error("强制I帧 错误码为:  " + sdk.NET_DVR_GetLastError());
        }

在每次录像之前,对I帧进行强制设置,可以及时录像,经过测试基本上按照配置的时间进行录制,比如1分钟就是1分钟,偶尔有59秒的情况,提到的问题已经大大的修复了。经次一轮,对SDK的使用也有了更深的了解。自己踩过的坑,也记录下来,也让别人能很好的使用官方的SDK。

最后附上程序,欢迎下载传阅,另外还有海康工程师给的有更全结构体的HCNetSDK.java文件
百度网盘 链接:https://pan.baidu.com/s/1JEKvEnb5wTDtmNqlNsKvLg
提取码:x4bj

你可能感兴趣的:(海康威视SDK视频录制及强制I帧操作)