一、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 结构体的官方文档
//强制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
网友评论