package com.ard.work.sdk.service; import com.ard.common.core.constant.CacheConstants; import com.ard.common.core.exception.ServiceException; import com.ard.common.core.exception.device.CameraSDKException; import com.ard.common.core.web.domain.AjaxResult; import com.ard.common.redis.service.RedisService; import com.ard.common.security.utils.SecurityUtils; import com.ard.work.api.domian.*; import com.ard.work.device.camera.domain.PtzParamDTO; import com.ard.work.device.noview.domain.ArdNoViewingZone; import com.ard.work.device.noview.service.IArdNoViewingZoneService; import com.ard.work.sdk.annotation.SdkOperate; import com.ard.work.sdk.common.RecordManager; import com.ard.work.sdk.factory.CameraSDKFactory; import com.ard.work.sdk.model.DeviceCFG; import com.ard.work.sdk.model.PtzScope; import com.ard.work.utils.gis.GisUtil; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; @Service @Slf4j public class CameraSDKService { @Resource private RedisService redisService; @Resource private CameraSDKFactory cameraSDKFactory; @Resource private IArdNoViewingZoneService ardNoViewingZoneService; // ========== 基础操作 ========== @Async("cameraSdkExecutor") public void login(ArdCamera ardCamera) { if (ardCamera == null) { throw CameraSDKException.cameraNotExist(null); } CameraSDK sdk = cameraSDKFactory.createCameraSDK(ardCamera.getFactory()); sdk.login(ardCamera); } public void logout(String cameraId) { ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cameraId); if (ardCamera == null || ardCamera.getFactory() == null) { return; } CameraSDK sdk = cameraSDKFactory.createCameraSDK(ardCamera.getFactory()); sdk.logout(cameraId); } // ========== 简单操作(一行搞定) ========== @SdkOperate public Boolean pTZControl(CameraCmd cmd) { return getSdk(cmd).pTZControl(cmd); } public Boolean setFocusPos(CameraCmd cmd) { return getSdk(cmd).setFocusPos(cmd); } public Integer getFocusPos(CameraCmd cmd) { return getSdk(cmd).getFocusPos(cmd); } public Boolean setPreset(CameraCmd cmd) { return getSdk(cmd).setPreset(cmd); } public Boolean gotoPreset(CameraCmd cmd) { return getSdk(cmd).gotoPreset(cmd); } public VideoCompressionCfg getVideoCompressionCfg(CameraCmd cmd) { return getSdk(cmd).getVideoCompressionCfg(cmd); } public Boolean controlDefog(CameraCmd cmd) { return getSdk(cmd).controlDefog(cmd); } public Boolean isEnableDefog(CameraCmd cmd) { return getSdk(cmd).isEnableDefog(cmd); } public Boolean controlInfrared(CameraCmd cmd) { return getSdk(cmd).controlInfrared(cmd); } public Boolean isEnableInfrared(CameraCmd cmd) { return getSdk(cmd).isEnableInfrared(cmd); } public Boolean controlFocusMode(CameraCmd cmd) { return getSdk(cmd).controlFocusMode(cmd); } public Boolean getFocusMode(CameraCmd cmd) { return getSdk(cmd).getFocusMode(cmd); } public Boolean controlPTHeater(CameraCmd cmd) { return getSdk(cmd).controlPTHeater(cmd); } public Boolean controlCameraDeicing(CameraCmd cmd) { return getSdk(cmd).controlCameraDeicing(cmd); } public Boolean getPTZLockInfo(CameraCmd cmd) { return getSdk(cmd).getPTZLockInfo(cmd); } public Boolean setPTZLockInfo(CameraCmd cmd) { return getSdk(cmd).setPTZLockInfo(cmd); } public byte[] localCapture(CameraCmd cmd) { return getSdk(cmd).localCapture(cmd); } public PtzScope getPtzScope(CameraCmd cmd) { return getSdk(cmd).getPtzScope(cmd); } public Boolean setZeroPtz(CameraCmd cmd) { return getSdk(cmd).setZeroPtz(cmd); } public Boolean set3DPosition(CameraCmd cmd) { return getSdk(cmd).set3DPosition(cmd); } public PtzParamDTO getGisInfo(CameraCmd cmd) { return getSdk(cmd).getGisInfo(cmd); } public Double correctPitch(CameraCmd cmd) { return getSdk(cmd).correctPitch(cmd); } // ========== 需要判断类型的操作 ========== public PtzDto getPtz(CameraCmd cmd) { return getSdk(cmd).getPtz(cmd); } @SdkOperate public Boolean setPtz(CameraCmd cmd) { return getSdk(cmd).setPtz(cmd); } // ========== 抓图(重载方法) ========== @SdkOperate public String picCutCate(CameraCmd cmd) { return getSdk(cmd).picCutCate(cmd); } @SdkOperate public String picCutCate(CameraCmd cmd, String bucketName, String objectName) { return getSdk(cmd).picCutCate(cmd, bucketName, objectName); } // ========== 录像 ========== public String record(CameraCmd cmd) { return getSdk(cmd).record(cmd); } public Boolean recordStart(CameraCmd cmd) { CameraSDK sdk = getSdk(cmd); Boolean result = sdk.recordStart(cmd); if (result != null && result) { RecordManager.addRecord(cmd.getCameraId() + "_" + cmd.getChanNo()); } return result; } public String recordStop(CameraCmd cmd) { CameraSDK sdk = getSdk(cmd); String url = sdk.recordStop(cmd); String key = cmd.getCameraId() + "_" + cmd.getChanNo(); RecordManager.stopRecord(key); return url; } // ========== 智能引导 ========== @SdkOperate public Boolean guideTargetPosition(CameraCmd cmd) { CameraSDK sdk = getSdk(cmd); ArdCamera camera = getCamera(cmd.getCameraId()); String cameraId = camera.getId(); // 判断是否超出引导距离 if (isOutMaxDistance(cameraId, cmd.getTargetPosition())) { throw new CameraSDKException(CameraSDKException.ErrorCode.OVER_GUIDANCE_RANGE.getCode(), cameraId, "目标超出最大引导距离"); } // 判断是否在不可视域 if (isInNoViewingZone(cameraId, cmd.getTargetPosition())) { throw new CameraSDKException(CameraSDKException.ErrorCode.BEYOND_VISIBILITY_RANGE.getCode(), cameraId, "目标在不可视区域内"); } cmd.setBaseYaw(camera.getBaseYaw()); return sdk.guideTargetPosition(cmd); } // ========== 在线检测 ========== public boolean isOnLine(CameraCmd cmd) { Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId()); if (loginId == null) { return false; } cmd.setLoginId(loginId); CameraSDK sdk = getSdk(cmd); return sdk.isOnLine(cmd); } // ========== 通道信息 ========== public List getChannels(ArdCamera camera) { Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, camera.getId()); if (loginId == null) { return new ArrayList<>(); } CameraSDK sdk = cameraSDKFactory.createCameraSDK(camera.getFactory()); return sdk.getChannels(camera); } // ========== 视频标签 ========== public AjaxResult getCameraVideoLable(CameraCmd cmd) { CameraSDK sdk = cameraSDKFactory.createCameraSDK("1"); // 硬编码问题建议修复 try { List> result = sdk.getCameraVideoLable(SecurityUtils.getUserId(), cmd); return AjaxResult.success(result); } catch (ServiceException e) { return AjaxResult.error(e.getMessage()); } } // ========== 定时任务 ========== @Scheduled(fixedRate = 30 * 1000) public void checkVideoTimeout() { Date now = new Date(); RecordManager.getActiveRecords().forEach((name, date) -> { long duration = now.getTime() - date.getTime(); if (duration > 15 * 60 * 1000) { CameraCmd cmd = new CameraCmd(); String cameraId = name.split("_")[0]; Integer chanNo = Integer.parseInt(name.split("_")[1]); cmd.setCameraId(cameraId); cmd.setChanNo(chanNo); recordStop(cmd); log.info("录像超时检测:停止{}_{}的录像,已录像时间超过15分钟", cameraId, chanNo); } }); } // ========== 私有辅助方法 ========== /** * 获取SDK实例(会校验参数、相机存在性、在线状态) */ private CameraSDK getSdk(CameraCmd cmd) { if (cmd == null || cmd.getCameraId() == null || cmd.getCameraId().isBlank()) { throw CameraSDKException.cameraNotExist(null); } Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId()); if (loginId == null) { throw CameraSDKException.cameraOffline(cmd.getCameraId()); } cmd.setLoginId(loginId); ArdCamera camera = getCamera(cmd.getCameraId()); return cameraSDKFactory.createCameraSDK(camera.getFactory()); } /** * 获取相机信息(会校验存在性) */ private ArdCamera getCamera(String cameraId) { ArdCamera camera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cameraId); if (camera == null) { throw CameraSDKException.cameraNotExist(cameraId); } return camera; } // 判断坐标是否超出引导范围 private Boolean isOutMaxDistance(String cameraId, Point targetPoint) { ArdCamera camera = getCamera(cameraId); Point cameraCoordinate = new Point(camera.getLongitude(), camera.getLatitude(), camera.getAltitude()); double distance = GisUtil.getDistance(cameraCoordinate, targetPoint); if (camera.getCamMaxVisibleDistance() == null) { throw new CameraSDKException(CameraSDKException.ErrorCode.CAMERA_MAX_VISIBLE_DISTANCE_NULL.getCode(), cameraId, CameraSDKException.ErrorCode.CAMERA_MAX_VISIBLE_DISTANCE_NULL.getMsg()); } return distance > camera.getCamMaxVisibleDistance(); } // 判断坐标是否在不可视域 private Boolean isInNoViewingZone(String cameraId, Point targetPoint) { ArdNoViewingZone query = new ArdNoViewingZone(); query.setCameraId(cameraId); List zones = ardNoViewingZoneService.selectArdNoViewingZoneList(query); if (zones.isEmpty()) { return false; } List points = new ArrayList<>(); for (ArdNoViewingZone zone : zones) { String[] parts = zone.getPoi().split(","); for (int i = 0; i < parts.length; i += 3) { Point point = new Point(); point.setLongitude(Double.valueOf(parts[i])); point.setLatitude(Double.valueOf(parts[i + 1])); points.add(point); } } return GisUtil.isInPolygon(targetPoint, points); } }