|
|
|
@ -39,27 +39,72 @@ public class ImageCaptureService {
|
|
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
@Resource
|
|
|
|
private AppConfig appConfig;
|
|
|
|
private AppConfig appConfig;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SDK是否可用:DLL缺失/加载失败/版本不匹配时为false,此时所有相机操作直接返回,不影响主流程
|
|
|
|
|
|
|
|
private volatile boolean sdkAvailable = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 是否已尝试过初始化(避免反复尝试加载不存在的DLL)
|
|
|
|
|
|
|
|
private volatile boolean sdkInitTried = false;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 构造函数,初始化SDK
|
|
|
|
* 构造函数,初始化SDK
|
|
|
|
|
|
|
|
* 注意:未配置海康相机时不初始化SDK,也不会去加载任何DLL
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@PostConstruct
|
|
|
|
@PostConstruct
|
|
|
|
public void init() {
|
|
|
|
public void init() {
|
|
|
|
|
|
|
|
List<AppConfig.Camera> cameras = appConfig.getHikCamera();
|
|
|
|
|
|
|
|
if (cameras == null || cameras.isEmpty()) {
|
|
|
|
|
|
|
|
log.info("未配置海康相机(hikCamera),跳过SDK初始化,不加载相机DLL");
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
initSdkAndCameras(cameras);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 初始化SDK并打开配置的相机。
|
|
|
|
|
|
|
|
* 任何异常或错误(UnsatisfiedLinkError/NoSuchFieldError/NoClassDefFoundError 等)都只记录日志,
|
|
|
|
|
|
|
|
* 绝不向上抛出,避免影响 Spring 容器启动。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param cameras 相机配置,可为空
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private synchronized void initSdkAndCameras(List<AppConfig.Camera> cameras) {
|
|
|
|
|
|
|
|
if (sdkInitTried || !sdkAvailable) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sdkInitTried = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int nRet;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
log.info("初始化海康相机SDK...");
|
|
|
|
log.info("初始化海康相机SDK...");
|
|
|
|
int nRet = MvCameraControl.MV_CC_Initialize();
|
|
|
|
nRet = MvCameraControl.MV_CC_Initialize();
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
log.error("海康相机SDK加载失败(DLL缺失或版本不匹配),相机功能不可用: {}", t.toString());
|
|
|
|
|
|
|
|
sdkAvailable = false;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (MV_OK != nRet) {
|
|
|
|
if (MV_OK != nRet) {
|
|
|
|
log.error("初始化SDK失败,errcode: [0x{}]", Integer.toHexString(nRet));
|
|
|
|
log.error("初始化SDK失败,errcode: [0x{}]", Integer.toHexString(nRet));
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
isSdkInitialized = true;
|
|
|
|
isSdkInitialized = true;
|
|
|
|
|
|
|
|
try {
|
|
|
|
log.info("SDK Version: {}", MV_CC_GetSDKVersion());
|
|
|
|
log.info("SDK Version: {}", MV_CC_GetSDKVersion());
|
|
|
|
log.info("SDK初始化成功");
|
|
|
|
log.info("SDK初始化成功");
|
|
|
|
|
|
|
|
if (cameras != null && !cameras.isEmpty()) {
|
|
|
|
|
|
|
|
initCamerasFromConfig(cameras);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (appConfig.getHikCamera() != null && !appConfig.getHikCamera().isEmpty()){
|
|
|
|
} catch (Throwable t) {
|
|
|
|
initCamerasFromConfig(appConfig.getHikCamera());
|
|
|
|
log.error("SDK初始化后处理异常", t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("初始化SDK异常", e);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* SDK是否可用(DLL已加载且初始化成功)
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public boolean isSdkAvailable() {
|
|
|
|
|
|
|
|
return sdkAvailable && isSdkInitialized;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
@ -67,6 +112,10 @@ public class ImageCaptureService {
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@PreDestroy
|
|
|
|
@PreDestroy
|
|
|
|
public void destroy() {
|
|
|
|
public void destroy() {
|
|
|
|
|
|
|
|
if (!sdkAvailable) {
|
|
|
|
|
|
|
|
handleMap.clear();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
log.info("开始清理相机资源...");
|
|
|
|
log.info("开始清理相机资源...");
|
|
|
|
|
|
|
|
|
|
|
|
// 停止抓图并销毁所有句柄
|
|
|
|
// 停止抓图并销毁所有句柄
|
|
|
|
@ -90,6 +139,8 @@ public class ImageCaptureService {
|
|
|
|
log.info("相机 {} 资源已清理", ip);
|
|
|
|
log.info("相机 {} 资源已清理", ip);
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
log.error("清理相机 {} 资源时发生异常", ip, e);
|
|
|
|
log.error("清理相机 {} 资源时发生异常", ip, e);
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
log.warn("清理相机 {} 资源时失败(SDK不可用)", ip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -102,6 +153,8 @@ public class ImageCaptureService {
|
|
|
|
log.info("SDK反初始化成功");
|
|
|
|
log.info("SDK反初始化成功");
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
log.error("SDK反初始化异常", e);
|
|
|
|
log.error("SDK反初始化异常", e);
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
log.warn("SDK反初始化失败(SDK不可用)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -112,6 +165,13 @@ public class ImageCaptureService {
|
|
|
|
* @return 成功初始化的相机数量
|
|
|
|
* @return 成功初始化的相机数量
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public int initCameras(List<String> ipList) {
|
|
|
|
public int initCameras(List<String> ipList) {
|
|
|
|
|
|
|
|
if (!sdkAvailable) {
|
|
|
|
|
|
|
|
log.warn("海康相机SDK不可用(DLL未加载),跳过相机初始化");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
|
|
|
|
initSdkAndCameras(appConfig.getHikCamera());
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
log.error("SDK未初始化,无法初始化相机");
|
|
|
|
log.error("SDK未初始化,无法初始化相机");
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
@ -133,8 +193,10 @@ public class ImageCaptureService {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.info("枚举到 {} 个设备", stDeviceList.size());
|
|
|
|
log.info("枚举到 {} 个设备", stDeviceList.size());
|
|
|
|
} catch (CameraControlException e) {
|
|
|
|
} catch (Throwable e) {
|
|
|
|
log.error("枚举设备失败", e);
|
|
|
|
log.error("枚举设备失败,SDK不可用: {}", e.toString());
|
|
|
|
|
|
|
|
sdkAvailable = false;
|
|
|
|
|
|
|
|
isSdkInitialized = false;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -238,6 +300,9 @@ public class ImageCaptureService {
|
|
|
|
} catch (CameraControlException e) {
|
|
|
|
} catch (CameraControlException e) {
|
|
|
|
log.error("相机 {} 初始化异常", ip, e);
|
|
|
|
log.error("相机 {} 初始化异常", ip, e);
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
log.error("相机 {} 初始化失败(SDK不可用)", ip, t);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -259,6 +324,13 @@ public class ImageCaptureService {
|
|
|
|
* @return 是否成功
|
|
|
|
* @return 是否成功
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private boolean captureImage(String ip, String savePath, boolean isRetry) {
|
|
|
|
private boolean captureImage(String ip, String savePath, boolean isRetry) {
|
|
|
|
|
|
|
|
if (!sdkAvailable) {
|
|
|
|
|
|
|
|
log.warn("海康相机SDK不可用(DLL未加载),跳过拍照: {}", ip);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
|
|
|
|
initSdkAndCameras(appConfig.getHikCamera());
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
log.error("SDK未初始化");
|
|
|
|
log.error("SDK未初始化");
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
@ -326,6 +398,9 @@ public class ImageCaptureService {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
log.error("拍照失败(SDK不可用)", t);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -455,17 +530,17 @@ public class ImageCaptureService {
|
|
|
|
if (hCamera == null) return;
|
|
|
|
if (hCamera == null) return;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
MvCameraControl.MV_CC_StopGrabbing(hCamera);
|
|
|
|
MvCameraControl.MV_CC_StopGrabbing(hCamera);
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Throwable e) {
|
|
|
|
log.warn("相机 {} 停止抓图异常", ip, e);
|
|
|
|
log.warn("相机 {} 停止抓图异常", ip, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
MvCameraControl.MV_CC_CloseDevice(hCamera);
|
|
|
|
MvCameraControl.MV_CC_CloseDevice(hCamera);
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Throwable e) {
|
|
|
|
log.warn("相机 {} 关闭设备异常", ip, e);
|
|
|
|
log.warn("相机 {} 关闭设备异常", ip, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
MvCameraControl.MV_CC_DestroyHandle(hCamera);
|
|
|
|
MvCameraControl.MV_CC_DestroyHandle(hCamera);
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Throwable e) {
|
|
|
|
log.warn("相机 {} 销毁句柄异常", ip, e);
|
|
|
|
log.warn("相机 {} 销毁句柄异常", ip, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.info("相机 {} 句柄已销毁", ip);
|
|
|
|
log.info("相机 {} 句柄已销毁", ip);
|
|
|
|
@ -476,6 +551,10 @@ public class ImageCaptureService {
|
|
|
|
* @return 新句柄,失败返回null
|
|
|
|
* @return 新句柄,失败返回null
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private Handle reconnectCamera(String ip) {
|
|
|
|
private Handle reconnectCamera(String ip) {
|
|
|
|
|
|
|
|
if (!sdkAvailable) {
|
|
|
|
|
|
|
|
log.warn("海康相机SDK不可用(DLL未加载),跳过重连: {}", ip);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
log.warn("相机 {} 开始重连...", ip);
|
|
|
|
log.warn("相机 {} 开始重连...", ip);
|
|
|
|
destroyCameraHandle(ip);
|
|
|
|
destroyCameraHandle(ip);
|
|
|
|
|
|
|
|
|
|
|
|
@ -495,6 +574,11 @@ public class ImageCaptureService {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
log.warn("相机 {} 重连异常(第{}/{}次)", ip, i, RECONNECT_MAX_RETRIES, e);
|
|
|
|
log.warn("相机 {} 重连异常(第{}/{}次)", ip, i, RECONNECT_MAX_RETRIES, e);
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
log.warn("相机 {} 重连失败(SDK不可用)", ip, t);
|
|
|
|
|
|
|
|
sdkAvailable = false;
|
|
|
|
|
|
|
|
isSdkInitialized = false;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (i < RECONNECT_MAX_RETRIES) {
|
|
|
|
if (i < RECONNECT_MAX_RETRIES) {
|
|
|
|
@ -520,6 +604,13 @@ public class ImageCaptureService {
|
|
|
|
public List<String> captureBatch(String ip, String basePath, int count) {
|
|
|
|
public List<String> captureBatch(String ip, String basePath, int count) {
|
|
|
|
List<String> successPaths = new ArrayList<>();
|
|
|
|
List<String> successPaths = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!sdkAvailable) {
|
|
|
|
|
|
|
|
log.warn("海康相机SDK不可用(DLL未加载),跳过拍照: {}", ip);
|
|
|
|
|
|
|
|
return successPaths;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
|
|
|
|
initSdkAndCameras(appConfig.getHikCamera());
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
if (!isSdkInitialized) {
|
|
|
|
log.error("SDK未初始化");
|
|
|
|
log.error("SDK未初始化");
|
|
|
|
return successPaths;
|
|
|
|
return successPaths;
|
|
|
|
|