引言
在项目推进过程中,我们团队深入客户现场进行开发作业,其中一项关键任务是与海康威视录像机进行数据交互,精准获取其内部的片段数据,以此为基石推动后续业务的顺利开展。接下来,就和大家分享一下这一实操过程中的宝贵经验,希望能为同行们提供有益的参考。
环境准备
1.确保您有最新版本的海康威视网络SDK
访问海康威视官方网站下载:
前往 https://www.hikvision.com/cn/ (中国大陆用户)或 https://www.hikvision.com/ (国际用户)
2.需要将以下DLL文件复制到项目根目录
HCNetSDK.dll
HCCore.dll
整个HCNetSDKCom文件夹(保持原名)
libssl-1_1.dll
libcrypto-1_1.dll
hlog.dll
hpr.dll
zlib1.dll
PlayCtrl.dll
SuperRender.dll
AudioRender.dll
GdiPlus.dll
HmMerge.dll
HXVA.dll
libmmd.dll
MP_Render.dll
NPQos.dll
OpenAL32.dll
YUVProcess.dll
2.1 DLL文件的工作原理
-
在程序运行时,当需要调用 DLL 文件中的功能时,操作系统会将 DLL 文件加载到内存中。多个应用程序可以共享同一个 DLL 文件,这使得内存的利用更加高效。例如,有多个软件都需要进行图像解码操作,它们就可以共享一个包含图像解码功能的 DLL 文件,而不是每个软件都自带一份解码代码。
-
DLL 文件采用模块化的设计。开发人员可以将程序的不同功能部分分别编写成不同的 DLL 文件。这样,在程序更新或维护时,只需要更新对应的 DLL 文件,而不用重新编译整个程序,大大提高了软件维护的效率。
3.添加JNA依赖
在您的Java项目中添加JNA的依赖。这可以通过以下几种方式实现:
- 如果您使用Maven,可以在pom.xml文件中添加以下依赖:
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.6.0</version>
</dependency>
- 如果您使用Gradle,可以在build.gradle文件中添加:
dependencies {
implementation 'net.java.dev.jna:jna:5.6.0'
}
- ·如果您不使用构建工具,您可以手动下载jna.jar文件并添加到项目的classpath中。您可以从Maven中央仓库下载: https://repo1.maven.org/maven2/net/java/dev/jna/jna/
代码案例
1.导入CommonUtil工具类
这个工具类的主要作用是将海康威视SDK中使用的特殊时间日期格式解析为可读的字符串格式
public class CommonUtil {
//SDK时间解析
public static String parseTime(int time)
{
int dwYear=(time>>26)+2000;
int dwMonth=(time>>22)&15;
int dwDay=(time>>17)&31;
int dwHour=(time>>12)&31;
int dwMinute=(time>>6)&63;
int dwSecond=(time>>0)&63;
String sTime = String.format("%04d", dwYear) +
String.format("%02d", dwMonth) +
String.format("%02d", dwDay) +
String.format("%02d", dwHour) +
String.format("%02d", dwMinute) +
String.format("%02d", dwSecond);
return sTime;
}
}
2.导入NCNetSDK.java
HCNetSDK是一个用于与海康威视设备进行通信的开发包,提供了一组API接口,开发者可以通过这些接口实现与设备的连接、视频预览、视频录制、报警处理等功能
点击链接即可下载HCNetSDK.java
3.截取录像机回放片段的具体代码
主要功能和流程
-
初始化SDK和播放控制实例
-
设置异常回调和SDK日志
-
登录设备
-
执行特定操作(在这个例子中是按时间下载录像)
-
注销设备并清理SDK资源
需要修改的地方
1.DLL文件路径: 修改 strDllPath
和 strPlayPath
为您系统中实际的DLL文件路径。
2.设备登录信息: 在 main
方法中,修改 loginDevice
方法的参数
lUserID = loginDevice("192.168.xxx.xxx", (short) 8000, "xxxxxx", "xxxxxx");
将IP地址、端口、用户名和密码改为您实际设备的信息。
3.下载录像的通道号:
在 main
方法中,修改 dowmloadRecordByTime
方法的第二个参数(通道号):
new VideoDemo().dowmloadRecordByTime(lUserID, 33);
将IP地址、端口、用户名和密码改为您实际设备的信息。
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import java.util.Scanner;
import java.util.Timer;
public class ClientDemo {
int iErr = 0; // 用于存储错误代码
static HCNetSDK hCNetSDK = null; // 海康威视SDK的实例
static PlayCtrl playControl = null; // 播放控制实例
static int lUserID = -1; // 用户句柄,初始化为-1表示未登录
static int lDChannel; // 预览通道号
static int lPlayHandle = -1; // 预览句柄,初始化为-1表示未开始预览
static boolean bSaveHandle = false; // 保存句柄的标志
Timer Playbacktimer; // 回放用定时器
static FExceptionCallBack_Imp fExceptionCallBack; // 异常回调函数实例
static int FlowHandle; // 流程句柄
// 定义异常回调函数的实现类
static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack {
public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {
System.out.println("异常事件类型:" + dwType);
return;
}
}
// 创建SDK实例的方法
private static boolean createSDKInstance() {
if (hCNetSDK == null) {
synchronized (HCNetSDK.class) {
String strDllPath = "";
try {
// 指定DLL文件的路径
strDllPath = "C:\\Users\\xiongwenhao\\CientDemo\\HCNetSDK.dll";
try {
// 加载DLL文件
hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
} catch (Exception ex) {
System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
}
} catch (Exception ex) {
System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
return false;
}
}
}
return true;
}
// 创建播放控制实例的方法
private static boolean createPlayInstance() {
if (playControl == null) {
synchronized (PlayCtrl.class) {
String strPlayPath = "";
try {
// 指定播放控制DLL文件的路径
strPlayPath = "C:\\Users\\xiongwenhao\\CientDemo\\HCNetSDK.dll";
try {
// 加载播放控制DLL文件
hCNetSDK = (HCNetSDK) Native.loadLibrary(strPlayPath, HCNetSDK.class);
} catch (Exception ex) {
System.out.println("loadLibrary: " + strPlayPath + " Error: " + ex.getMessage());
}
} catch (Exception ex) {
System.out.println("loadLibrary: " + strPlayPath + " Error: " + ex.getMessage());
return false;
}
}
}
return true;
}
public static void main(String[] args) throws InterruptedException {
// 检查并创建SDK和播放控制实例
if (hCNetSDK == null && playControl == null) {
if (!createSDKInstance()) {
System.out.println("Load SDK fail");
return;
}
if (!createPlayInstance()) {
System.out.println("Load PlayCtrl fail");
return;
}
}
// 初始化SDK
boolean initSuc = hCNetSDK.NET_DVR_Init();
// 设置异常回调
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);
// 登录设备
lUserID = loginDevice("192.168.xxx.xxx", (short) 8000, "xxxxxx", "xxxxxx");
System.out.println("[Module]按时间下载录像");
new VideoDemo().dowmloadRecordByTime(lUserID, 33);
// 注销设备
if (hCNetSDK.NET_DVR_Logout(lUserID)) {
System.out.println("注销成功");
}
// 清理SDK资源
hCNetSDK.NET_DVR_Cleanup();
}
// 登录设备的方法
public static int loginDevice(String ip, short port, String user, String psw) {
// 创建登录信息和设备信息对象
HCNetSDK.NET_DVR_USER_LOGIN_INFO loginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
HCNetSDK.NET_DVR_DEVICEINFO_V40 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
// 设置设备IP地址
byte[] deviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
byte[] ipBytes = ip.getBytes();
System.arraycopy(ipBytes, 0, deviceAddress, 0, Math.min(ipBytes.length, deviceAddress.length));
loginInfo.sDeviceAddress = deviceAddress;
// 设置用户名和密码
byte[] userName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
byte[] password = psw.getBytes();
System.arraycopy(user.getBytes(), 0, userName, 0, Math.min(user.length(), userName.length));
System.arraycopy(password, 0, loginInfo.sPassword, 0, Math.min(password.length, loginInfo.sPassword.length));
loginInfo.sUserName = userName;
// 设置端口和登录模式
loginInfo.wPort = port;
loginInfo.bUseAsynLogin = false; // 同步登录
loginInfo.byLoginMode = 0; // 使用SDK私有协议
// 执行登录操作
int userID = hCNetSDK.NET_DVR_Login_V40(loginInfo, deviceInfo);
if (userID == -1) {
System.err.println("登录失败,错误码为: " + hCNetSDK.NET_DVR_GetLastError());
} else {
System.out.println(ip + " 设备登录成功!");
// 处理通道号逻辑
int startDChan = deviceInfo.struDeviceV30.byStartDChan;
System.out.println("预览起始通道号: " + startDChan);
}
return userID; // 返回登录结果
}
}
海康威视SDK常见错误码
错误码 | 宏定义 | 描述 |
---|---|---|
0 | NET_DVR_NOERROR | 没有错误 |
1 | NET_DVR_PASSWORD_ERROR | 用户名密码错误 |
2 | NET_DVR_NOENOUGHPRI | 权限不足 |
3 | NET_DVR_NOINIT | SDK未初始化 |
4 | NET_DVR_CHANNEL_ERROR | 通道号错误 |
5 | NET_DVR_OVER_MAXLINK | 连接到的设备端口超出最大数 |
6 | NET_DVR_VERSIONNOMATCH | 版本不匹配 |
7 | NET_DVR_NETWORK_FAIL_CONNECT | 连接服务器失败 |
8 | NET_DVR_NETWORK_SEND_ERROR | 向服务器发送失败 |
9 | NET_DVR_NETWORK_RECV_ERROR | 从服务器接收数据失败 |
10 | NET_DVR_NETWORK_RECV_TIMEOUT | 从服务器接收数据超时 |
11 | NET_DVR_NETWORK_ERRORDATA | 传送的数据有误 |
12 | NET_DVR_ORDER_ERROR | 调用次序错误 |
13 | NET_DVR_OPERNOPERMIT | 无此权限 |
14 | NET_DVR_COMMANDTIMEOUT | 设备命令执行超时 |
15 | NET_DVR_ERRORSERIALPORT | 串口号错误 |
16 | NET_DVR_ERRORALARMPORT | 报警端口错误 |
17 | NET_DVR_PARAMETER_ERROR | 参数错误 |
18 | NET_DVR_CHAN_EXCEPTION | 设备通道处于错误状态 |
19 | NET_DVR_NODISK | 设备无硬盘 |
20 | NET_DVR_ERRORDISKNUM | 硬盘号错误 |
21 | NET_DVR_DISK_FULL | 设备硬盘满 |
22 | NET_DVR_DISK_ERROR | 设备硬盘出错 |
23 | NET_DVR_NOSUPPORT | 设备不支持的操作 |
24 | NET_DVR_BUSY | 设备忙 |
25 | NET_DVR_MODIFY_FAIL | 设备修改不成功 |
26 | NET_DVR_PASSWORD_FORMAT_ERROR | 密码输入格式不正确 |
27 | NET_DVR_DISK_FORMATING | 硬盘正在格式化,不能启动操作 |
28 | NET_DVR_DVRNORESOURCE | 设备资源不足 |
29 | NET_DVR_DVROPRATEFAILED | 设备操作失败 |
30 | NET_DVR_OPENHOSTSOUND_FAIL | 打开PC声音失败 |
31 | NET_DVR_DVRVOICEOPENED | 设备语音对讲被占用 |
32 | NET_DVR_TIMEINPUTERROR | 时间输入不正确 |
33 | NET_DVR_NOSPECFILE | 回放时服务器没有指定的文件 |
34 | NET_DVR_CREATEFILE_ERROR | 创建文件出错 |
35 | NET_DVR_FILEOPENFAIL | 打开文件出错 |
36 | NET_DVR_OPERNOTFINISH | 上次的操作还没有完成 |
37 | NET_DVR_GETPLAYTIMEFAIL | 获取当前播放的时间出错 |
38 | NET_DVR_PLAYFAIL | 播放出错 |
39 | NET_DVR_FILEFORMAT_ERROR | 文件格式不正确 |
40 | NET_DVR_DIR_ERROR | 路径错误 |
41 | NET_DVR_ALLOC_RESOURCE_ERROR | 资源分配错误 |
42 | NET_DVR_AUDIO_MODE_ERROR | 声卡模式错误 |
43 | NET_DVR_NOENOUGH_BUF | 缓冲区太小 |
44 | NET_DVR_CREATESOCKET_ERROR | 创建SOCKET出错 |
45 | NET_DVR_SETSOCKET_ERROR | 设置SOCKET出错 |
46 | NET_DVR_MAX_NUM | 个数达到最大 |
47 | NET_DVR_USERNOTEXIST | 用户不存在 |
48 | NET_DVR_WRITEFLASHERROR | 写FLASH出错 |
49 | NET_DVR_UPGRADEFAIL | 设备升级失败 |
50 | NET_DVR_CARDHAVEINIT | 解码卡已经初始化过 |
51 | NET_DVR_PLAYERFAILED | 调用播放库中某个函数失败 |
52 | NET_DVR_MAX_USERNUM | 设备端用户数达到最大 |
53 | NET_DVR_GETLOCALIPANDMACFAIL | 获得客户端的IP地址或物理地址失败 |
54 | NET_DVR_NOENCODEING | 该通道没有编码 |
55 | NET_DVR_IPMISMATCH | IP地址不匹配 |
56 | NET_DVR_MACMISMATCH | MAC地址不匹配 |
57 | NET_DVR_UPGRADELANGMISMATCH | 升级文件语言不匹配 |
58 | NET_DVR_MAX_PLAYERPORT | 播放器路数达到最大 |
59 | NET_DVR_NOSPACEBACKUP | 备份设备中没有足够空间进行备份 |
60 | NET_DVR_NODEVICEBACKUP | 没有找到指定的备份设备 |
61 | NET_DVR_PICTURE_BITS_ERROR | 图像素位数不符,限24色 |
62 | NET_DVR_PICTURE_DIMENSION_ERROR | 图片高宽超限, 限128256 |
63 | NET_DVR_PICTURE_SIZ_ERROR | 图片大小超限,限100K |
64 | NET_DVR_LOADPLAYERSDKFAILED | 载入当前目录下Player Sdk出错 |
65 | NET_DVR_LOADPLAYERSDKPROC_ERROR | 找不到Player Sdk中某个函数入口 |
66 | NET_DVR_LOADDSSDKFAILED | 载入当前目录下DSsdk出错 |
67 | NET_DVR_LOADDSSDKPROC_ERROR | 找不到DsSdk中某个函数入口 |
68 | NET_DVR_DSSDK_ERROR | 调用硬解码库DsSdk中某个函数失败 |
69 | NET_DVR_VOICEMONOPOLIZE | 声卡被独占 |
70 | NET_DVR_JOINMULTICASTFAILED | 加入多播组失败 |
71 | NET_DVR_CREATEDIR_ERROR | 建立日志文件目录失败 |
72 | NET_DVR_BINDSOCKET_ERROR | 绑定套接字失败 |
73 | NET_DVR_SOCKETCLOSE_ERROR | socket连接中断,此错误通常是由于连接中断或内存状态错误 |
74 | NET_DVR_USERID_ISUSING | 注销时用户ID正在进行某操作 |
75 | NET_DVR_SOCKETLISTEN_ERROR | 监听失败 |
76 | NET_DVR_PROGRAM_EXCEPTION | 程序异常 |
77 | NET_DVR_WRITEFILE_FAILED | 写文件失败 |
78 | NET_DVR_FORMAT_READONLY | 禁止格式化只读硬盘 |
79 | NET_DVR_WITHSAMEUSERNAME | 用户配置结构中存在相同的用户名 |
80 | NET_DVR_DEVICETYPE_ERROR | 导入参数时设备型号不匹配 |
81 | NET_DVR_LANGUAGE_ERROR | 导入参数时语言不匹配 |
82 | NET_DVR_PARAVERSION_ERROR | 导入参数时软件版本不匹配 |
83 | NET_DVR_IPCHAN_NOTALIVE | 预览时外接IP通道不在线 |
84 | NET_DVR_RTSP_SDK_ERROR | 加载高清IPC通讯库StreamTransClient.dll失败 |
85 | NET_DVR_CONVERT_SDK_ERROR | 加载转码库失败 |
86 | NET_DVR_IPC_COUNT_OVERFLOW | 超出最大的IP接入通道数 |
87 | NET_PLAYM4_NOERROR | 没有错误 |
88 | NET_PLAYM4_PARA_OVER | 输入参数非法 |
89 | NET_PLAYM4_ORDER_ERROR | 调用顺序不对 |
90 | NET_PLAYM4_TIMER_ERROR | 多媒体时钟设置失败 |
91 | NET_PLAYM4_DEC_VIDEO_ERROR | 视频解码失败 |
92 | NET_PLAYM4_DEC_AUDIO_ERROR | 音频解码失败 |
93 | NET_PLAYM4_ALLOC_MEMORY_ERROR | 分配内存失败 |
94 | NET_PLAYM4_OPEN_FILE_ERROR | 文件操作失败 |
95 | NET_PLAYM4_CREATE_OBJ_ERROR | 创建线程事件等失败 |
96 | NET_PLAYM4_CREATE_DDRAW_ERROR | 创建DirectDraw对象失败 |
97 | NET_PLAYM4_CREATE_OFFSCREEN_ERROR | 创建后备缓存失败 |
98 | NET_PLAYM4_BUF_OVER | 缓冲区满,输入流失败 |
99 | NET_PLAYM4_CREATE_SOUND_ERROR | 创建音频设备失败 |
100 | NET_PLAYM4_SET_VOLUME_ERROR | 设置音量失败 |
101 | NET_PLAYM4_SUPPORT_FILE_ONLY | 只能在播放文件时才能使用此函数 |
102 | NET_PLAYM4_SUPPORT_STREAM_ONLY | 只能在播放流时才能使用此函数 |
103 | NET_PLAYM4_SYS_NOT_SUPPORT | 系统不支持,解码器可能不支持 |
104 | NET_PLAYM4_FILEHEADER_UNKNOWN | 没有文件头 |
105 | NET_PLAYM4_VERSION_INCORRECT | 解码器和编码器版本不对应 |
106 | NET_PALYM4_INIT_DECODER_ERROR | 初始化解码器失败 |
107 | NET_PLAYM4_CHECK_FILE_ERROR | 文件太短或码流无法识别 |
108 | NET_PLAYM4_INIT_TIMER_ERROR | 初始化多媒体时钟失败 |
109 | NET_PLAYM4_BLT_ERROR | 位拷贝失败 |
110 | NET_PLAYM4_UPDATE_ERROR | 显示overlay失败 |
111 | NET_PLAYM4_OPEN_FILE_ERROR_MULTI | 打开文件错误,音视频数据不匹配 |
112 | NET_PLAYM4_OPEN_FILE_ERROR_VIDEO | 打开文件错误,脱音频数据不存在 |
113 | NET_PLAYM4_JPEG_COMPRESS_ERROR | JPEG压缩错误 |
114 | NET_PLAYM4_EXTRACT_NOT_SUPPORT | 不支持该文件版本 |
115 | NET_PLAYM4_EXTRACT_DATA_ERROR | 提取文件数据失败 |
116 | NET_PLAYM4_SECRET_KEY_ERROR | 解密密钥错误 |
117 | NET_PLAYM4_DECRYPT_ERROR | 解密错误 |
118 | NET_PLAYM4_RENDER_LOCK_ERROR | 渲染库资源锁定失败 |
119 | NET_PLAYM4_DEC_REPORT_UNSUPPORT | 解码器不支持的功能 |
120 | NET_PLAYM4_DEC_VIDEO_ERROR_MULTI | 多路解码时,某路解码失败 |
121 | NET_PLAYM4_INVALID_PORT | 无效的端口号 |
122 | NET_PLAYM4_NOT_FIND | 查找失败 |
123 | NET_PLAYM4_NEED_MORE_DATA | 需要更多的数据才能解析 |
124 | NET_PLAYM4_INVALID_MAIN_HANDLE | 无效的句柄 |
125 | NET_PLAYM4_INVALID_HANDLE | 无效的句柄 |
126 | NET_PLAYM4_INVALID_PARA | 无效的参数 |
127 | NET_PLAYM4_INVALID_FORMAT | 无效的文件格式 |
结语
通过以上的详细介绍,相信大家对如何在项目中与海康威视录像机进行数据交互、精准截取回放片段有了较为清晰的认识。
从环境搭建的细致筹备,到代码编写的关键要点,每一步都凝聚着我们团队实践探索的心血。在实际操作过程中,大家可能还会遇到一些诸如兼容性问题、网络波动影响数据传输等小波折,但只要依据海康威视提供的官方文档,结合我们分享的这些实战经验,逐步排查、耐心调试,定能攻克难关。
希望这篇博客能成为您开启相关项目开发的得力助手,助力您的业务一路畅行。倘若后续您在实践中有任何新的疑问、心得或是优化建议,欢迎随时交流分享,让我们携手在技术探索的道路上不断前行,共同解锁更多项目开发的新技能。