1. 前言
海康威视作为国内知名的视频监控解决方案提供商,其SDK也得到了广泛的应用。而Java海康SDK二次开发作为其应用范畴,也吸引了越来越多的开发者的关注。但是在实际的开发中,也会遇到一些常见挑战和问题。本文主要介绍在Java海康SDK二次开发中遇到的常见挑战及解决方案。
2. SDK版本兼容性问题
2.1 SDK版本选择
在进行Java海康SDK二次开发时,常见的问题就是SDK版本的选择。由于不同的SDK版本会有不同的兼容性问题,因此需要仔细考虑版本的选择。一般来说,建议选择较新的SDK版本,并确保使用的SDK版本与开发环境兼容。
2.2 版本兼容性问题
在使用不同的SDK版本时,还需要注意版本兼容性问题。有时候,使用较新的SDK版本在旧的设备上可能会出现兼容性问题,而使用旧的SDK版本在新的设备上可能会出现无法使用的问题。这时需要对SDK版本进行升级或降级。
以下是一个降级示例:
HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
hCNetSDK.NET_DVR_Init();
hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
hCNetSDK.NET_DVR_SetReconnect(10000, true);
// 查询SDK版本
System.out.println(hCNetSDK.NET_DVR_GetSDKVersion());
// 手动选择版本
hCNetSDK.NET_DVR_SetSDKInitCfg(HCNetSDK.NET_DVR_SDKLOCAL_CFG_TYPE.NET_DVR_SDK_LOCAL_GENERAL_CFG, new WinDef.INT_PTR(new Pointer(2)), 4, null);
// 降级为SDK v2.4.1.1版本
System.out.println(hCNetSDK.NET_DVR_GetSDKVersion());
3. 网络连接问题
3.1 连接超时问题
在调用海康SDK的API时,有时会出现连接超时问题。这是由于网络连接不稳定或者设备负载较高导致的。出现这种问题时,一般建议增加等待时间并重试。
以下是一个重试示例:
public void login(String ip, String username, String password) {
HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
NativeLong userID = new NativeLong(-1);
HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
int iRetryTime = 3; // 最多重试3次
// 登录失败后,循环重试,直到登录成功或达到最大重试次数
while (iRetryTime-- > 0 && userID.intValue() == -1) {
userID = hCNetSDK.NET_DVR_Login_V30(ip, (short) 8000, username, password, deviceInfo);
if (userID.intValue() == -1) {
System.out.println("NET_DVR_Login_V30 failed with:" + hCNetSDK.NET_DVR_GetLastError());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (userID.intValue() != -1) {
// 登录成功,处理后续逻辑
}
}
3.2 安全认证问题
在连接海康设备时,有些设备会开启安全认证模式。在开启该模式的情况下,使用默认的登录名和密码是无法进行连接的。需要使用设备管理员设置的用户名和密码进行连接。
以下是一个登录示例:
public void login(String ip, String username, String password) {
HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
NativeLong userID = new NativeLong(-1);
HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
// 连接超时时间设置为5s
hCNetSDK.NET_DVR_SetConnectTime(5000, 1);
// 尝试使用默认用户名和密码登录
userID = hCNetSDK.NET_DVR_Login_V30(ip, (short) 8000, username, password, deviceInfo);
if (userID.intValue() == -1) {
// 使用设备管理员设置的用户名和密码登录
SC_UserLoginStruct loginInfo = new SC_UserLoginStruct();
Pointer pointer = loginInfo.getPointer();
loginInfo.read();
loginInfo.charEncodeType = "GB2312".getBytes();
loginInfo.wUserName = "admin".getBytes();
loginInfo.wPassword = "12345".getBytes();
int serverIndex = hCNetSDK.NET_DVR_LoginWithHighLevelSecurity(ip, (short) 8000, loginInfo, pointer);
if (serverIndex >= 0) {
userID = new NativeLong(serverIndex);
}
}
if (userID.intValue() != -1) {
// 登录成功,处理后续逻辑
}
}
4. 抓图和录像操作
4.1 抓图
在进行抓图操作时,需要注意一些细节。比如指定抓图缩略图大小、文件名以及格式等。在抓图后,还需要根据返回值进行异常处理和结果判断。
以下是一个抓图示例:
public void snapPicture(NativeLong lRealHandle, String outputFile, int quality) {
HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
// 抓图缩略图的大小,要求长宽比为4:3
int thumbWidth = 640;
int thumbHeight = 480;
// 抓图的文件名和格式
String fileName = outputFile.substring(outputFile.lastIndexOf("\\")+1);
String filePath = outputFile.substring(0, outputFile.lastIndexOf("\\")+1);
String format = fileName.substring(fileName.lastIndexOf(".")+1);
// 开始抓图
HCNetSDK.BYTE_ARRAY ptrPicByte = new HCNetSDK.BYTE_ARRAY(thumbWidth*thumbHeight);
int iLen = 0;
if (!hCNetSDK.NET_DVR_CapturePicture(lRealHandle, filePath)) {
System.out.println("NET_DVR_CapturePicture failed with:" + hCNetSDK.NET_DVR_GetLastError());
} else {
// 成功抓图,获取图片数据并保存
iLen = hCNetSDK.NET_DVR_GetLastError();
if (iLen > 0) {
hCNetSDK.NET_DVR_GetPicStream(lRealHandle, ptrPicByte.getPointer(), iLen);
FileOutputStream fout;
try {
fout = new FileOutputStream(outputFile);
// 把图片写到文件中,quality取值0-100
BufferedImage bi = ImageIO.read(new ByteArrayInputStream(ptrPicByte.byValue));
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fout);
JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(bi);
jep.setQuality(quality, true);
encoder.encode(bi, jep);
fout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
4.2 录像回放
在进行录像回放操作时,需要注意一些细节。比如录像回放的时间段、存储路径以及格式等。在录像回放后,还需要根据返回值进行异常处理和结果判断。
以下是一个录像回放示例:
public void playback(NativeLong lUserID, NativeLong lChannel, String outputFile, Date startTime, Date endTime) {
HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
// 录像回放的存储路径和格式
String fileName = outputFile.substring(outputFile.lastIndexOf("\\")+1);
String filePath = outputFile.substring(0, outputFile.lastIndexOf("\\")+1);
String format = fileName.substring(fileName.lastIndexOf(".")+1);
// 开始录像回放
HCNetSDK.NET_DVR_TIME startTimeDvr = new HCNetSDK.NET_DVR_TIME();
HCNetSDK.NET_DVR_TIME endTimeDvr = new HCNetSDK.NET_DVR_TIME();
if (startTime != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(startTime);
startTimeDvr.dwYear = calendar.get(Calendar.YEAR);
startTimeDvr.dwMonth = calendar.get(Calendar.MONTH) + 1;
startTimeDvr.dwDay = calendar.get(Calendar.DATE);
startTimeDvr.dwHour = calendar.get(Calendar.HOUR_OF_DAY);
startTimeDvr.dwMinute = calendar.get(Calendar.MINUTE);
startTimeDvr.dwSecond = calendar.get(Calendar.SECOND);
}
if (endTime != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(endTime);
endTimeDvr.dwYear = calendar.get(Calendar.YEAR);
endTimeDvr.dwMonth = calendar.get(Calendar.MONTH) + 1;
endTimeDvr.dwDay = calendar.get(Calendar.DATE);
endTimeDvr.dwHour = calendar.get(Calendar.HOUR_OF_DAY);
endTimeDvr.dwMinute = calendar.get(Calendar.MINUTE);
endTimeDvr.dwSecond = calendar.get(Calendar.SECOND);
}
NativeLong lPlayHandle = hCNetSDK.NET_DVR_PlayBackByTime_V40(lUserID, lChannel,
startTimeDvr, endTimeDvr, null);
if (lPlayHandle.intValue() == -1) {
System.out.println("NET_DVR_PlayBackByTime_V40 failed with:" + hCNetSDK.NET_DVR_GetLastError());
} else {
if (!hCNetSDK.NET_DVR_PlayBackControl(lPlayHandle, HCNetSDK.NET_DVR_PLAYSTART, 0, null)) {
System.out.println("NET_DVR_PlayBackControl failed with:" + hCNetSDK.NET_DVR_GetLastError());
} else {
// 录像回放中,模拟实时的视频画面并输出到文件中
FileOutputStream outPutDebug = null;
try {
outPutDebug = new FileOutputStream(outputFile);
HCNetSDK.NET_DVR_PLAYINFO playInfo = new HCNetSDK.NET_DVR_PLAYINFO();
while (playInfo.lPlayBackPos < 100 && playInfo.lPlayBackPos >= 0) {
hCNetSDK.NET_DVR_GetPlayBackPos(lPlayHandle, playInfo);
if (playInfo.dwTotalFrames != 0 && playInfo.dwTotalFrames <= playInfo.dwCurFrames) {
// 播放结束,退出循环
break;
}
HCNetSDK.NET_DVR_YUV_DATA_CALLBACK_V40 yuvDataCallBack =
new HCNetSDK.NET_DVR_YUV_DATA_CALLBACK_V40() {
@Override
public void invoke(NativeLong lPlayHandle, Pointer pYuvBuffer,
int lYuvBufferLen, int frameInfo, Pointer pUserData) {
// 获取yuv数据并输出到文件中
OutputStream fw = (OutputStream) pUserData;
try {
byte[] buffer = pYuvBuffer.getByteArray(0, lYuvBufferLen);
fw.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
};
yuvDataCallBack.setUserParam(outPutDebug);
hCNetSDK.NET_DVR_SetYV12Display(lPlayHandle, true);
hCNetSDK.NET_DVR_SetYV12DataCallBack_V40(lPlayHandle, yuvDataCallBack, outPutDebug);
Thread.sleep(40);
}
// 登录成功,处理后续逻辑
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
outPutDebug.flush();
outPutDebug.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
5. 总结
本文主要介绍了在Java海康SDK二次开发中遇到的常见挑战及解决方案,包括SDK版本兼容性问题、网络连接问题以及抓图和录像操作等。这些问题在实际的开发中是比较常见的,需要开发者注意。通过本文的介绍,相信开发者们在进行Java海康SDK二次开发时能够更加顺利地进行开发。