Java海康SDK二次开发中遇到的常见挑战及解决方案

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二次开发时能够更加顺利地进行开发。

后端开发标签