From ab00d30e72fea3b9cb33dc065861e92e5d0eeb14 Mon Sep 17 00:00:00 2001
From: aijinhui <aijinhui>
Date: Sat, 21 Oct 2023 14:09:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 ard-work/src/main/java/com/ruoyi/device/dhsdk/service/IDhClientService.java                   |   24 
 ard-work/src/main/resources/templates/test.html                                               |  102 
 ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java                        |    4 
 ard-work/src/main/java/com/ruoyi/utils/tools/ArdTool.java                                     |   16 
 ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/HCNetSDK.java                              |    2 
 ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java                             |    5 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java                                |   26 
 ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java         |  230 ++-
 ard-work/src/main/java/com/ruoyi/device/dhsdk/module/ConfigModule.java                        |   96 +
 ard-work/src/main/java/com/ruoyi/media/domain/Items.java                                      |   11 
 ard-work/src/main/java/com/ruoyi/media/service/impl/MediaV2ServiceImpl.java                   |  490 +++++++++
 ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/HikSdkController.java               |   25 
 ard-work/src/main/java/com/ruoyi/device/dhsdk/module/RealPlayModule.java                      |   17 
 ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java                      |   20 
 ard-work/src/main/java/com/ruoyi/device/dhsdk/module/PtzControlModule.java                    |   14 
 ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS_UNIT.java      |   54 
 lib/mediamtx/mediamtx.exe                                                                     |    0 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java                                |   17 
 ard-work/src/main/java/com/ruoyi/device/dhsdk/controller/DhSdkController.java                 |    5 
 ard-work/src/main/java/com/ruoyi/inspect/service/impl/ArdVideoInspectTaskServiceImpl.java     |   11 
 ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS.java           |   44 
 lib/mediamtx/mediamtx.yml                                                                     |  594 ++++++----
 ard-work/src/main/java/com/ruoyi/media/domain/Conf.java                                       |  123 --
 ard-work/src/main/java/com/ruoyi/device/camera/controller/ArdCamerasController.java           |   31 
 ard-work/src/main/java/com/ruoyi/device/camera/domain/CameraCmd.java                          |   10 
 ard-work/src/main/java/com/ruoyi/device/dhsdk/service/impl/DhClientServiceImpl.java           |  399 ++++++
 ard-work/src/main/java/com/ruoyi/device/camera/controller/CameraSdkController.java            |   19 
 ard-work/src/main/java/com/ruoyi/device/hiksdk/service/IHikClientService.java                 |   15 
 ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java                           |   65 +
 ard-work/src/main/resources/templates/preview.html                                            |    8 
 ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/enumeration/EM_FOCUS_LIMIT_SELECT_MODE.java |   50 
 ard-work/src/main/java/com/ruoyi/utils/forest/MediaClientV2.java                              |  100 +
 ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/QueueTaskExecutor.java             |   13 
 ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java                                |   17 
 lib/mediamtx/LICENSE                                                                          |    5 
 ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java                     |  130 +-
 ard-work/src/main/java/com/ruoyi/device/hiksdk/service/impl/HikClientServiceImpl.java         |  330 +++--
 ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java                         |   26 
 ruoyi-admin/src/main/resources/logback.xml                                                    |   17 
 ard-work/src/main/java/com/ruoyi/device/camera/service/ICameraSdkService.java                 |   28 
 ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java        |    1 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/SdkOperateAspect.java               |    2 
 ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/LoginResultCallBack.java                   |   27 
 43 files changed, 2,189 insertions(+), 1,034 deletions(-)

diff --git a/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/QueueTaskExecutor.java b/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/QueueTaskExecutor.java
index b4b12e0..dfce1a1 100644
--- a/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/QueueTaskExecutor.java
+++ b/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/QueueTaskExecutor.java
@@ -15,7 +15,7 @@
 import com.ruoyi.alarm.tube.service.IArdAlarmTubeService;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.device.camera.domain.CameraCmd;
-import com.ruoyi.device.hiksdk.service.IHikClientService;
+import com.ruoyi.device.camera.service.ICameraSdkService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
@@ -39,7 +39,7 @@
     @Resource
     IArdAlarmRadarPumpService ardAlarmRadarPumpService;
     @Resource
-    IHikClientService hikClientService;
+    ICameraSdkService cameraSdkService;
     @Resource
     IArdAlarmTubeService ardAlarmTubeService;
 
@@ -47,6 +47,7 @@
     IArdAlarmExternalService ardAlarmExternalService;
     @Resource
     IArdAlarmAccessService ardAlarmAccessService;
+
     public void processTask(GuideTask guideTask) {
         try {
             CameraCmd cmd = new CameraCmd();
@@ -58,17 +59,17 @@
             cmd.setRecordBucketName("record");
             cmd.setRecordObjectName("alarm_" + guideTask.getAlarmId());
             log.debug("开始引导");
-            boolean guideRes = hikClientService.guideTargetPosition(cmd);
+            boolean guideRes = cameraSdkService.guideTargetPosition(cmd);
             if (guideRes) {
                 log.debug("引导成功");
-                hikClientService.controlLock(cmd);//上锁
-                hikClientService.recordStart(cmd);//开始录像
+                cameraSdkService.controlLock(cmd);//上锁
+                cameraSdkService.recordStart(cmd);//开始录像
                 try {
                     Thread.sleep(30000);
                 } catch (InterruptedException e) {
                     log.info("当前任务ID" + guideTask.getAlarmId() + "线程被终止");
                 }
-                String url = hikClientService.recordStopToMinio(cmd);//停止录像返回url
+                String url = cameraSdkService.recordStopToMinio(cmd);//停止录像返回url
                 if (StringUtils.isNotEmpty(url)) {
                     switch (guideTask.getAlarmType()) {
                         case "sys_tube_leak":
diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/controller/ArdCamerasController.java b/ard-work/src/main/java/com/ruoyi/device/camera/controller/ArdCamerasController.java
index 2ffda2a..4a4976e 100644
--- a/ard-work/src/main/java/com/ruoyi/device/camera/controller/ArdCamerasController.java
+++ b/ard-work/src/main/java/com/ruoyi/device/camera/controller/ArdCamerasController.java
@@ -7,6 +7,8 @@
 import com.ruoyi.device.camera.domain.ArdCameras;
 import com.ruoyi.device.camera.domain.CameraCmd;
 import com.ruoyi.device.camera.service.IArdCamerasService;
+import com.ruoyi.device.camera.service.ICameraSdkService;
+import com.ruoyi.device.camera.service.impl.CameraSdkServiceImpl;
 import com.ruoyi.device.dhsdk.service.IDhClientService;
 import com.ruoyi.device.hiksdk.service.IHikClientService;
 import com.ruoyi.device.hiksdk.service.impl.HikClientServiceImpl;
@@ -49,6 +51,8 @@
     private IHikClientService hikSdk;
     @Resource
     private IDhClientService dhSdk;
+    @Resource
+    private ICameraSdkService cameraSdkService;
     @Resource
     private IArdCamerasService ardCamerasService;
     @Resource
@@ -99,17 +103,8 @@
     public AjaxResult add(@RequestBody ArdCameras camera) {
         int i = ardCamerasService.insertArdCameras(camera);
         if (i > 0) {
-            if (camera.getFactory().equals("1")) {
-                //注销
-                hikSdk.logout(camera.getId());
-                //异步登录
-                hikSdk.asyncLogin(camera);
-            }
-            else if(camera.getFactory().equals("2"))
-            {
-                dhSdk.logout(camera.getId());
-                dhSdk.login(camera);
-            }
+            cameraSdkService.logout(camera.getId());
+            cameraSdkService.login(camera);
         }
         return toAjax(i);
     }
@@ -124,15 +119,8 @@
     public AjaxResult edit(@RequestBody ArdCameras camera) {
         int i = ardCamerasService.updateArdCameras(camera);
         if (i > 0) {
-            camera= ardCamerasService.selectArdCamerasById(camera.getId());
-            if(camera.getFactory().equals("1")) {
-                hikSdk.logout(camera.getId());
-                hikSdk.asyncLogin(camera);
-            }
-            else if(camera.getFactory().equals("2")) {
-                dhSdk.logout(camera.getId());
-                dhSdk.login(camera);
-            }
+            cameraSdkService.logout(camera.getId());
+            cameraSdkService.login(camera);
         }
         return toAjax(i);
     }
@@ -146,8 +134,7 @@
     @DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable String[] ids) {
         for (String id : ids) {
-            hikSdk.logout(id);
-            dhSdk.logout(id);
+            cameraSdkService.logout(id);
         }
         return toAjax(ardCamerasService.deleteArdCamerasByIds(ids));
     }
diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/controller/CameraSdkController.java b/ard-work/src/main/java/com/ruoyi/device/camera/controller/CameraSdkController.java
index 81adfa8..2357121 100644
--- a/ard-work/src/main/java/com/ruoyi/device/camera/controller/CameraSdkController.java
+++ b/ard-work/src/main/java/com/ruoyi/device/camera/controller/CameraSdkController.java
@@ -150,8 +150,8 @@
     public @ResponseBody
     AjaxResult getFocusPos(@RequestBody CameraCmd cmd) {
         cmd.setOperator(SecurityUtils.getUserId());
-        Map<String, Object> Map = cameraSdkService.getFocusPos(cmd);
-        return AjaxResult.success("获取聚焦值", Map);
+        int focus = cameraSdkService.getFocusPos(cmd);
+        return AjaxResult.success("获取聚焦值", focus);
     }
 
     @ApiOperation("设置聚焦值")
@@ -286,6 +286,7 @@
 
     @ApiOperation(value = "获取聚焦模式", notes = "1手动2自动")
     @PostMapping("/getFocusMode")
+    @ApiOperationSupport(includeParameters = {"cmd.cameraId", "cmd.chanNo"})
     public @ResponseBody
     AjaxResult getFocusMode(@RequestBody CameraCmd cmd) {
         cmd.setOperator(SecurityUtils.getUserId());
@@ -328,11 +329,22 @@
     @ApiOperation("获取相机架设参数")
     @PostMapping("/getGisInfo")
     @Log(title = "获取相机架设参数", businessType = BusinessType.CONTROL)
-    @ApiOperationSupport(includeParameters = {"cmd.cameraId", "cmd.chanNo", "cmd.enable"})
+    @ApiOperationSupport(includeParameters = {"cmd.cameraId", "cmd.chanNo"})
     public @ResponseBody
     AjaxResult getGisInfo(@RequestBody CameraCmd cmd) {
         cmd.setOperator(SecurityUtils.getUserId());
         return AjaxResult.success(cameraSdkService.getGisInfo(cmd));
+    }
+
+    @ApiOperation("录像")
+    @PostMapping("/record")
+    @Log(title = "手动录像开始", businessType = BusinessType.CONTROL)
+    @ApiOperationSupport(includeParameters = {"cmd.cameraId", "cmd.chanNo", "cmd.enable"})
+    public @ResponseBody
+    AjaxResult record(@RequestBody CameraCmd cmd) {
+        cmd.setOperator(SecurityUtils.getUserId());
+        String url = cameraSdkService.record(cmd);
+        return AjaxResult.success(url);
     }
 
     @ApiOperation("手动录像开始")
@@ -345,6 +357,7 @@
         boolean b = cameraSdkService.recordStart(cmd);
         return toAjax(b);
     }
+
     @ApiOperation("手动录像停止")
     @PostMapping("/recordStop")
     @Log(title = "手动录像停止", businessType = BusinessType.CONTROL)
diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/domain/CameraCmd.java b/ard-work/src/main/java/com/ruoyi/device/camera/domain/CameraCmd.java
index ad30ca7..0b67dcb 100644
--- a/ard-work/src/main/java/com/ruoyi/device/camera/domain/CameraCmd.java
+++ b/ard-work/src/main/java/com/ruoyi/device/camera/domain/CameraCmd.java
@@ -2,13 +2,21 @@
 
 import io.swagger.annotations.ApiModel;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 import org.springframework.boot.context.properties.bind.DefaultValue;
 
 import java.util.Map;
 
 @Data
+@NoArgsConstructor
 @ApiModel(description = "sdk命令实体类")
 public class CameraCmd {
+
+    public CameraCmd(String cameraId, Integer chanNo) {
+        this.cameraId = cameraId;
+        this.chanNo = chanNo;
+    }
+
     /*命令标识*/
     String cmdType;
     /*相机ID*/
@@ -26,7 +34,7 @@
     /*聚焦值*/
     Integer dwFocusPos;
     /*PTZ值*/
-    Map<String,Double>ptzMap;
+    Map<String, Double> ptzMap;
 
     /*目标经纬度*/
     double[] targetPosition;
diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/service/ICameraSdkService.java b/ard-work/src/main/java/com/ruoyi/device/camera/service/ICameraSdkService.java
index dc7f5cf..e210aad 100644
--- a/ard-work/src/main/java/com/ruoyi/device/camera/service/ICameraSdkService.java
+++ b/ard-work/src/main/java/com/ruoyi/device/camera/service/ICameraSdkService.java
@@ -2,20 +2,15 @@
 
 import com.ruoyi.device.camera.domain.ArdCameras;
 import com.ruoyi.device.camera.domain.CameraCmd;
-import com.ruoyi.device.channel.domain.ArdChannel;
 
-import java.util.List;
 import java.util.Map;
 
 public interface ICameraSdkService {
     //sdk初始化
     void initSDK();
 
-    //同步登录
-    void syncLogin(ArdCameras cameras);
-
-    //异步登录
-    void asyncLogin(ArdCameras cameras);
+    //登录
+    Boolean login(ArdCameras ardCamera);
 
     //注销
     boolean logout(String cameraId);
@@ -30,7 +25,7 @@
     boolean setFocusPos(CameraCmd cmd);
 
     //获取聚焦值
-    Map<String, Object> getFocusPos(CameraCmd cmd);
+    int getFocusPos(CameraCmd cmd);
 
     //设置预置位
     boolean setPreset(CameraCmd cmd);
@@ -39,12 +34,12 @@
     boolean gotoPreset(CameraCmd cmd);
 
     //获取码流压缩参数
-    Map<String, String> getVideoCompressionCfg(CameraCmd cmd);
+    Map<String, Object> getVideoCompressionCfg(CameraCmd cmd);
 
     //透雾
     boolean controlDefogcfg(CameraCmd cmd);
 
-    //红外?
+    //红外
     boolean controlInfrarecfg(CameraCmd cmd);
 
     //聚焦模式
@@ -56,7 +51,7 @@
     //云台加热
     boolean controlPTHeateRpwron(CameraCmd cmd);
 
-    //镜头除冰
+    //镜头加热除冰
     boolean controlCameraDeicing(CameraCmd cmd);
 
     //配置锁定
@@ -85,9 +80,11 @@
     //设置零方位角
     boolean setZeroPtz(CameraCmd cmd);
 
-
     //引导目标位置
     boolean guideTargetPosition(CameraCmd cmd);
+
+    //录像
+    String record(CameraCmd cmd);
 
     //手动开始录像
     boolean recordStart(CameraCmd cmd);
@@ -96,11 +93,8 @@
     String recordStopToMinio(CameraCmd cmd);
 
     //停止录像-不上传minio
-    void recordStopNotToMinio(CameraCmd cmd);
-
-    //获取相机通道信息
-    public List<ArdChannel> getCameraChannelList(ArdCameras camera);
+    boolean recordStopNotToMinio(CameraCmd cmd);
 
     //获取GIS信息数据
-    public Map<String, Object> getGisInfo(CameraCmd cmd);
+    Map<String, Object> getGisInfo(CameraCmd cmd);
 }
diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java b/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java
index e44f979..8fb5c0d 100644
--- a/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java
@@ -13,6 +13,7 @@
 import com.ruoyi.device.channel.domain.ArdChannel;
 import com.ruoyi.device.channel.mapper.ArdChannelMapper;
 import com.ruoyi.device.hiksdk.service.IHikClientService;
+import com.ruoyi.media.domain.Vtdu;
 import com.ruoyi.media.service.IVtduService;
 import com.ruoyi.scheduling.domian.SchedulingParam;
 import com.ruoyi.utils.gis.GisUtil;
diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java b/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java
index 97591be..88678a3 100644
--- a/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java
@@ -1,11 +1,16 @@
 package com.ruoyi.device.camera.service.impl;
 
+import com.ruoyi.common.annotation.SdkOperate;
 import com.ruoyi.common.constant.CacheConstants;
 import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.file.FileUtils;
 import com.ruoyi.device.camera.domain.ArdCameras;
 import com.ruoyi.device.camera.domain.CameraCmd;
+import com.ruoyi.device.camera.service.IArdCamerasService;
 import com.ruoyi.device.camera.service.ICameraSdkService;
 import com.ruoyi.device.channel.domain.ArdChannel;
+import com.ruoyi.device.dhsdk.lib.NetSDKLib;
+import com.ruoyi.device.dhsdk.module.RealPlayModule;
 import com.ruoyi.device.dhsdk.service.IDhClientService;
 import com.ruoyi.device.hiksdk.common.GlobalVariable;
 import com.ruoyi.device.hiksdk.service.IHikClientService;
@@ -13,10 +18,13 @@
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static com.ruoyi.device.dhsdk.lib.ToolKits.getErrorCodePrint;
+import static com.ruoyi.device.dhsdk.module.LoginModule.netsdk;
 import static com.ruoyi.device.hiksdk.sdk.HCNetSDK.NET_DVR_CHECK_USER_STATUS;
 
 
@@ -30,12 +38,14 @@
 @Slf4j(topic = "SDK")
 public class CameraSdkServiceImpl implements ICameraSdkService {
     @Resource
+    private IArdCamerasService ardCamerasService;
+    @Resource
     IHikClientService hikClientService;
     @Resource
     IDhClientService dhClientService;
     @Resource
     RedisCache redisCache;
-
+    //初始化SDK
     @Override
     public void initSDK() {
         //初始化加载sdk库文件
@@ -48,20 +58,47 @@
             dhClientService.loginAll();//登录全部大华相机
         }
     }
+    //登录
     @Override
-    public void syncLogin(ArdCameras cameras) {
-
+    public Boolean login(ArdCameras ardCamera) {
+        boolean result = false;
+        try {
+            if (ardCamera != null) {
+                String factory = ardCamera.getFactory();
+                if (factory.equals("1")) {
+                    hikClientService.syncLogin(ardCamera);
+                    result=true;
+                } else if (factory.equals("2")) {
+                    result = dhClientService.login(ardCamera);
+                }
+            }
+        } catch (Exception ex) {
+            log.error("登录异常:" + ex.getMessage());
+            return false;
+        }
+        return result;
     }
-
-    @Override
-    public void asyncLogin(ArdCameras cameras) {
-
-    }
-
+    //注销
     @Override
     public boolean logout(String cameraId) {
-        return false;
+        boolean result = false;
+        try {
+            ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
+            if (ardCamera != null) {
+                String factory = ardCamera.getFactory();
+                if (factory.equals("1")) {
+                    result = hikClientService.logout(cameraId);
+                } else if (factory.equals("2")) {
+                    result = dhClientService.logout(cameraId);
+                }
+            }
+        } catch (Exception ex) {
+            log.error("注销异常:" + ex.getMessage());
+            return false;
+        }
+        return result;
     }
+
     //在线检测
     @Override
     public boolean isOnLine(CameraCmd cmd) {
@@ -84,6 +121,7 @@
         }
     }
     //云台控制
+    @SdkOperate
     @Override
     public boolean pTZControl(CameraCmd cmd) {
         try {
@@ -116,7 +154,7 @@
                 if (factory.equals("1")) {
                     result = hikClientService.setFocusPos(cmd);
                 } else if (factory.equals("2")) {
-
+                    result = dhClientService.setFocusPos(cmd);
                 }
             }
         } catch (Exception ex) {
@@ -127,23 +165,23 @@
     }
     //获取聚焦值
     @Override
-    public Map<String, Object> getFocusPos(CameraCmd cmd) {
-        Map<String, Object> map = new HashMap<>();
+    public int getFocusPos(CameraCmd cmd) {
+        int result=0;
         try {
             String cameraId = cmd.getCameraId();
             ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
             if (ardCamera != null) {
                 String factory = ardCamera.getFactory();
                 if (factory.equals("1")) {
-                    map = hikClientService.getFocusPos(cmd);
+                    result = hikClientService.getFocusPos(cmd);
                 } else if (factory.equals("2")) {
-
+                    result = dhClientService.getFocusPos(cmd);
                 }
             }
         } catch (Exception ex) {
             log.error("获取聚焦值异常:" + ex.getMessage());
         }
-        return map;
+        return result;
     }
     //设置预置位
     @Override
@@ -187,8 +225,8 @@
     }
     //获取码流压缩参数
     @Override
-    public Map<String, String> getVideoCompressionCfg(CameraCmd cmd) {
-        Map<String, String> map = new HashMap<>();
+    public Map<String, Object> getVideoCompressionCfg(CameraCmd cmd) {
+        Map<String, Object> map = new HashMap<>();
         try {
             String cameraId = cmd.getCameraId();
             ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
@@ -197,7 +235,7 @@
                 if (factory.equals("1")) {
                     map = hikClientService.getVideoCompressionCfg(cmd);
                 } else if (factory.equals("2")) {
-
+                    map = dhClientService.getVideoCompressionCfg(cmd);
                 }
             }
         } catch (Exception ex) {
@@ -217,7 +255,7 @@
                 if (factory.equals("1")) {
                     result = hikClientService.controlDefogcfg(cmd);
                 } else if (factory.equals("2")) {
-
+                    //不支持
                 }
             }
         } catch (Exception ex) {
@@ -237,7 +275,7 @@
                 if (factory.equals("1")) {
                     result = hikClientService.controlInfrarecfg(cmd);
                 } else if (factory.equals("2")) {
-
+                    result = dhClientService.controlInfrarecfg(cmd);
                 }
             }
         } catch (Exception ex) {
@@ -277,7 +315,7 @@
                 if (factory.equals("1")) {
                     result = hikClientService.getFocusMode(cmd);
                 } else if (factory.equals("2")) {
-
+                    result = dhClientService.getFocusMode(cmd);
                 }
             }
         } catch (Exception ex) {
@@ -297,7 +335,7 @@
                 if (factory.equals("1")) {
                     result = hikClientService.controlPTHeateRpwron(cmd);
                 } else if (factory.equals("2")) {
-
+                    //不支持
                 }
             }
         } catch (Exception ex) {
@@ -317,7 +355,7 @@
                 if (factory.equals("1")) {
                     result = hikClientService.controlCameraDeicing(cmd);
                 } else if (factory.equals("2")) {
-
+                    //不支持
                 }
             }
         } catch (Exception ex) {
@@ -325,46 +363,7 @@
         }
         return result;
     }
-    //操控锁定
-    @Override
-    public boolean controlLock(CameraCmd cmd) {
-        boolean result = false;
-        try {
-            String cameraId = cmd.getCameraId();
-            ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
-            if (ardCamera != null) {
-                String factory = ardCamera.getFactory();
-                if (factory.equals("1")) {
-                    result = hikClientService.controlLock(cmd);
-                } else if (factory.equals("2")) {
 
-                }
-            }
-        } catch (Exception ex) {
-            log.error("操控锁定异常:" + ex.getMessage());
-        }
-        return result;
-    }
-    //设置解锁
-    @Override
-    public boolean controlUnLock(CameraCmd cmd) {
-        boolean result = false;
-        try {
-            String cameraId = cmd.getCameraId();
-            ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
-            if (ardCamera != null) {
-                String factory = ardCamera.getFactory();
-                if (factory.equals("1")) {
-                    result = hikClientService.controlUnLock(cmd);
-                } else if (factory.equals("2")) {
-
-                }
-            }
-        } catch (Exception ex) {
-            log.error("设置解锁异常:" + ex.getMessage());
-        }
-        return result;
-    }
     //获取云台锁定信息
     @Override
     public int getPTZLockInfo(CameraCmd cmd) {
@@ -391,17 +390,23 @@
         return null;
     }
     //抓图
+    @SdkOperate
     @Override
     public String picCutCate(CameraCmd cmd) {
-        String url = "";
+       String url = "";
         try {
+            //获取摄像头ID
             String cameraId = cmd.getCameraId();
+            //从redis中获取摄像头信息
             ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
             if (ardCamera != null) {
+                //获取摄像头工厂
                 String factory = ardCamera.getFactory();
                 if (factory.equals("1")) {
+                    //调用hikClientService的picCutCate方法
                     url = hikClientService.picCutCate(cmd);
                 } else if (factory.equals("2")) {
+                    //调用dhClientService的picCutCate方法
                     url = dhClientService.picCutCate(cmd);
                 }
             }
@@ -451,6 +456,7 @@
         return map;
     }
     //设置ptz
+    @SdkOperate
     @Override
     public boolean setPtz(CameraCmd cmd) {
         boolean result = false;
@@ -471,6 +477,7 @@
         return result;
     }
     //设置零方位角
+    @SdkOperate
     @Override
     public boolean setZeroPtz(CameraCmd cmd) {
         boolean result = false;
@@ -491,6 +498,7 @@
         return result;
     }
     //引导指向目标
+    @SdkOperate
     @Override
     public boolean guideTargetPosition(CameraCmd cmd) {
         boolean result = false;
@@ -510,6 +518,74 @@
         }
         return result;
     }
+
+    /**
+     * @描述 操控锁定
+     * @参数 [userId, channelNum]
+     * @返回值 boolean
+     * @创建人 刘苏义
+     * @创建时间 2023/1/17 16:36
+     * @修改人和其它信息 0-解锁 1-锁定
+     */
+    @Override
+    @SdkOperate
+    public boolean controlLock(CameraCmd cmd) {
+        String cameraId = cmd.getCameraId();//申请锁的相机
+        ArdCameras ardCameras = ardCamerasService.selectArdCamerasById(cameraId);
+        Date now = new Date();
+        now.setTime(now.getTime() + cmd.getExpired() * 1000);
+        ardCameras.setOperatorExpired(now);//设置当前过期时间
+        ardCamerasService.updateArdCameras(ardCameras);
+        return true;
+    }
+
+    /**
+     * @描述 操控解锁
+     * @参数 [userId, channelNum]
+     * @返回值 boolean
+     * @创建人 刘苏义
+     * @创建时间 2023/6/30 15:36
+     * @修改人和其它信息
+     */
+    @Override
+    public boolean controlUnLock(CameraCmd cmd) {
+        String cameraId = cmd.getCameraId();//申请解锁的相机
+        String operator = cmd.getOperator();//申请者
+        ArdCameras ardCameras = ardCamerasService.selectArdCamerasById(cameraId);
+        if (ardCameras.getOperatorId().equals(operator)) {
+            //如果解锁相机的当前用户是申请者,则清空该相机的过期时间
+            ardCameras.setOperatorExpired(null);
+            int i = ardCamerasService.updateArdCameras(ardCameras);
+            if (i > 0) {
+                log.debug(cameraId + "--解锁成功");
+            }
+        }
+        return true;
+    }
+
+
+    //录像
+    @SdkOperate
+    @Override
+    public String record(CameraCmd cmd) {
+        String url = "";
+        try {
+            String cameraId = cmd.getCameraId();
+            ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
+            if (ardCamera != null) {
+                String factory = ardCamera.getFactory();
+                if (factory.equals("1")) {
+                    url = hikClientService.record(cmd);
+                } else if (factory.equals("2")) {
+                    url = dhClientService.record(cmd);
+                }
+            }
+        } catch (Exception ex) {
+            log.error("录像异常:" + ex.getMessage());
+        }
+        return url;
+    }
+
     //开始录像
     @Override
     public boolean recordStart(CameraCmd cmd) {
@@ -552,13 +628,23 @@
     }
     //停止录像并不存入minio
     @Override
-    public void recordStopNotToMinio(CameraCmd cmd) {
-
-    }
-
-    @Override
-    public List<ArdChannel> getCameraChannelList(ArdCameras camera) {
-        return null;
+    public boolean recordStopNotToMinio(CameraCmd cmd) {
+        boolean result = false;
+        try {
+            String cameraId = cmd.getCameraId();
+            ArdCameras ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
+            if (ardCamera != null) {
+                String factory = ardCamera.getFactory();
+                if (factory.equals("1")) {
+                    result = hikClientService.recordStopNotToMinio(cmd);
+                } else if (factory.equals("2")) {
+                    result = dhClientService.recordStopNotToMinio(cmd);
+                }
+            }
+        } catch (Exception ex) {
+            log.error("停止录像异常:" + ex.getMessage());
+        }
+        return result;
     }
 
     //获取相机架设参数
@@ -573,7 +659,7 @@
                 if (factory.equals("1")) {
                     map = hikClientService.getGisInfo(cmd);
                 } else if (factory.equals("2")) {
-
+                    map = dhClientService.getGisInfo(cmd);
                 }
             }
         } catch (Exception ex) {
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/controller/DhSdkController.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/controller/DhSdkController.java
index c0039e5..94d0385 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/controller/DhSdkController.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/controller/DhSdkController.java
@@ -9,7 +9,6 @@
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.device.camera.domain.CameraCmd;
 import com.ruoyi.device.dhsdk.service.IDhClientService;
-import com.ruoyi.device.hiksdk.service.IHikClientService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.stereotype.Controller;
@@ -17,8 +16,6 @@
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import java.util.Map;
 
@@ -28,7 +25,7 @@
  * @Author: 刘苏义
  * @Date: 2023年10月14日10:34:58
  **/
-@Api(tags = "大华SDK接口")
+
 @Controller
 @RequestMapping("/dh")
 @Anonymous
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/enumeration/EM_FOCUS_LIMIT_SELECT_MODE.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/enumeration/EM_FOCUS_LIMIT_SELECT_MODE.java
index 40520ef..a096b4b 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/enumeration/EM_FOCUS_LIMIT_SELECT_MODE.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/enumeration/EM_FOCUS_LIMIT_SELECT_MODE.java
@@ -1,43 +1,43 @@
 package com.ruoyi.device.dhsdk.lib.enumeration;
 
 
-/** 
-* @author 291189
-* @description  聚焦极限对应枚举 
-* @date 2022/11/01 11:16:54
-*/
+/**
+ * @author 291189
+ * @description 聚焦极限对应枚举
+ * @date 2022/11/01 11:16:54
+ */
 public enum EM_FOCUS_LIMIT_SELECT_MODE {
-/**
- Manual  自动
-*/
-EM_FOCUS_LIMIT_MODE_MANUAL(0," Manual  自动"),
-/**
- Auto 手动
-*/
-EM_FOCUS_LIMIT_MODE_AUTO(1," Auto 手动"),
-/**
+    /**
+     * Manual  自动
+     */
+    EM_FOCUS_LIMIT_MODE_MANUAL(0, " Manual 自动"),
+    /**
+     * Auto 手动
+     */
+    EM_FOCUS_LIMIT_MODE_AUTO(1, " Auto 手动"),
+    /**
+     *
+     */
+    EM_FOCUS_LIMIT_MODE_INVALI(2, "无效");
 
-*/
-EM_FOCUS_LIMIT_MODE_INVALI(2,"无效");
+    private int value;
 
-private int value;
+    private String note;
 
-private String note;
-
-public String getNote() {
+    public String getNote() {
         return note;
     }
 
-public int getValue() {
+    public int getValue() {
         return value;
     }
 
-EM_FOCUS_LIMIT_SELECT_MODE(int givenValue, String note) {
+    EM_FOCUS_LIMIT_SELECT_MODE(int givenValue, String note) {
         this.value = givenValue;
         this.note = note;
     }
 
-public static String getNoteByValue(int givenValue) {
+    public static String getNoteByValue(int givenValue) {
         for (EM_FOCUS_LIMIT_SELECT_MODE enumType : EM_FOCUS_LIMIT_SELECT_MODE.values()) {
             if (givenValue == enumType.getValue()) {
                 return enumType.getNote();
@@ -46,7 +46,7 @@
         return null;
     }
 
-public static int getValueByNote(String givenNote) {
+    public static int getValueByNote(String givenNote) {
         for (EM_FOCUS_LIMIT_SELECT_MODE enumType : EM_FOCUS_LIMIT_SELECT_MODE.values()) {
             if (givenNote.equals(enumType.getNote())) {
                 return enumType.getValue();
@@ -55,7 +55,7 @@
         return -1;
     }
 
-public static EM_FOCUS_LIMIT_SELECT_MODE getEnum(int value) {
+    public static EM_FOCUS_LIMIT_SELECT_MODE getEnum(int value) {
         for (EM_FOCUS_LIMIT_SELECT_MODE e : EM_FOCUS_LIMIT_SELECT_MODE.values()) {
             if (e.getValue() == value)
                 return e;
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS.java
index 45b376e..612c608 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS.java
@@ -3,28 +3,28 @@
 
 import com.ruoyi.device.dhsdk.lib.NetSDKLib;
 
-/** 
-* @author 291189
-* @description  聚焦设置基本信息单元 
-* @date 2022/11/01 11:16:54
-*/
+/**
+ * @author 291189
+ * @description 聚焦设置基本信息单元
+ * @date 2022/11/01 11:16:54
+ */
 public class CFG_VIDEO_IN_FOCUS extends NetSDKLib.SdkStructure {
-/** 
-通道号
-*/
-public			int					nChannelIndex;
-/** 
-配置使用个数
-*/
-public			int					nVideoInFocusRealNum;
-/** 
-通道聚焦配置单元信息
-*/
-public			CFG_VIDEO_IN_FOCUS_UNIT[]					stVideoInFocusUnit=new CFG_VIDEO_IN_FOCUS_UNIT[32];
+    /**
+     * 通道号
+     */
+    public int nChannelIndex;
+    /**
+     * 配置使用个数
+     */
+    public int nVideoInFocusRealNum;
+    /**
+     * 通道聚焦配置单元信息
+     */
+    public CFG_VIDEO_IN_FOCUS_UNIT[] stVideoInFocusUnit = new CFG_VIDEO_IN_FOCUS_UNIT[32];
 
-public			CFG_VIDEO_IN_FOCUS(){
-		for(int i=0;i<stVideoInFocusUnit.length;i++){
-			stVideoInFocusUnit[i]=new CFG_VIDEO_IN_FOCUS_UNIT();
-			}
-}
+    public CFG_VIDEO_IN_FOCUS() {
+        for (int i = 0; i < stVideoInFocusUnit.length; i++) {
+            stVideoInFocusUnit[i] = new CFG_VIDEO_IN_FOCUS_UNIT();
+        }
+    }
 }
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS_UNIT.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS_UNIT.java
index e8667be..3e1b252 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS_UNIT.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/lib/structure/CFG_VIDEO_IN_FOCUS_UNIT.java
@@ -2,33 +2,33 @@
 
 import com.ruoyi.device.dhsdk.lib.NetSDKLib;
 
-/** 
-* @author 291189
-* @description  聚焦设置基本信息单元 
-* @date 2022/11/01 11:16:54
-*/
+/**
+ * @author 291189
+ * @description 聚焦设置基本信息单元
+ * @date 2022/11/01 11:16:54
+ */
 public class CFG_VIDEO_IN_FOCUS_UNIT extends NetSDKLib.SdkStructure {
-/** 
-聚焦模式, 0-关闭, 1-辅助聚焦, 2-自动聚焦, 3-半自动聚焦, 4-手动聚焦
-*/
-public			int					nMode;
-/** 
-聚焦灵敏度, 0-高, 1-默认, 2-低
-*/
-public			int					nSensitivity;
-/** 
-红外光聚焦修正, 0-不修正, 1-修正, 2-自动修正
-*/
-public			int					nIRCorrection;
-/** 
-聚焦极限 {@link com.ruoyi.device.dhsdk.lib.enumeration.EM_FOCUS_LIMIT_SELECT_MODE}
-*/
-public			int					emFocusMode;
-/** 
-聚焦极限值, 单位毫米
-*/
-public			int					nFocusLimit;
+    /**
+     * 聚焦模式, 0-关闭, 1-辅助聚焦, 2-自动聚焦, 3-半自动聚焦, 4-手动聚焦
+     */
+    public int nMode;
+    /**
+     * 聚焦灵敏度, 0-高, 1-默认, 2-低
+     */
+    public int nSensitivity;
+    /**
+     * 红外光聚焦修正, 0-不修正, 1-修正, 2-自动修正
+     */
+    public int nIRCorrection;
+    /**
+     * 聚焦极限 {@link com.ruoyi.device.dhsdk.lib.enumeration.EM_FOCUS_LIMIT_SELECT_MODE}
+     */
+    public int emFocusMode;
+    /**
+     * 聚焦极限值, 单位毫米
+     */
+    public int nFocusLimit;
 
-public			CFG_VIDEO_IN_FOCUS_UNIT(){
-}
+    public CFG_VIDEO_IN_FOCUS_UNIT() {
+    }
 }
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/ConfigModule.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/ConfigModule.java
index bb99075..1234d40 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/ConfigModule.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/ConfigModule.java
@@ -1,8 +1,10 @@
 package com.ruoyi.device.dhsdk.module;
 
 import com.ruoyi.device.dhsdk.lib.NetSDKLib;
+import com.ruoyi.device.dhsdk.lib.ToolKits;
 import com.sun.jna.Structure;
 import com.sun.jna.ptr.IntByReference;
+
 import static com.ruoyi.device.dhsdk.lib.ToolKits.getErrorCodePrint;
 
 /**
@@ -14,6 +16,7 @@
 public class ConfigModule {
     public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;
     public static NetSDKLib configsdk = NetSDKLib.CONFIG_INSTANCE;
+
     /**
      * 查询设备状态
      */
@@ -27,28 +30,106 @@
         stuInfo.read();
         return true;
     }
+
+    /**
+     * 查询远程设备状态
+     */
+    public static boolean queryRemotDevState(NetSDKLib.LLong hLoginHandle, int nChn, int nType, NetSDKLib.SdkStructure stuInfo) {
+
+        IntByReference intRetLen = new IntByReference();
+        stuInfo.write();
+        if (!netsdk.CLIENT_QueryRemotDevState(hLoginHandle, nType, nChn, stuInfo.getPointer(), stuInfo.size(), intRetLen, 3000)) {
+            System.err.println("Config Failed!" + ToolKits.getErrorCodePrint());
+            return false;
+        }
+        stuInfo.read();
+        return true;
+    }
+
+    /**
+     * 获取单个配置
+     *
+     * @param hLoginHandle 登陆句柄
+     * @param nChn         通道号,-1 表示全通道
+     * @param strCmd       配置名称
+     * @param cmdObject    配置对应的结构体对象
+     * @return 成功返回 true
+     */
+    public static boolean GetNewDevConfig(NetSDKLib.LLong hLoginHandle, int nChn, String strCmd, Structure cmdObject) {
+        boolean result = false;
+        IntByReference error = new IntByReference(0);
+        int nBufferLen = 2 * 1024 * 1024;
+        byte[] strBuffer = new byte[nBufferLen];
+
+        if (netsdk.CLIENT_GetNewDevConfig(hLoginHandle, strCmd, nChn, strBuffer, nBufferLen, error, 3000)) {
+            cmdObject.write();
+            if (configsdk.CLIENT_ParseData(strCmd, strBuffer, cmdObject.getPointer(), cmdObject.size(), null)) {
+                cmdObject.read();
+                result = true;
+            } else {
+                System.err.println("Parse " + strCmd + " Config Failed!" + ToolKits.getErrorCodePrint());
+                result = false;
+            }
+        } else {
+            System.err.printf("Get %s Config Failed!Last Error = %s\n", strCmd, getErrorCodePrint());
+            result = false;
+        }
+
+        return result;
+    }
+
+    public static boolean GetDevConfig(NetSDKLib.LLong hLoginHandle, int nChn, String strCmd, Structure cmdObject) {
+        boolean result = true;
+        IntByReference error = new IntByReference(0);
+        int nBufferLen = 2 * 1024 * 1024;
+        byte[] strBuffer = new byte[nBufferLen];
+        cmdObject.write();
+        boolean bRet = netsdk.CLIENT_QueryNewSystemInfo(hLoginHandle, strCmd, nChn, strBuffer, cmdObject.size(), error, 3000);
+        if (bRet) {
+            cmdObject.read();
+        } else {
+            System.err.printf("Get %s Config Failed!Last Error = %s\n", strCmd, getErrorCodePrint());
+            result = false;
+        }
+        return result;
+    }
+    // 获取配置
+    public static boolean GetConfig(NetSDKLib.LLong hLoginHandle, int nChn,int type,Structure cmdObject) {
+        boolean result = false;
+        // 获取
+        cmdObject.write();
+        if (netsdk.CLIENT_GetConfig(hLoginHandle, type, nChn, cmdObject.getPointer(), cmdObject.size(), 4000, null)) {
+            cmdObject.read();
+            result=true;
+        } else {
+            System.err.println("GetConfig Failed!" + getErrorCodePrint());
+            result=false;
+        }
+        return result;
+    }
     /**
      * 设置单个配置
+     *
      * @param hLoginHandle 登陆句柄
-     * @param nChn 通道号,-1 表示全通道
-     * @param strCmd 配置名称
-     * @param cmdObject 配置对应的结构体对象
+     * @param nChn         通道号,-1 表示全通道
+     * @param strCmd       配置名称
+     * @param cmdObject    配置对应的结构体对象
      * @return 成功返回 true
      */
     public static boolean SetDevConfig(NetSDKLib.LLong hLoginHandle, int nChn, String strCmd, Structure cmdObject) {
         boolean result = false;
-        int nBufferLen = 2*1024*1024;
+        int nBufferLen = 2 * 1024 * 1024;
         byte szBuffer[] = new byte[nBufferLen];
-        for(int i=0; i<nBufferLen; i++)szBuffer[i]=0;
+        for (int i = 0; i < nBufferLen; i++) szBuffer[i] = 0;
         IntByReference error = new IntByReference(0);
         IntByReference restart = new IntByReference(0);
         cmdObject.write();
         if (configsdk.CLIENT_PacketData(strCmd, cmdObject.getPointer(), cmdObject.size(), szBuffer, nBufferLen)) {
             cmdObject.read();
-            if( configsdk.CLIENT_SetNewDevConfig(hLoginHandle, strCmd , nChn , szBuffer, nBufferLen, error, restart, 3000)) {
+            if (netsdk.CLIENT_SetNewDevConfig(hLoginHandle, strCmd, nChn, szBuffer, nBufferLen, error, restart, 3000)) {
                 result = true;
             } else {
-                System.err.printf("Set %s Config Failed! Last Error = %s\n" , strCmd , getErrorCodePrint());
+                System.err.printf("Set %s Config Failed! Last Error = %s\n", strCmd, getErrorCodePrint());
                 result = false;
             }
         } else {
@@ -59,4 +140,5 @@
         return result;
     }
 
+
 }
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/PtzControlModule.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/PtzControlModule.java
index 31ecfe6..32fa9a0 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/PtzControlModule.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/PtzControlModule.java
@@ -2,18 +2,27 @@
 
 import com.ruoyi.device.dhsdk.lib.NetSDKLib;
 
+import static com.ruoyi.device.dhsdk.module.LoginModule.netsdk;
+
 /**
  * 云台控制接口实现
  * 主要有 :八个方向控制、变倍、变焦、光圈功能
  */
 public class PtzControlModule {
     public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;
+    /**
+     * 按dwPTZCommand类型控制
+     */
+    public static boolean ptzControl(NetSDKLib.LLong m_hLoginHandle,int nChannelID, int dwPTZCommand,int lParam1, int lParam2,int lParam3, int dwStop) {
+        return  netsdk.CLIENT_DHPTZControlEx(m_hLoginHandle, nChannelID, dwPTZCommand, lParam1, lParam2, lParam3, dwStop);
+    }
+
 
     /**
      * 向上
      */
-    public static boolean ptzControlUpStart(NetSDKLib.LLong lLoginID, int nChannelID, int lParam1, int lParam2) {
-        return netsdk.CLIENT_DHPTZControlEx(LoginModule.m_hLoginHandle, nChannelID,
+    public static boolean ptzControlUpStart(NetSDKLib.LLong m_hLoginHandle, int nChannelID, int lParam1, int lParam2) {
+        return netsdk.CLIENT_DHPTZControlEx(m_hLoginHandle, nChannelID,
                 NetSDKLib.NET_PTZ_ControlType.NET_PTZ_UP_CONTROL,
                 lParam1, lParam2, 0, 0);
     }
@@ -72,6 +81,7 @@
     /**
      * 向左上
      */
+
     public static boolean ptzControlLeftUpStart(int nChannelID, int lParam1, int lParam2) {
         return netsdk.CLIENT_DHPTZControlEx(LoginModule.m_hLoginHandle, nChannelID,
                 NetSDKLib.NET_EXTPTZ_ControlType.NET_EXTPTZ_LEFTTOP,
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/RealPlayModule.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/RealPlayModule.java
index a397132..a97ce4c 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/RealPlayModule.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/RealPlayModule.java
@@ -18,25 +18,14 @@
      * 开始预览
      * \endif
      */
-    public static NetSDKLib.LLong startRealPlay(NetSDKLib.LLong m_hLoginHandle, int channel, int stream) {
-        NetSDKLib.LLong m_hPlayHandle = netsdk.CLIENT_RealPlayEx(m_hLoginHandle, channel, null, stream);
-        if (m_hPlayHandle.longValue() == 0) {
-            System.err.println("开始实时预览失败,错误码" + ToolKits.getErrorCodePrint());
-        } else {
-            System.out.println("Success to start realplay");
-            //  netsdk.CLIENT_SetRealDataCallBackEx(m_hPlayHandle, CbfRealDataCallBackEx.getInstance(),null, 0x0000001f);
-        }
-        return m_hPlayHandle;
-    }
 
-    public static NetSDKLib.LLong startRealPlay1(NetSDKLib.LLong m_hLoginHandle, int channel, String path) {
+    public static NetSDKLib.LLong startRealPlay(NetSDKLib.LLong m_hLoginHandle, int channel, String path) {
         NetSDKLib.NET_IN_REALPLAY_BY_DATA_TYPE net_in_realplay_by_data_type = new NetSDKLib.NET_IN_REALPLAY_BY_DATA_TYPE();
         net_in_realplay_by_data_type.nChannelID = channel;
         net_in_realplay_by_data_type.hWnd = null;
         net_in_realplay_by_data_type.rType = 0;
         net_in_realplay_by_data_type.emDataType = NetSDKLib.EM_REAL_DATA_TYPE.EM_REAL_DATA_TYPE_MP4;
         net_in_realplay_by_data_type.szSaveFileName = path;
-        //net_in_realplay_by_data_type.cbRealData = CbfRealDataCallBackEx.getInstance();
         NetSDKLib.NET_OUT_REALPLAY_BY_DATA_TYPE net_out_realplay_by_data_type = new NetSDKLib.NET_OUT_REALPLAY_BY_DATA_TYPE();
         NetSDKLib.LLong m_hPlayHandle = netsdk.CLIENT_RealPlayByDataType(m_hLoginHandle, net_in_realplay_by_data_type, net_out_realplay_by_data_type, 5000);
         if (m_hPlayHandle.longValue() == 0) {
@@ -49,7 +38,7 @@
 
     /**
      * \if ENGLISH_LANG
-     * Start RealPlay
+     * Stop RealPlay
      * \else
      * 停止预览
      * \endif
@@ -110,4 +99,4 @@
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/IDhClientService.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/IDhClientService.java
index 32ad998..daa9fb2 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/IDhClientService.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/IDhClientService.java
@@ -1,11 +1,7 @@
 package com.ruoyi.device.dhsdk.service;
 
-import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.device.camera.domain.ArdCameras;
 import com.ruoyi.device.camera.domain.CameraCmd;
-import com.ruoyi.device.channel.domain.ArdChannel;
-
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -51,7 +47,7 @@
     String record(CameraCmd cmd);
     boolean recordStart(CameraCmd cmd);
     String recordStopToMinio(CameraCmd cmd);
-
+    boolean recordStopNotToMinio(CameraCmd cmd);
     //引导目标位置
     boolean guideTargetPosition(CameraCmd cmd);
 
@@ -59,6 +55,22 @@
     boolean gotoPreset(CameraCmd cmd);
     //设置预置位
     boolean setPreset(CameraCmd cmd);
-    //聚焦模式
+
+    //设置聚焦模式
     boolean controlFocusMode(CameraCmd cmd);
+    //获取聚焦模式
+    String getFocusMode(CameraCmd cmd);
+
+    //透雾
+    boolean controlDefogcfg(CameraCmd cmd);
+    //红外
+    boolean controlInfrarecfg(CameraCmd cmd);
+    //获取聚焦值
+    int getFocusPos(CameraCmd cmd);
+    //设置聚焦值
+    boolean setFocusPos(CameraCmd cmd);
+    //获取码流压缩参数
+    Map<String, Object> getVideoCompressionCfg(CameraCmd cmd);
+    //获取GIS信息数据
+    Map<String, Object> getGisInfo(CameraCmd cmd);
 }
diff --git a/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/impl/DhClientServiceImpl.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/impl/DhClientServiceImpl.java
index b7aadfb..2a20d7e 100644
--- a/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/impl/DhClientServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/device/dhsdk/service/impl/DhClientServiceImpl.java
@@ -3,25 +3,23 @@
 import com.ruoyi.common.annotation.SdkOperate;
 import com.ruoyi.common.utils.file.FileUtils;
 import com.ruoyi.common.utils.file.MimeTypeUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.common.utils.uuid.IdUtils;
 import com.ruoyi.device.camera.domain.ArdCameras;
 import com.ruoyi.device.camera.domain.CameraCmd;
 import com.ruoyi.device.camera.service.IArdCamerasService;
 import com.ruoyi.device.channel.domain.ArdChannel;
 import com.ruoyi.device.channel.service.IArdChannelService;
-import com.ruoyi.device.dhsdk.common.Res;
 import com.ruoyi.device.dhsdk.lib.NetSDKLib;
 import com.ruoyi.device.dhsdk.lib.NetSDKLib.LLong;
+import com.ruoyi.device.dhsdk.lib.enumeration.EM_NEW_CONFIG;
+import com.ruoyi.device.dhsdk.lib.enumeration.NET_EM_CFG_OPERATE_TYPE;
 import com.ruoyi.device.dhsdk.lib.structure.CFG_VIDEO_IN_FOCUS;
-import com.ruoyi.device.dhsdk.lib.structure.CFG_VIDEO_IN_FOCUS_UNIT;
-import com.ruoyi.device.dhsdk.module.CapturePictureModule;
-import com.ruoyi.device.dhsdk.module.ConfigModule;
-import com.ruoyi.device.dhsdk.module.LoginModule;
-import com.ruoyi.device.dhsdk.module.RealPlayModule;
+import com.ruoyi.device.dhsdk.lib.structure.DH_OUT_PTZ_VIEW_RANGE_STATUS;
+import com.ruoyi.device.dhsdk.module.*;
 import com.ruoyi.device.dhsdk.service.IDhClientService;
 import com.ruoyi.device.hiksdk.common.GlobalVariable;
-import com.ruoyi.device.hiksdk.sdk.HCNetSDK;
+import com.ruoyi.media.domain.Vtdu;
+import com.ruoyi.media.service.IVtduService;
 import com.ruoyi.utils.gis.GisUtil;
 import com.ruoyi.utils.minio.MinioUtil;
 import com.sun.jna.Pointer;
@@ -31,20 +29,15 @@
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.io.ByteArrayInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.text.DecimalFormat;
 import java.util.*;
 
-import static com.ruoyi.device.dhsdk.lib.NetSDKLib.NET_DEVSTATE_ONLINE;
-import static com.ruoyi.device.dhsdk.lib.NetSDKLib.NET_DEVSTATE_PTZ_LOCATION;
+import static com.ruoyi.device.dhsdk.lib.NetSDKLib.*;
 import static com.ruoyi.device.dhsdk.lib.NetSDKLib.NET_PTZ_ControlType.NET_PTZ_POINT_MOVE_CONTROL;
 import static com.ruoyi.device.dhsdk.lib.NetSDKLib.NET_PTZ_ControlType.NET_PTZ_POINT_SET_CONTROL;
 import static com.ruoyi.device.dhsdk.lib.ToolKits.getErrorCodePrint;
 import static com.ruoyi.device.dhsdk.module.LoginModule.netsdk;
-import static com.ruoyi.device.hiksdk.sdk.HCNetSDK.NET_DVR_SET_PTZPOS;
 
 
 /**
@@ -61,10 +54,11 @@
     private IArdCamerasService ardCamerasService;
     @Resource
     private IArdChannelService ardChannelService;
+    @Resource
+    private IVtduService vtduService;
     @Value("${minio.endpoint}")
     private String minioEndPoint;
 
-    private Vector<String> chnlist = new Vector<String>();
     // 设备断线通知回调
     private static DisConnect disConnect = new DisConnect();
     // 网络连接恢复
@@ -125,13 +119,46 @@
             GlobalVariable.loginMap.put(camera.getId(), loginId);
             //获取最新通道
             for (int i = 1; i < LoginModule.m_stDeviceInfo.byChanNum + 1; i++) {
-                chnlist.add(Res.string().getChannel() + " " + String.valueOf(i));
                 ArdChannel channel = new ArdChannel();
+                AV_CFG_ChannelName av_cfg_channelName = new AV_CFG_ChannelName();
+                boolean b = ConfigModule.GetNewDevConfig(loginId, i - 1, CFG_CMD_CHANNELTITLE, av_cfg_channelName);
+                if (b) {
+                    String chanName = null;
+                    try {
+                        chanName = new String(av_cfg_channelName.szName, "GBK").trim();
+                    } catch (UnsupportedEncodingException e) {
+                        e.printStackTrace();
+                    }
+                    channel.setName(chanName);
+                } else {
+                    channel.setName("通道" + i);
+                }
                 channel.setDeviceId(camera.getId());
-                channel.setName("通道" + i);
-                channel.setId(IdUtils.simpleUUID());
                 channel.setChanNo(i);
                 ardChannelService.insertArdChannel(channel);
+
+                //配置到流媒体
+                String name = camera.getId() + "_" + channel.getChanNo();
+                String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0";
+                Vtdu vtdu = vtduService.selectVtduByName(name);
+                if (vtdu != null) {
+                    vtduService.deleteVtduByName(name);
+                }
+
+                //添加到流媒体
+                CameraCmd cmd = new CameraCmd(camera.getId(), channel.getChanNo());
+                Map<String, Object> videoCompressionCfg = getVideoCompressionCfg(cmd);
+                vtdu = new Vtdu();
+                if (videoCompressionCfg.get("videoEncType").equals("标准h264")) {
+                    vtdu.setIsCode("0");//默认不转码
+                } else {
+                    vtdu.setIsCode("1");//默认转码
+                }
+                vtdu.setRtspSource(rtspSource);
+                vtdu.setName(camera.getId() + "_" + channel.getChanNo());
+                vtdu.setMode("1");//默认CPU软解码
+                vtdu.setCameraId(camera.getId());
+                vtduService.insertVtdu(vtdu);
             }
         } else {
             //log.debug(camera.getIp() + ":" + camera.getPort() + "登录失败");
@@ -210,58 +237,58 @@
         switch (code) {
             /*方向*/
             case 1:
-                dwPTZCommand = NetSDKLib.NET_EXTPTZ_ControlType.NET_EXTPTZ_LEFTTOP;
+                dwPTZCommand = NET_EXTPTZ_ControlType.NET_EXTPTZ_LEFTTOP;
                 break;
             case 2:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_UP_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_UP_CONTROL;
                 break;
             case 3:
-                dwPTZCommand = NetSDKLib.NET_EXTPTZ_ControlType.NET_EXTPTZ_RIGHTTOP;
+                dwPTZCommand = NET_EXTPTZ_ControlType.NET_EXTPTZ_RIGHTTOP;
                 break;
             case 4:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_LEFT_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_LEFT_CONTROL;
                 break;
             case 5:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_POINT_LOOP_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_POINT_LOOP_CONTROL;
                 break;
             case 6:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_RIGHT_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_RIGHT_CONTROL;
                 break;
             case 7:
-                dwPTZCommand = NetSDKLib.NET_EXTPTZ_ControlType.NET_EXTPTZ_LEFTDOWN;
+                dwPTZCommand = NET_EXTPTZ_ControlType.NET_EXTPTZ_LEFTDOWN;
                 break;
             case 8:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_DOWN_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_DOWN_CONTROL;
                 break;
             case 9:
-                dwPTZCommand = NetSDKLib.NET_EXTPTZ_ControlType.NET_EXTPTZ_RIGHTDOWN;
+                dwPTZCommand = NET_EXTPTZ_ControlType.NET_EXTPTZ_RIGHTDOWN;
                 break;
             /*焦距*/
             case 10:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_ZOOM_ADD_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_ZOOM_ADD_CONTROL;
                 break;
             case 11:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_ZOOM_DEC_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_ZOOM_DEC_CONTROL;
                 break;
             /*焦点*/
             case 12:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_FOCUS_ADD_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_FOCUS_ADD_CONTROL;
                 break;
             case 13:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_FOCUS_DEC_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_FOCUS_DEC_CONTROL;
                 break;
             /*光圈*/
             case 14:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_APERTURE_ADD_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_APERTURE_ADD_CONTROL;
                 break;
             case 15:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_APERTURE_DEC_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_APERTURE_DEC_CONTROL;
                 break;
             case 16:
-                dwPTZCommand = NetSDKLib.NET_PTZ_ControlType.NET_PTZ_LAMP_CONTROL;
+                dwPTZCommand = NET_PTZ_ControlType.NET_PTZ_LAMP_CONTROL;
                 break;
         }
-        boolean bool = netsdk.CLIENT_DHPTZControlEx(loginId, chanNo - 1, dwPTZCommand, speed, speed, 0, dwStop);
+        boolean bool = PtzControlModule.ptzControl(loginId, chanNo - 1, dwPTZCommand, speed, speed, 0, dwStop);
         if (!bool) {
             log.error("控制失败,请稍后重试" + getErrorCodePrint());
         }
@@ -286,7 +313,8 @@
         if (b) {
             DecimalFormat df = new DecimalFormat("0.0");//设置保留位数
             String nPTZPan = df.format((float) dh_ptz_location_info.nPTZPan / 10);
-            String nPTZTilt = df.format((float) dh_ptz_location_info.nPTZTilt / 10);
+            float t = (float) dh_ptz_location_info.nPTZTilt / 10;
+            String nPTZTilt = df.format(t < 0 ? t + 360 : t);
             String nPTZZoom = df.format((float) dh_ptz_location_info.nPTZZoom);
             ptzMap.put("p", nPTZPan);
             ptzMap.put("t", nPTZTilt);
@@ -409,7 +437,7 @@
             if (enable) {
                 LLong lRealHandle = new LLong(0);
                 if (!GlobalVariable.previewMap.containsKey(cameraId)) {
-                    lRealHandle = RealPlayModule.startRealPlay(loginId, chanNo, 0);
+                    lRealHandle = RealPlayModule.startRealPlay(loginId, chanNo - 1, path);
                     if (lRealHandle.longValue() <= 0) {
                         log.error("取流失败" + getErrorCodePrint());
                         return "";
@@ -417,15 +445,11 @@
                     log.debug("取流成功");
                     GlobalVariable.previewMap.put(cameraId, lRealHandle.intValue());
                 }
-                if (!netsdk.CLIENT_SaveRealData(lRealHandle, path)) {
-                    log.error("保存视频文件到临时文件夹失败 错误码为:  " + getErrorCodePrint());
-                    return "";
-                }
                 log.debug("录像开始");
             } else {
                 if (GlobalVariable.previewMap.containsKey(cameraId)) {
                     LLong lRealHandle = new LLong(GlobalVariable.previewMap.get(cameraId));
-                    boolean b = netsdk.CLIENT_StopSaveRealData(lRealHandle);
+                    RealPlayModule.stopRealPlay(lRealHandle);
                     GlobalVariable.previewMap.remove(cameraId);
                 }
                 log.debug("录像停止");
@@ -450,11 +474,11 @@
             LLong lRealHandle;
             if (GlobalVariable.previewMap.containsKey(cameraId)) {
                 lRealHandle = new LLong(GlobalVariable.previewMap.get(cameraId));
-                netsdk.CLIENT_StopRealPlayEx(lRealHandle);
+                RealPlayModule.stopRealPlay(lRealHandle);
                 GlobalVariable.previewMap.remove(cameraId);
                 log.debug("停止当前录像");
             }
-            lRealHandle = RealPlayModule.startRealPlay1(loginId, chanNo - 1, path);
+            lRealHandle = RealPlayModule.startRealPlay(loginId, chanNo - 1, path);
             if (lRealHandle.longValue() <= 0) {
                 log.error("取流失败" + getErrorCodePrint());
             }
@@ -485,7 +509,7 @@
             LLong lRealHandle;
             if (GlobalVariable.previewMap.containsKey(cameraId)) {
                 lRealHandle = new LLong(GlobalVariable.previewMap.get(cameraId));
-                netsdk.CLIENT_StopRealPlayEx(lRealHandle);
+                RealPlayModule.stopRealPlay(lRealHandle);
                 GlobalVariable.previewMap.remove(cameraId);
                 log.debug("停止当前录像");
             }
@@ -503,6 +527,29 @@
             log.error("录像异常" + ex.getMessage());
             return "";
         }
+    }
+
+    @Override
+    public boolean recordStopNotToMinio(CameraCmd cmd) {
+        boolean result = false;
+        try {
+            String cameraId = cmd.getCameraId();
+            if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+                return false;
+            }
+            LLong lRealHandle;
+            if (GlobalVariable.previewMap.containsKey(cameraId)) {
+                lRealHandle = new LLong(GlobalVariable.previewMap.get(cameraId));
+                RealPlayModule.stopRealPlay(lRealHandle);
+                GlobalVariable.previewMap.remove(cameraId);
+                log.debug("停止当前录像");
+            }
+
+            result = true;
+        } catch (Exception ex) {
+            log.error("录像异常" + ex.getMessage());
+        }
+        return result;
     }
 
     /**
@@ -595,14 +642,23 @@
         LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
         try {
             CFG_VIDEO_IN_FOCUS cfg_video_in_focus = new CFG_VIDEO_IN_FOCUS();
-            CFG_VIDEO_IN_FOCUS_UNIT[] stVideoInFocusUnit = new CFG_VIDEO_IN_FOCUS_UNIT[32];
-            if (enable) {
-                stVideoInFocusUnit[0].nMode = 4;//手动聚焦
-            } else {
-                stVideoInFocusUnit[0].nMode = 2;//手动聚焦
+            cfg_video_in_focus.nVideoInFocusRealNum = 3;//配置使用个数
+            for (int i = 0; i < 3; i++) {
+                cfg_video_in_focus.stVideoInFocusUnit[i].nSensitivity = 1;//聚焦灵敏度, 0-高, 1-默认, 2-低
+
+                cfg_video_in_focus.stVideoInFocusUnit[i].nIRCorrection = 2;//红外光聚焦修正, 0-不修正, 1-修正, 2-自动修正
+                cfg_video_in_focus.stVideoInFocusUnit[i].nFocusLimit = 10000;//聚焦极限值, 单位毫米
+                if (enable) {//聚焦模式, 0-关闭, 1-辅助聚焦, 2-自动聚焦, 3-半自动聚焦, 4-手动聚焦
+                    cfg_video_in_focus.stVideoInFocusUnit[i].nMode = 4;//手动聚焦
+                    cfg_video_in_focus.stVideoInFocusUnit[i].emFocusMode = 0;//聚焦极限Manual
+                    log.debug("当前为手动聚焦模式");
+                } else {
+                    cfg_video_in_focus.stVideoInFocusUnit[i].nMode = 2;//自动聚焦
+                    cfg_video_in_focus.stVideoInFocusUnit[i].emFocusMode = 1;//聚焦极限Auto
+                    log.debug("当前为自动聚焦模式");
+                }
             }
             cfg_video_in_focus.nChannelIndex = chanNo - 1;
-            cfg_video_in_focus.stVideoInFocusUnit = stVideoInFocusUnit;
             boolean bool = ConfigModule.SetDevConfig(loginId, chanNo - 1, NetSDKLib.CFG_CMD_VIDEOIN_FOCUS, cfg_video_in_focus);
             if (!bool) {
                 log.error("控制失败,请稍后重试" + getErrorCodePrint());
@@ -614,6 +670,245 @@
         }
     }
 
+    @Override
+    public String getFocusMode(CameraCmd cmd) {
+        String mode = "";
+        String cameraId = cmd.getCameraId();
+        Integer chanNo = cmd.getChanNo();
+        if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+            return "";
+        }
+        LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
+        try {
+            NET_VIDEOIN_FOCUSMODE_INFO focusModeInfo = new NET_VIDEOIN_FOCUSMODE_INFO();
+            int emCfgOpType = NET_EM_CFG_OPERATE_TYPE.NET_EM_CFG_VIDEOIN_FOCUSMODE;
+            boolean bool = ConfigModule.GetConfig(loginId, chanNo - 1, emCfgOpType, focusModeInfo);
+            if (!bool) {
+                log.error("获取失败,请稍后重试" + getErrorCodePrint());
+            }
+            System.out.println("配置类型:" + focusModeInfo.emCfgType);     // 具体信息,参考库里的枚举
+            System.out.println("聚焦模式:" + focusModeInfo.emFocusMode);
+            switch (focusModeInfo.emFocusMode) {
+                case 0:
+                    mode = "关闭";
+                    break;
+                case 1:
+                    mode = "辅助聚焦";
+                    break;
+                case 2:
+                    mode = "自动聚焦";
+                    break;
+                case 3:
+                    mode = "半自动聚焦";
+                    break;
+                case 4:
+                    mode = "手动聚焦";
+                    break;
+            }
+
+        } catch (Exception ex) {
+            log.error("获取聚焦模式异常:" + ex.getMessage());
+
+        }
+        return mode;
+    }
+
+    //透雾
+    @Override
+    public boolean controlDefogcfg(CameraCmd cmd) {
+        String cameraId = cmd.getCameraId();
+        Integer chanNo = cmd.getChanNo();
+        boolean enable = cmd.isEnable();
+        if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+            return false;
+        }
+        LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
+        try {
+            String command = EM_NEW_CONFIG.CFG_CMD_VIDEOINDEFOG.getValue();
+            //CFG_VIDEOINDEFOG_LIST cfg_videoindefog_list=new CFG_VIDEOINDEFOG_LIST();
+            boolean bool = ConfigModule.SetDevConfig(loginId, chanNo - 1, command, null);
+            if (!bool) {
+                log.error("控制失败,请稍后重试" + getErrorCodePrint());
+            }
+            return bool;
+        } catch (Exception ex) {
+            log.error("切换透雾异常:" + ex.getMessage());
+            return false;
+        }
+    }
+
+    //红外
+    @Override
+    public boolean controlInfrarecfg(CameraCmd cmd) {
+        String cameraId = cmd.getCameraId();
+        Integer chanNo = cmd.getChanNo();
+        boolean enable = cmd.isEnable();
+        if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+            return false;
+        }
+        LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
+        try {
+            CFG_LIGHTING_INFO cfg_lighting_info = new CFG_LIGHTING_INFO();
+            cfg_lighting_info.nLightingDetailNum = 1;
+            if (enable) {
+                cfg_lighting_info.stuLightingDetail[0].emMode = EM_CFG_LIGHTING_MODE.EM_CFG_LIGHTING_MODE_MANUAL;
+            } else {
+                cfg_lighting_info.stuLightingDetail[0].emMode = EM_CFG_LIGHTING_MODE.EM_CFG_LIGHTING_MODE_OFF;
+            }
+            boolean bool = ConfigModule.SetDevConfig(loginId, chanNo - 1, CFG_CMD_LIGHTING, cfg_lighting_info);
+            if (!bool) {
+                log.error("控制失败,请稍后重试" + getErrorCodePrint());
+            }
+            return bool;
+        } catch (Exception ex) {
+            log.error("切换红外异常:" + ex.getMessage());
+            return false;
+        }
+    }
+
+    //获取聚焦值
+    @Override
+    public int getFocusPos(CameraCmd cmd) {
+        int result = 0;
+        try {
+            String cameraId = cmd.getCameraId();
+            Integer chanNo = cmd.getChanNo();
+            if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+                return result;
+            }
+            LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
+            NET_PTZ_LOCATION_INFO net_ptz_location_info = new NET_PTZ_LOCATION_INFO();
+            net_ptz_location_info.nChannelID = chanNo - 1;
+            boolean bool = ConfigModule.queryDevState(loginId, NET_DEVSTATE_PTZ_LOCATION, net_ptz_location_info);
+            if (!bool) {
+                log.error("控制失败,请稍后重试" + getErrorCodePrint());
+            }
+            result = net_ptz_location_info.nFocusMapValue;
+        } catch (Exception ex) {
+            log.error("获取聚焦值异常:" + ex.getMessage());
+        }
+        return result;
+    }
+
+    //设置聚焦值
+    @Override
+    public boolean setFocusPos(CameraCmd cmd) {
+        String cameraId = cmd.getCameraId();
+        Integer chanNo = cmd.getChanNo();
+        boolean enable = cmd.isEnable();
+        if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+            return false;
+        }
+        LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
+        try {
+            CFG_LIGHTING_INFO cfg_lighting_info = new CFG_LIGHTING_INFO();
+            cfg_lighting_info.nLightingDetailNum = 1;
+            if (enable) {
+                cfg_lighting_info.stuLightingDetail[0].emMode = EM_CFG_LIGHTING_MODE.EM_CFG_LIGHTING_MODE_MANUAL;
+            } else {
+                cfg_lighting_info.stuLightingDetail[0].emMode = EM_CFG_LIGHTING_MODE.EM_CFG_LIGHTING_MODE_OFF;
+            }
+            boolean bool = ConfigModule.SetDevConfig(loginId, chanNo - 1, CFG_CMD_LIGHTING, cfg_lighting_info);
+            if (!bool) {
+                log.error("控制失败,请稍后重试" + getErrorCodePrint());
+            }
+            return bool;
+        } catch (Exception ex) {
+            log.error("设置聚焦值异常:" + ex.getMessage());
+            return false;
+        }
+    }
+
+    //获取码流压缩参数
+    @Override
+    public Map<String, Object> getVideoCompressionCfg(CameraCmd cmd) {
+        Map<String, Object> map = new HashMap<>();
+        String cameraId = cmd.getCameraId();
+        Integer chanNo = cmd.getChanNo();
+        if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+            return null;
+        }
+        LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
+        CFG_ENCODE_INFO cfg_encode_info = new CFG_ENCODE_INFO();
+        cfg_encode_info.nChannelID = chanNo - 1;
+        boolean b = ConfigModule.GetNewDevConfig(loginId, chanNo - 1, CFG_CMD_ENCODE, cfg_encode_info);
+        if (b) {
+            int emCompression = cfg_encode_info.stuMainStream[0].stuVideoFormat.emCompression;//视频格式
+            String videoEncType = "";
+            switch (emCompression) {
+                case 0:
+                    videoEncType = "MPEG4";
+                    break;
+                case 1:
+                    videoEncType = "MS-MPEG4";
+                    break;
+                case 2:
+                    videoEncType = "MPEG2";
+                    break;
+                case 3:
+                    videoEncType = "MPEG1";
+                    break;
+                case 4:
+                    videoEncType = "H.263";
+                    break;
+                case 5:
+                    videoEncType = "MJPG";
+                    break;
+                case 6:
+                    videoEncType = "FCC-MPEG4";
+                    break;
+                case 7:
+                    videoEncType = "标准h264";
+                    break;
+                case 8:
+                    videoEncType = "标准h265";
+                    break;
+                case 9:
+                    videoEncType = "SVAC";
+                    break;
+                default:
+                    videoEncType = "未知";
+                    break;
+            }
+            int nBitRate = cfg_encode_info.stuMainStream[0].stuVideoFormat.nBitRate;
+            int nWidth = cfg_encode_info.stuMainStream[0].stuVideoFormat.nWidth;
+            int nHeight = cfg_encode_info.stuMainStream[0].stuVideoFormat.nHeight;
+            String resolution = nWidth + "*" + nHeight;
+            float nFrameRate = cfg_encode_info.stuMainStream[0].stuVideoFormat.nFrameRate;
+            map.put("resolution", resolution);//分辨率
+            map.put("videoBitrate", String.valueOf(nBitRate));//比特率
+            map.put("videoEncType", videoEncType);//编码
+            map.put("nFrameRate", String.valueOf(nFrameRate));//帧率
+        }
+        return map;
+    }
+
+    //获取GIS信息数据
+    @Override
+    public Map<String, Object> getGisInfo(CameraCmd cmd) {
+        Map<String, Object> map = new HashMap<>();
+        try {
+            String cameraId = cmd.getCameraId();
+            Integer chanNo = cmd.getChanNo();
+            if (!GlobalVariable.loginMap.containsKey(cameraId)) {
+                return null;
+            }
+            LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId);
+            DH_OUT_PTZ_VIEW_RANGE_STATUS dh_out_ptz_view_range_status = new DH_OUT_PTZ_VIEW_RANGE_STATUS();
+            boolean b = ConfigModule.queryDevState(loginId, NET_DEVSTATE_PTZ_VIEW_RANGE, dh_out_ptz_view_range_status);
+            if (b) {
+                float nAngelH = (float) dh_out_ptz_view_range_status.nAngelH / 10;
+                float nAngelV = (float) dh_out_ptz_view_range_status.nAngelV / 10;
+                map = getPtz(cmd);//获取ptz
+                map.put("fHorFieldAngle", nAngelH);// 水平视场角
+                map.put("fVerFieldAngle", nAngelV);// 垂直视场角
+            }
+        } catch (Exception ex) {
+            log.error("获取云台可视域异常" + ex.getMessage());
+        }
+        return map;
+    }
+
     // 设备断线回调: 当设备出现断线时,SDK会调用该函数
     private static class DisConnect implements NetSDKLib.fDisConnect {
         public void invoke(LLong m_hLoginHandle, String pchDVRIP, int nDVRPort, Pointer dwUser) {
diff --git a/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/HikSdkController.java b/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/HikSdkController.java
index 6f9fbcb..7ccc486 100644
--- a/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/HikSdkController.java
+++ b/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/HikSdkController.java
@@ -29,7 +29,6 @@
  * @Date: 2023年01月17日 12:04
  * @Version: 1.0
  **/
-@Api(tags = "海康SDK接口")
 @Controller
 @RequestMapping("/hik")
 @Anonymous
@@ -45,6 +44,7 @@
     private String preview() {
         return "preview";
     }
+
     @RequestMapping("/index")
     private String index() {
         return "test";
@@ -115,8 +115,8 @@
     public @ResponseBody
     AjaxResult getFocusPos(@RequestBody CameraCmd cmd) {
         cmd.setOperator(SecurityUtils.getUserId());
-        Map<String, Object> Map = sdk.getFocusPos(cmd);
-        return AjaxResult.success("获取聚焦值", Map);
+        int focus = sdk.getFocusPos(cmd);
+        return AjaxResult.success("获取聚焦值", focus);
     }
 
     @ApiOperation("设置聚焦值")
@@ -182,25 +182,6 @@
         return toAjax(sdk.setZeroPtz(cmd));
     }
 
-    @ApiOperation("设置锁定")
-    @PostMapping("/setPTZLock")
-    @ApiOperationSupport(includeParameters = {"cmd.cameraId", "cmd.expired"})
-    @Log(title = "设置锁定", businessType = BusinessType.CONTROL)
-    public @ResponseBody
-    AjaxResult setPTZLock(@RequestBody CameraCmd cmd) {
-        cmd.setOperator(SecurityUtils.getUserId());
-        return AjaxResult.success(sdk.controlLock(cmd));
-    }
-
-    @ApiOperation("设置解锁")
-    @PostMapping("/setPTZUnLock")
-    @ApiOperationSupport(includeParameters = {"cmd.cameraId"})
-    @Log(title = "设置解锁", businessType = BusinessType.CONTROL)
-    public @ResponseBody
-    AjaxResult setPTZUnLock(@RequestBody CameraCmd cmd) {
-        cmd.setOperator(SecurityUtils.getUserId());
-        return AjaxResult.success(sdk.controlUnLock(cmd));
-    }
 
     @ApiOperation("获取云台锁定信息")
     @PostMapping("/getPTZLockInfo")
diff --git a/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/HCNetSDK.java b/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/HCNetSDK.java
index d3dbd9f..7754aea 100644
--- a/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/HCNetSDK.java
+++ b/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/HCNetSDK.java
@@ -1802,7 +1802,7 @@
     public static class NET_DVR_COMPRESSIONCFG_V30 extends HIKSDKStructure {
         public int dwSize;
         public NET_DVR_COMPRESSION_INFO_V30 struNormHighRecordPara;    //录像 对应8000的普通
-        public NET_DVR_COMPRESSION_INFO_V30 struRes;   //保留 String[28];
+        public NET_DVR_COMPRESSION_INFO_V30 struRes;                   //保留 String[28];
         public NET_DVR_COMPRESSION_INFO_V30 struEventRecordPara;       //事件触发压缩参数
         public NET_DVR_COMPRESSION_INFO_V30 struNetPara;               //网传(子码流)
 
diff --git a/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/LoginResultCallBack.java b/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/LoginResultCallBack.java
index a385d70..de4b4c1 100644
--- a/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/LoginResultCallBack.java
+++ b/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/LoginResultCallBack.java
@@ -12,11 +12,9 @@
 import com.ruoyi.device.hiksdk.service.IHikClientService;
 import com.ruoyi.media.domain.Vtdu;
 import com.ruoyi.media.service.IVtduService;
-import com.ruoyi.utils.forest.MediaClient;
 import com.sun.jna.Pointer;
 import lombok.extern.slf4j.Slf4j;
 
-import javax.annotation.Resource;
 import java.util.Comparator;
 import java.util.List;
 import java.util.concurrent.PriorityBlockingQueue;
@@ -68,22 +66,17 @@
                     String name = camera.getId() + "_" + channel.getChanNo();
                     String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream";
                     Vtdu vtdu = vtduService.selectVtduByName(name);
-                    if (vtdu == null) {
-                        //添加到流媒体
-                        vtdu = new Vtdu();
-                        vtdu.setRtspSource(rtspSource);
-                        vtdu.setName(camera.getId() + "_" + channel.getChanNo());
-                        vtdu.setIsCode("0");//默认不转码
-                        vtdu.setMode("1");//默认CPU软解码
-                        vtdu.setCameraId(camera.getId());
-                        vtduService.insertVtdu(vtdu);
-                    } else {
-                        if (!rtspSource.equals(vtdu.getRtspSource())) {
-                            //更新rtsp地址
-                            vtdu.setRtspSource(rtspSource);
-                            vtduService.updateVtdu(vtdu);
-                        }
+                    if (vtdu != null) {
+                        vtduService.deleteVtduByName(name);
                     }
+                    //添加到流媒体
+                    vtdu = new Vtdu();
+                    vtdu.setRtspSource(rtspSource);
+                    vtdu.setName(camera.getId() + "_" + channel.getChanNo());
+                    vtdu.setIsCode("0");//默认不转码
+                    vtdu.setMode("1");//默认CPU软解码
+                    vtdu.setCameraId(camera.getId());
+                    vtduService.insertVtdu(vtdu);
                 }
             }
             //创建引导队列
diff --git a/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/IHikClientService.java b/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/IHikClientService.java
index b740fc8..2c2c2c9 100644
--- a/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/IHikClientService.java
+++ b/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/IHikClientService.java
@@ -40,7 +40,7 @@
     boolean setFocusPos(CameraCmd cmd);
 
     //获取聚焦值
-    Map<String, Object> getFocusPos(CameraCmd cmd);
+    int getFocusPos(CameraCmd cmd);
 
     //设置预置位
     boolean setPreset(CameraCmd cmd);
@@ -49,12 +49,12 @@
     boolean gotoPreset(CameraCmd cmd);
 
     //获取码流压缩参数
-    Map<String, String> getVideoCompressionCfg(CameraCmd cmd);
+    Map<String, Object> getVideoCompressionCfg(CameraCmd cmd);
 
     //透雾
     boolean controlDefogcfg(CameraCmd cmd);
 
-    //红外?
+    //红外
     boolean controlInfrarecfg(CameraCmd cmd);
 
     //聚焦模式
@@ -68,12 +68,6 @@
 
     //镜头除冰
     boolean controlCameraDeicing(CameraCmd cmd);
-
-    //配置锁定
-    boolean controlLock(CameraCmd cmd);
-
-    //配置解锁
-    boolean controlUnLock(CameraCmd cmd);
 
     //获取云台锁定信息
     int getPTZLockInfo(CameraCmd cmd);
@@ -90,6 +84,7 @@
     //获取ptz范围
     Map<String, Object> getPtzScope(CameraCmd cmd);
 
+    //设置ptz
     boolean setPtz(CameraCmd cmd);
 
     //设置零方位角
@@ -109,7 +104,7 @@
     String recordStopToMinio(CameraCmd cmd);
 
     //停止录像-不上传minio
-    void recordStopNotToMinio(CameraCmd cmd);
+    boolean recordStopNotToMinio(CameraCmd cmd);
 
     //获取相机通道信息
     public List<ArdChannel> getCameraChannelList(ArdCameras camera);
diff --git a/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/impl/HikClientServiceImpl.java b/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/impl/HikClientServiceImpl.java
index 126acde..d094ae1 100644
--- a/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/impl/HikClientServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/device/hiksdk/service/impl/HikClientServiceImpl.java
@@ -5,7 +5,6 @@
 import com.ruoyi.common.annotation.SdkOperate;
 import com.ruoyi.common.utils.file.FileUtils;
 import com.ruoyi.common.utils.file.MimeTypeUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.common.utils.uuid.IdUtils;
 import com.ruoyi.device.camera.domain.CameraCmd;
 import com.ruoyi.device.camera.service.IArdCamerasService;
@@ -26,7 +25,7 @@
 import com.sun.jna.Pointer;
 import com.sun.jna.ptr.IntByReference;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.util.Base64;
@@ -112,6 +111,7 @@
      * @创建时间 2023/1/17 16:12
      * @修改人和其它信息
      */
+    @Async
     public void syncLogin(ArdCameras camera) {
         // 初始化
         if (!hCNetSDK.NET_DVR_Init()) {
@@ -184,22 +184,23 @@
                     String name = camera.getId() + "_" + channel.getChanNo();
                     String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream";
                     Vtdu vtdu = vtduService.selectVtduByName(name);
-                    if (vtdu == null) {
-                        //添加到流媒体
-                        vtdu = new Vtdu();
-                        vtdu.setRtspSource(rtspSource);
-                        vtdu.setName(camera.getId() + "_" + channel.getChanNo());
-                        vtdu.setIsCode("0");//默认不转码
-                        vtdu.setMode("1");//默认CPU软解码
-                        vtdu.setCameraId(camera.getId());
-                        vtduService.insertVtdu(vtdu);
-                    } else {
-                        if (!rtspSource.equals(vtdu.getRtspSource())) {
-                            //更新rtsp地址
-                            vtdu.setRtspSource(rtspSource);
-                            vtduService.updateVtdu(vtdu);
-                        }
+                    if (vtdu != null) {
+                        vtduService.deleteVtduByName(name);
                     }
+                    //添加到流媒体
+                    vtdu = new Vtdu();
+                    vtdu.setRtspSource(rtspSource);
+                    vtdu.setName(camera.getId() + "_" + channel.getChanNo());
+                    CameraCmd cmd = new CameraCmd(camera.getId(), channel.getChanNo());
+                    Map<String, Object> videoCompressionCfg = getVideoCompressionCfg(cmd);
+                    if (videoCompressionCfg.get("videoEncType").equals("标准h264")) {
+                        vtdu.setIsCode("0");//默认不转码
+                    } else {
+                        vtdu.setIsCode("1");//默认转码
+                    }
+                    vtdu.setMode("1");//默认CPU软解码
+                    vtdu.setCameraId(camera.getId());
+                    vtduService.insertVtdu(vtdu);
                 }
             }
             //创建引导队列
@@ -285,7 +286,7 @@
             for (ArdCameras camera : ardCameras) {
                 Thread.sleep(500);
                 //异步登录
-                asyncLogin(camera);
+                syncLogin(camera);
             }
         } catch (Exception ex) {
             log.error("初始化登录相机异常:" + ex.getMessage());
@@ -305,7 +306,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         boolean b = hCNetSDK.NET_DVR_Logout(userId);
         if (b) {
             GlobalVariable.loginMap.remove(cameraId);
@@ -325,7 +326,7 @@
             if (!GlobalVariable.loginMap.containsKey(cameraId)) {
                 return false;
             }
-            Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+            Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
             return hCNetSDK.NET_DVR_RemoteControl(userId, NET_DVR_CHECK_USER_STATUS, null, 0);
         } catch (Exception ex) {
             log.error("检测在线异常:" + ex.getMessage());
@@ -344,7 +345,6 @@
      * @修改人和其它信息
      */
     @Override
-    @SdkOperate
     public boolean pTZControlWithSpeed(CameraCmd cmd) {
         String cameraId = cmd.getCameraId();
         boolean enable = cmd.isEnable();
@@ -354,7 +354,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         int dwStop;
         if (enable) {
             dwStop = 0;//开启
@@ -431,7 +431,6 @@
      * @param cmd 相机命令
      */
     @Override
-    @SdkOperate
     public boolean setFocusPos(CameraCmd cmd) {
         String cameraId = cmd.getCameraId();
         Integer channelNum = cmd.getChanNo();
@@ -440,7 +439,7 @@
             return false;
         }
         // 获取参数
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         HCNetSDK.NET_DVR_STD_CONFIG struStdCfg = new HCNetSDK.NET_DVR_STD_CONFIG();
         HCNetSDK.NET_DVR_GIS_INFO struGisInfo = new HCNetSDK.NET_DVR_GIS_INFO();
         struGisInfo.struPtzPosEx.dwFocus = dwFocusPos;
@@ -467,14 +466,15 @@
      * @param cmd 相机命令
      */
     @Override
-    public Map<String, Object> getFocusPos(CameraCmd cmd) {
+    public int getFocusPos(CameraCmd cmd) {
+        int result = 0;
         String cameraId = cmd.getCameraId();
         Integer channelNum = cmd.getChanNo();
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
-            return new HashMap<>();
+            return result;
         }
         // 获取参数
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         HCNetSDK.NET_DVR_STD_CONFIG struStdCfg = new HCNetSDK.NET_DVR_STD_CONFIG();
         HCNetSDK.NET_DVR_GIS_INFO struGisInfo = new HCNetSDK.NET_DVR_GIS_INFO();
         struStdCfg.read();
@@ -488,13 +488,12 @@
         if (!bool) {
             int code = hCNetSDK.NET_DVR_GetLastError();
             log.error("获取GIS信息数据失败,请稍后重试" + code);
-            return new HashMap<>();
+            return result;
         } else {
             struGisInfo.read();
-            Map<String, Object> map = new HashMap<>();
-            map.put("dwFocus", struGisInfo.struPtzPosEx.dwFocus);
-            return map;
+            result = struGisInfo.struPtzPosEx.dwFocus;
         }
+        return result;
     }
 
     /**
@@ -503,7 +502,6 @@
      * @param cmd 相机命令
      */
     @Override
-    @SdkOperate
     public boolean setPreset(CameraCmd cmd) {
         String cameraId = cmd.getCameraId();
         Integer channelNum = cmd.getChanNo();
@@ -511,7 +509,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         boolean bool = hCNetSDK.NET_DVR_PTZPreset_Other(userId, channelNum, SET_PRESET, PresetIndex);
         if (!bool) {
             int code = hCNetSDK.NET_DVR_GetLastError();
@@ -526,7 +524,6 @@
      * @param cmd 相机命令
      */
     @Override
-    @SdkOperate
     public boolean gotoPreset(CameraCmd cmd) {
         String cameraId = cmd.getCameraId();
         Integer channelNum = cmd.getChanNo();
@@ -534,7 +531,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         boolean bool = hCNetSDK.NET_DVR_PTZPreset_Other(userId, channelNum, GOTO_PRESET, PresetIndex);
         if (!bool) {
             int code = hCNetSDK.NET_DVR_GetLastError();
@@ -552,15 +549,15 @@
      * @修改人和其它信息
      */
     @Override
-    public Map<String, String> getVideoCompressionCfg(CameraCmd cmd) {
+    public Map<String, Object> getVideoCompressionCfg(CameraCmd cmd) {
         String cameraId = cmd.getCameraId();
         Integer chanNo = cmd.getChanNo();
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return null;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
 
-        Map<String, String> map = new HashMap<>();
+        Map<String, Object> map = new HashMap<>();
         NET_DVR_COMPRESSIONCFG_V30 compressioncfg = new NET_DVR_COMPRESSIONCFG_V30();
         compressioncfg.write();
         Pointer pioint = compressioncfg.getPointer();
@@ -617,85 +614,85 @@
                         videoBitrate = "保留";
                         break;
                     case 1:
-                        videoBitrate = "16K(保留)";
+                        videoBitrate = "16(保留)";
                         break;
                     case 2:
-                        videoBitrate = "32K";
+                        videoBitrate = "32";
                         break;
                     case 3:
-                        videoBitrate = "48k";
+                        videoBitrate = "48";
                         break;
                     case 4:
-                        videoBitrate = "64k";
+                        videoBitrate = "64";
                         break;
                     case 5:
-                        videoBitrate = "80k";
+                        videoBitrate = "80";
                         break;
                     case 6:
-                        videoBitrate = "96k";
+                        videoBitrate = "96";
                         break;
                     case 7:
-                        videoBitrate = "128k";
+                        videoBitrate = "128";
                         break;
                     case 8:
-                        videoBitrate = "160k";
+                        videoBitrate = "160";
                         break;
                     case 9:
-                        videoBitrate = "192k";
+                        videoBitrate = "192";
                         break;
                     case 10:
-                        videoBitrate = "224k";
+                        videoBitrate = "224";
                         break;
                     case 11:
-                        videoBitrate = "256K";
+                        videoBitrate = "256";
                         break;
                     case 12:
-                        videoBitrate = "320K";
+                        videoBitrate = "320";
                         break;
                     case 13:
-                        videoBitrate = "384K";
+                        videoBitrate = "384";
                         break;
                     case 14:
-                        videoBitrate = "448K";
+                        videoBitrate = "448";
                         break;
                     case 15:
-                        videoBitrate = "512K";
+                        videoBitrate = "512";
                         break;
                     case 16:
-                        videoBitrate = "640K";
+                        videoBitrate = "640";
                         break;
                     case 17:
-                        videoBitrate = "768K";
+                        videoBitrate = "768";
                         break;
                     case 18:
-                        videoBitrate = "896K";
+                        videoBitrate = "896";
                         break;
                     case 19:
-                        videoBitrate = "1024K";
+                        videoBitrate = "1024";
                         break;
                     case 20:
-                        videoBitrate = "1280K";
+                        videoBitrate = "1280";
                         break;
                     case 21:
-                        videoBitrate = "1536K";
+                        videoBitrate = "1536";
                         break;
                     case 22:
-                        videoBitrate = "1792K";
+                        videoBitrate = "1792";
                         break;
                     case 23:
                         videoBitrate = "2048K";
                         break;
                     case 24:
-                        videoBitrate = "3072K";
+                        videoBitrate = "3072";
                         break;
                     case 25:
-                        videoBitrate = "4096K";
+                        videoBitrate = "4096";
                         break;
                     case 26:
-                        videoBitrate = "8192K";
+                        videoBitrate = "8192";
                         break;
                     case 27:
-                        videoBitrate = "16384K";
+                        videoBitrate = "16384";
                         break;
                     default:
                         videoBitrate = "其他";
@@ -705,43 +702,43 @@
                 String resolution = "";
                 switch (compressioncfg.struNormHighRecordPara.byResolution) {
                     case 0:
-                        resolution = "DCIF(528*384/528*320)";
+                        resolution = "528*384/528*320";
                         break;
                     case 1:
-                        resolution = "CIF(352*288/352*240)";
+                        resolution = "352*288/352*240";
                         break;
                     case 2:
-                        resolution = "QCIF(176*144/176*120)";
+                        resolution = "176*144/176*120";
                         break;
                     case 3:
-                        resolution = "4CIF(704*576/704*480)";
+                        resolution = "704*576/704*480";
                         break;
                     case 4:
-                        resolution = "2CIF(704*288/704*240)";
+                        resolution = "704*288/704*240";
                         break;
                     case 6:
-                        resolution = "QVGA(320*240)";
+                        resolution = "320*240";
                         break;
                     case 7:
-                        resolution = "QQVGA(160*120)";
+                        resolution = "160*120";
                         break;
                     case 16:
-                        resolution = "VGA(640*480)";
+                        resolution = "640*480";
                         break;
                     case 17:
-                        resolution = "UXGA(1600*1200)";
+                        resolution = "1600*1200";
                         break;
                     case 18:
-                        resolution = "SVGA(800*600)";
+                        resolution = "800*600";
                         break;
                     case 19:
-                        resolution = "HD720P(1280*720)";
+                        resolution = "1280*720";
                         break;
                     case 20:
-                        resolution = "XVGA(1280*960)";
+                        resolution = "1280*960";
                         break;
                     case 21:
-                        resolution = "HD900P(1600*900)";
+                        resolution = "1600*900";
                         break;
                     case 22:
                         resolution = "1360*1024";
@@ -753,7 +750,7 @@
                         resolution = "1920*1920";
                         break;
                     case 27:
-                        resolution = "1920*1080p";
+                        resolution = "1920*1080";
                         break;
                     case 28:
                         resolution = "2560*1920";
@@ -768,10 +765,80 @@
                         resolution = "不在当前分辨率索引,请联系管理员添加";
                         break;
                 }
-                map.put("resolution", resolution);
-                map.put("videoBitrate", videoBitrate);
-                map.put("videoEncType", videoEncType);
-                map.put("streamType", streamType);
+                //帧率
+                String nFrameRate = "";
+                switch (compressioncfg.struNormHighRecordPara.dwVideoFrameRate) {
+                    case 0:
+                        nFrameRate = "0";
+                        break;
+                    case 1:
+                        nFrameRate = "1/16";
+                        break;
+                    case 2:
+                        nFrameRate = "1/8";
+                        break;
+                    case 3:
+                        nFrameRate = "1/4";
+                        break;
+                    case 4:
+                        nFrameRate = "1/2";
+                        break;
+                    case 5:
+                        nFrameRate = "1";
+                        break;
+                    case 6:
+                        nFrameRate = "2";
+                        break;
+                    case 7:
+                        nFrameRate = "4";
+                        break;
+                    case 8:
+                        nFrameRate = "6";
+                        break;
+                    case 9:
+                        nFrameRate = "8";
+                        break;
+                    case 10:
+                        nFrameRate = "10";
+                        break;
+                    case 11:
+                        nFrameRate = "12";
+                        break;
+                    case 12:
+                        nFrameRate = "16";
+                        break;
+                    case 13:
+                        nFrameRate = "20";
+                        break;
+                    case 14:
+                        nFrameRate = "15";
+                        break;
+                    case 15:
+                        nFrameRate = "18";
+                        break;
+                    case 16:
+                        nFrameRate = "22";
+                        break;
+                    case 17:
+                        nFrameRate = "25";
+                        break;
+                    case 18:
+                        nFrameRate = "30";
+                        break;
+                    case 19:
+                        nFrameRate = "35";
+                        break;
+                    case 20:
+                        nFrameRate = "40";
+                        break;
+                    default:
+                        nFrameRate = "未知";
+                        break;
+                }
+                map.put("resolution", resolution);//分辨率
+                map.put("videoBitrate", videoBitrate);//比特率
+                map.put("videoEncType", videoEncType);//编码
+                map.put("nFrameRate", nFrameRate);//帧率
 
             } else {
                 int code = hCNetSDK.NET_DVR_GetLastError();
@@ -798,7 +865,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return new HashMap<>();
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
 
         NET_DVR_PTZPOS m_ptzPosCurrent = new NET_DVR_PTZPOS();
         Pointer pioint = m_ptzPosCurrent.getPointer();
@@ -842,7 +909,6 @@
      * @修改人和其它信息 注意俯仰角度负值需要加上360得到的正值进行设置
      */
     @Override
-    @SdkOperate
     public boolean setPtz(CameraCmd cmd) {
         String cameraId = cmd.getCameraId();
         Integer channelNum = cmd.getChanNo();
@@ -850,13 +916,13 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_PTZPOS m_ptzPosCurrent = new NET_DVR_PTZPOS();
         m_ptzPosCurrent.wAction = 1;
         try {
-            String p = String.valueOf((int)(ptz.get("p") * 10));
-            String t = String.valueOf((int)(ptz.get("t") * 10));
-            String z = String.valueOf((int)(ptz.get("z") * 10));
+            String p = String.valueOf((int) (ptz.get("p") * 10));
+            String t = String.valueOf((int) (ptz.get("t") * 10));
+            String z = String.valueOf((int) (ptz.get("z") * 10));
             m_ptzPosCurrent.wPanPos = (short) (Integer.parseInt(p, 16));
             m_ptzPosCurrent.wTiltPos = (short) (Integer.parseInt(t, 16));
             m_ptzPosCurrent.wZoomPos = (short) (Integer.parseInt(z, 16));
@@ -875,14 +941,13 @@
     }
 
     @Override
-    @SdkOperate
     public boolean guideTargetPosition(CameraCmd cmd) {
         String cameraId = cmd.getCameraId();
         Integer channelNum = cmd.getChanNo();
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_PTZPOS m_ptzPosCurrent = new NET_DVR_PTZPOS();
         m_ptzPosCurrent.wAction = 1;
         try {
@@ -910,49 +975,6 @@
         }
     }
 
-    /**
-     * @描述 操控锁定
-     * @参数 [userId, channelNum]
-     * @返回值 boolean
-     * @创建人 刘苏义
-     * @创建时间 2023/1/17 16:36
-     * @修改人和其它信息 0-解锁 1-锁定
-     */
-    @Override
-    @SdkOperate
-    public boolean controlLock(CameraCmd cmd) {
-        String cameraId = cmd.getCameraId();//申请锁的相机
-        ArdCameras ardCameras = ardCamerasService.selectArdCamerasById(cameraId);
-        Date now = new Date();
-        now.setTime(now.getTime() + cmd.getExpired() * 1000);
-        ardCameras.setOperatorExpired(now);//设置当前过期时间
-        ardCamerasService.updateArdCameras(ardCameras);
-        return true;
-    }
-
-    /**
-     * @描述 操控解锁
-     * @参数 [userId, channelNum]
-     * @返回值 boolean
-     * @创建人 刘苏义
-     * @创建时间 2023/6/30 15:36
-     * @修改人和其它信息
-     */
-    @Override
-    public boolean controlUnLock(CameraCmd cmd) {
-        String cameraId = cmd.getCameraId();//申请解锁的相机
-        String operator = cmd.getOperator();//申请者
-        ArdCameras ardCameras = ardCamerasService.selectArdCamerasById(cameraId);
-        if (ardCameras.getOperatorId().equals(operator)) {
-            //如果解锁相机的当前用户是申请者,则清空该相机的过期时间
-            ardCameras.setOperatorExpired(null);
-            int i = ardCamerasService.updateArdCameras(ardCameras);
-            if (i > 0) {
-                log.debug(cameraId + "--解锁成功");
-            }
-        }
-        return true;
-    }
 
     /**
      * @描述 获取ptz锁定信息
@@ -969,7 +991,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return -1;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_PTZ_LOCKCFG netDvrPtzLockcfg = new NET_DVR_PTZ_LOCKCFG();
         Pointer point = netDvrPtzLockcfg.getPointer();
         IntByReference ibrBytesReturned = new IntByReference(0);
@@ -1001,7 +1023,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_INITIALPOSITIONCTRL initialpositionctrl = new NET_DVR_INITIALPOSITIONCTRL();
 
         initialpositionctrl.dwSize = initialpositionctrl.size();
@@ -1033,7 +1055,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return new HashMap<>();
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_PTZSCOPE m_ptzPosCurrent = new NET_DVR_PTZSCOPE();
         Pointer point = m_ptzPosCurrent.getPointer();
         IntByReference ibrBytesReturned = new IntByReference(0);
@@ -1082,7 +1104,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_CAMERAPARAMCFG_EX struCameraParam = new NET_DVR_CAMERAPARAMCFG_EX();
         Pointer point = struCameraParam.getPointer();
         IntByReference ibrBytesReturned = new IntByReference(0);
@@ -1128,7 +1150,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_CAMERAPARAMCFG_EX struDayNigh = new NET_DVR_CAMERAPARAMCFG_EX();
         Pointer point = struDayNigh.getPointer();
         IntByReference ibrBytesReturned = new IntByReference(0);
@@ -1176,7 +1198,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_FOCUSMODE_CFG struFocusMode = new NET_DVR_FOCUSMODE_CFG();
         Pointer point = struFocusMode.getPointer();
         IntByReference ibrBytesReturned = new IntByReference(0);
@@ -1219,7 +1241,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return "";
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_FOCUSMODE_CFG struFocusMode = new NET_DVR_FOCUSMODE_CFG();
         Pointer point = struFocusMode.getPointer();
         IntByReference ibrBytesReturned = new IntByReference(0);
@@ -1249,7 +1271,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         int dwStop;
         if (enable) {
             dwStop = 0;//开启
@@ -1282,7 +1304,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return false;
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_DEVSERVER_CFG struDeicing = new NET_DVR_DEVSERVER_CFG();
         Pointer point = struDeicing.getPointer();
         IntByReference ibrBytesReturned = new IntByReference(0);
@@ -1319,7 +1341,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return "";
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         NET_DVR_WORKSTATE_V30 devwork = new NET_DVR_WORKSTATE_V30();
         if (!hCNetSDK.NET_DVR_GetDVRWorkState_V30(userId, devwork)) {
             // 返回Boolean值,判断是否获取设备能力
@@ -1362,7 +1384,7 @@
         if (!GlobalVariable.loginMap.containsKey(cameraId)) {
             return "";
         }
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         //图片信息
         NET_DVR_JPEGPARA jpeg = new NET_DVR_JPEGPARA();
         //设置图片分辨率
@@ -1426,7 +1448,7 @@
             if (!GlobalVariable.loginMap.containsKey(cameraId)) {
                 return "";
             }
-            Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+            Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
             //强制I帧结构体对象
             HCNetSDK.NET_DVR_I_FRAME netDvrIFrame = new HCNetSDK.NET_DVR_I_FRAME();   //新建结构体对象
             netDvrIFrame.read();
@@ -1472,7 +1494,7 @@
                 log.debug("录像停止");
                 //存入minio
                 String BucketName = "record";
-                String ObjectName =IdUtils.simpleUUID() + ".mp4";
+                String ObjectName = IdUtils.simpleUUID() + ".mp4";
                 FileInputStream stream = new FileInputStream(path);
                 boolean b = MinioUtil.uploadObject(BucketName, ObjectName, stream, stream.available(), "video/MP4");
                 if (b) {
@@ -1496,7 +1518,7 @@
             if (!GlobalVariable.loginMap.containsKey(cameraId)) {
                 return false;
             }
-            Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+            Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
             //强制I帧结构体对象
             HCNetSDK.NET_DVR_I_FRAME netDvrIFrame = new HCNetSDK.NET_DVR_I_FRAME();   //新建结构体对象
             netDvrIFrame.read();
@@ -1553,7 +1575,7 @@
             if (!GlobalVariable.loginMap.containsKey(cameraId)) {
                 return "";
             }
-            Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+            Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
             //region 强制I帧
             HCNetSDK.NET_DVR_I_FRAME netDvrIFrame = new HCNetSDK.NET_DVR_I_FRAME();   //新建结构体对象
             netDvrIFrame.read();
@@ -1599,14 +1621,15 @@
     }
 
     @Override
-    public void recordStopNotToMinio(CameraCmd cmd) {
+    public boolean recordStopNotToMinio(CameraCmd cmd) {
+        boolean result = false;
         try {
             String cameraId = cmd.getCameraId();
             Integer channelNum = cmd.getChanNo();
             if (!GlobalVariable.loginMap.containsKey(cameraId)) {
-                return;
+                return false;
             }
-            Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+            Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
             //强制I帧结构体对象
             HCNetSDK.NET_DVR_I_FRAME netDvrIFrame = new HCNetSDK.NET_DVR_I_FRAME();   //新建结构体对象
             netDvrIFrame.read();
@@ -1633,9 +1656,12 @@
                 GlobalVariable.previewMap.remove(cameraId);
             }
             log.debug("录像停止");
+            result = true;
         } catch (Exception ex) {
             log.error("录像停止异常" + ex.getMessage());
+            result = false;
         }
+        return result;
     }
 
     //获取IP通道
@@ -1691,7 +1717,7 @@
             return new HashMap<>();
         }
         // 获取参数
-        Integer userId = (Integer)GlobalVariable.loginMap.get(cameraId);
+        Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
         HCNetSDK.NET_DVR_STD_CONFIG struStdCfg = new HCNetSDK.NET_DVR_STD_CONFIG();
         HCNetSDK.NET_DVR_GIS_INFO struGisInfo = new HCNetSDK.NET_DVR_GIS_INFO();
         struStdCfg.read();
diff --git a/ard-work/src/main/java/com/ruoyi/inspect/service/impl/ArdVideoInspectTaskServiceImpl.java b/ard-work/src/main/java/com/ruoyi/inspect/service/impl/ArdVideoInspectTaskServiceImpl.java
index 4ad799a..88f2431 100644
--- a/ard-work/src/main/java/com/ruoyi/inspect/service/impl/ArdVideoInspectTaskServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/inspect/service/impl/ArdVideoInspectTaskServiceImpl.java
@@ -8,6 +8,7 @@
 import com.ruoyi.device.camera.domain.ArdCameras;
 import com.ruoyi.device.camera.domain.CameraCmd;
 import com.ruoyi.device.camera.mapper.ArdCamerasMapper;
+import com.ruoyi.device.camera.service.ICameraSdkService;
 import com.ruoyi.device.hiksdk.service.IHikClientService;
 import com.ruoyi.inspect.domain.ArdVideoInspectRecord;
 import com.ruoyi.inspect.mapper.ArdVideoInspectRecordMapper;
@@ -44,7 +45,7 @@
     @Resource
     private ArdCamerasMapper ardCamerasMapper;
     @Resource
-    private IHikClientService hikClientService;
+    private ICameraSdkService cameraSdkService;
     @Resource
     private ArdCamerasMapper camerasMapper;
 
@@ -455,10 +456,10 @@
                     cmd.setTargetPosition(targetPositon);
                     cmd.setOperator("sys_patrol_inspect");
                     cmd.setExpired(step.getRecordingTime() * 60);
-                    boolean setTargetPosition = hikClientService.guideTargetPosition(cmd);
+                    boolean setTargetPosition = cameraSdkService.guideTargetPosition(cmd);
                     if (setTargetPosition) {
                         /*控制相机巡检成功,开始录像*/
-                        hikClientService.recordStart(cmd);
+                        cameraSdkService.recordStart(cmd);
                     } else {
                         /*控制失败,当前步骤启动时间置null*/
                         ardVideoInspectTask.setCurrentStepStartTime("");
@@ -513,7 +514,7 @@
                     cmd.setTargetPosition(targetPositon);
                     cmd.setOperator("sys_patrol_inspect");
                     cmd.setExpired(step.getRecordingTime() * 60);
-                    boolean setTargetPosition = hikClientService.guideTargetPosition(cmd);
+                    boolean setTargetPosition = cameraSdkService.guideTargetPosition(cmd);
                     if (!setTargetPosition) {
                         /*控制失败,当前步骤启动时间置null*/
                         ardVideoInspectTask.setCurrentStepStartTime("");
@@ -552,7 +553,7 @@
                 cmd.setOperator("sys_patrol_inspect");
                 cmd.setRecordBucketName("record");
                 cmd.setRecordObjectName("inspect_" + IdUtils.fastSimpleUUID());
-                String url = hikClientService.recordStopToMinio(cmd);
+                String url = cameraSdkService.recordStopToMinio(cmd);
                 /*插入巡检记录*/
                 ArdVideoInspectRecord ardVideoInspectRecord = new ArdVideoInspectRecord();
                 ardVideoInspectRecord.setStepId(step.getId());
diff --git a/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java b/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java
index e24e4e6..4dd8d3b 100644
--- a/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java
+++ b/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java
@@ -85,7 +85,9 @@
         vtdu.setRtspUrl(map.get("rtspUrl"));
         vtdu.setRtmpUrl(map.get("rtmpUrl"));
         vtdu.setWebrtcUrl(map.get("webrtcUrl"));
-        vtduService.updateVtdu(vtdu);
+        //vtduService.updateVtdu(vtdu);
+        vtduService.deleteVtduByName(vtdu.getName());
+        vtduService.insertVtdu(vtdu);
         return AjaxResult.success(map);
     }
 
diff --git a/ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java b/ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java
index 5ea0a2d..afbbf20 100644
--- a/ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java
+++ b/ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java
@@ -6,6 +6,8 @@
 import javax.servlet.http.HttpServletResponse;
 
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.device.camera.domain.CameraCmd;
+import com.ruoyi.device.camera.service.ICameraSdkService;
 import com.ruoyi.media.service.IMediaService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -38,7 +40,8 @@
 {
     @Autowired
     private IVtduService vtduService;
-
+    @Resource
+    private ICameraSdkService cameraSdkService;
     /**
      * 查询流媒体管理列表
      */
@@ -71,6 +74,27 @@
     @GetMapping(value = "/{name}")
     public AjaxResult getInfo(@PathVariable("name") String name)
     {
+        //region 自动转码
+        String[] nameArray = name.split("_");
+        String cameraId=nameArray[0];
+        Integer chanNo=Integer.valueOf(nameArray[1]);
+        CameraCmd cmd=new CameraCmd();
+        cmd.setCameraId(cameraId);
+        cmd.setChanNo(chanNo);
+        Map<String, Object> videoCompressionCfg = cameraSdkService.getVideoCompressionCfg(cmd);
+        String videoEncType = (String)videoCompressionCfg.get("videoEncType");
+        Vtdu vtdu = vtduService.selectVtduByName(name);
+        if(!videoEncType.equals("标准h264"))
+        {
+             vtdu.setIsCode("1");
+        }
+        else
+        {
+            vtdu.setIsCode("0");
+        }
+        vtduService.deleteVtduByName(name);
+        vtduService.insertVtdu(vtdu);
+        //endregion
         return success(vtduService.selectVtduByName(name));
     }
 
diff --git a/ard-work/src/main/java/com/ruoyi/media/domain/Conf.java b/ard-work/src/main/java/com/ruoyi/media/domain/Conf.java
index e7cdc7e..791fba8 100644
--- a/ard-work/src/main/java/com/ruoyi/media/domain/Conf.java
+++ b/ard-work/src/main/java/com/ruoyi/media/domain/Conf.java
@@ -15,122 +15,11 @@
 @Data
 public class Conf {
     private String source;
-    @JsonProperty("sourceFingerprint")
-    private String sourcefingerprint;
-    @JsonProperty("sourceOnDemand")
-    private boolean sourceondemand;
-    @JsonProperty("sourceOnDemandStartTimeout")
-    private String sourceondemandstarttimeout;
-    @JsonProperty("sourceOnDemandCloseAfter")
-    private String sourceondemandcloseafter;
-    @JsonProperty("publishUser")
-    private String publishuser;
-    @JsonProperty("publishPass")
-    private String publishpass;
-    @JsonProperty("publishIPs")
-    private List<String> publiships;
-    @JsonProperty("readUser")
-    private String readuser;
-    @JsonProperty("readPass")
-    private String readpass;
-    @JsonProperty("readIPs")
-    private List<String> readips;
-    @JsonProperty("disablePublisherOverride")
-    private boolean disablepublisheroverride;
-    private String fallback;
-    @JsonProperty("sourceProtocol")
-    private String sourceprotocol;
-    @JsonProperty("sourceAnyPortEnable")
-    private boolean sourceanyportenable;
-    @JsonProperty("rtspRangeType")
-    private String rtsprangetype;
-    @JsonProperty("rtspRangeStart")
-    private String rtsprangestart;
-    @JsonProperty("sourceRedirect")
-    private String sourceredirect;
-    @JsonProperty("rpiCameraCamID")
-    private int rpicameracamid;
-    @JsonProperty("rpiCameraWidth")
-    private int rpicamerawidth;
-    @JsonProperty("rpiCameraHeight")
-    private int rpicameraheight;
-    @JsonProperty("rpiCameraHFlip")
-    private boolean rpicamerahflip;
-    @JsonProperty("rpiCameraVFlip")
-    private boolean rpicameravflip;
-    @JsonProperty("rpiCameraBrightness")
-    private int rpicamerabrightness;
-    @JsonProperty("rpiCameraContrast")
-    private int rpicameracontrast;
-    @JsonProperty("rpiCameraSaturation")
-    private int rpicamerasaturation;
-    @JsonProperty("rpiCameraSharpness")
-    private int rpicamerasharpness;
-    @JsonProperty("rpiCameraExposure")
-    private String rpicameraexposure;
-    @JsonProperty("rpiCameraAWB")
-    private String rpicameraawb;
-    @JsonProperty("rpiCameraDenoise")
-    private String rpicameradenoise;
-    @JsonProperty("rpiCameraShutter")
-    private int rpicamerashutter;
-    @JsonProperty("rpiCameraMetering")
-    private String rpicamerametering;
-    @JsonProperty("rpiCameraGain")
-    private int rpicameragain;
-    @JsonProperty("rpiCameraEV")
-    private int rpicameraev;
-    @JsonProperty("rpiCameraROI")
-    private String rpicameraroi;
-    @JsonProperty("rpiCameraTuningFile")
-    private String rpicameratuningfile;
-    @JsonProperty("rpiCameraMode")
-    private String rpicameramode;
-    @JsonProperty("rpiCameraFPS")
-    private int rpicamerafps;
-    @JsonProperty("rpiCameraIDRPeriod")
-    private int rpicameraidrperiod;
-    @JsonProperty("rpiCameraBitrate")
-    private int rpicamerabitrate;
-    @JsonProperty("rpiCameraProfile")
-    private String rpicameraprofile;
-    @JsonProperty("rpiCameraLevel")
-    private String rpicameralevel;
-    @JsonProperty("rpiCameraAfMode")
-    private String rpicameraafmode;
-    @JsonProperty("rpiCameraAfRange")
-    private String rpicameraafrange;
-    @JsonProperty("rpiCameraAfSpeed")
-    private String rpicameraafspeed;
-    @JsonProperty("rpiCameraLensPosition")
-    private int rpicameralensposition;
-    @JsonProperty("rpiCameraAfWindow")
-    private String rpicameraafwindow;
-    @JsonProperty("rpiCameraTextOverlayEnable")
-    private boolean rpicameratextoverlayenable;
-    @JsonProperty("rpiCameraTextOverlay")
-    private String rpicameratextoverlay;
-    @JsonProperty("runOnInit")
-    private String runoninit;
-    @JsonProperty("runOnInitRestart")
-    private boolean runoninitrestart;
-    @JsonProperty("runOnDemand")
-    private String runondemand;
-    @JsonProperty("runOnDemandRestart")
-    private boolean runondemandrestart;
-    @JsonProperty("runOnDemandStartTimeout")
-    private String runondemandstarttimeout;
-    @JsonProperty("runOnDemandCloseAfter")
-    private String runondemandcloseafter;
-    @JsonProperty("runOnReady")
-    private String runonready;
-    @JsonProperty("runOnReadyRestart")
-    private boolean runonreadyrestart;
-    @JsonProperty("runOnRead")
-    private String runonread;
-    @JsonProperty("runOnReadRestart")
-    private boolean runonreadrestart;
-
-    @JsonProperty("maxReaders")
+    private boolean sourceOnDemand;
+    private String sourceProtocol;
     private Integer maxReaders;
+    private String runOnDemand;
+    private boolean runOnDemandRestart;
+    private String runOnDemandStartTimeout;
+    private String runOnDemandCloseAfter;
 }
diff --git a/ard-work/src/main/java/com/ruoyi/media/domain/Items.java b/ard-work/src/main/java/com/ruoyi/media/domain/Items.java
index 09960f7..bd4b340 100644
--- a/ard-work/src/main/java/com/ruoyi/media/domain/Items.java
+++ b/ard-work/src/main/java/com/ruoyi/media/domain/Items.java
@@ -19,18 +19,9 @@
 public class Items {
     private String name;
     private String confName;
-    private Conf conf;
     private Source source;
     private List<Readers> readers;
-    private boolean sourceReady;
     private List<String> tracks;
-    private String mode;
-
-    private String id;
-    private Date created;
-    private String remoteAddr;
-    private String state;
-    private long bytesReceived;
-    private long bytesSent;
+    private Long bytesReceived;
 
 }
diff --git a/ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java b/ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java
index 5d04ef0..c5a3b28 100644
--- a/ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java
+++ b/ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java
@@ -1,9 +1,6 @@
 package com.ruoyi.media.service;
 
-import com.dtflys.forest.annotation.Var;
 import com.ruoyi.media.domain.*;
-
-import java.lang.reflect.MalformedParameterizedTypeException;
 import java.util.List;
 import java.util.Map;
 
@@ -40,6 +37,8 @@
 
     List<String> getNameList();
 
+    boolean checkNameExist(String name);
+
     RtspSession getRtspSessionById(String sessionId);
 
     WebrtcSession getWebrtcSessionById(String sessionId);
diff --git a/ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java b/ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java
new file mode 100644
index 0000000..cccbc36
--- /dev/null
+++ b/ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java
@@ -0,0 +1,65 @@
+package com.ruoyi.media.service;
+
+import com.ruoyi.media.domain.*;
+
+import java.util.List;
+import java.util.Map;
+
+public interface IMediaV2Service {
+    /**
+     * 增加路径
+     * name 名称
+     * rtspPath rtsp地址
+     * mode 模式:gpu硬解码/cpu软解码
+     * isCode 是否转码
+     * 刘苏义
+     * 2023/8/12 13:56:52
+     */
+    Map<String, String> addPath(String name, String sourceUrl, String mode, String isCode);
+
+    /**
+     * 修改路径
+     * name 名称
+     * rtspPath rtsp地址
+     * mode 模式:实时/按需
+     * isCode 是否转码
+     * 刘苏义
+     * 2023/8/12 13:56:52
+     */
+    Map<String, String> editPath(String name, String sourceUrl, String mode, String isCode);
+
+    StreamInfo getPathInfo(String name);
+
+    void removePath(String[] names);
+
+    void removePath(String name);
+
+    List<StreamInfo> paths();
+
+    List<String> getNameList();
+
+    boolean checkNameExist(String name);
+
+    RtspSession getRtspSessionById(String sessionId);
+
+    WebrtcSession getWebrtcSessionById(String sessionId);
+
+    RtmpSession getRtmpSessionById(String sessionId);
+
+    List<StreamInfo> getPushStreamList();
+
+    List<StreamInfo> getPullStreamList();
+
+    Boolean kickRtspSession(String sessionId);
+
+    Boolean kickRtmpSession(String sessionId);
+
+    Boolean kickWebrtcSession(String sessionId);
+
+    /**
+     * 配置流媒体参数
+     * 刘苏义
+     * 2023/10/13 15:17:57
+     */
+    public String setConfig(Config config);
+}
diff --git a/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java b/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java
index 5d84867..dcb2670 100644
--- a/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java
@@ -1,31 +1,18 @@
 package com.ruoyi.media.service.impl;
 
 import com.alibaba.fastjson2.JSONObject;
-import com.dtflys.forest.Forest;
 import com.dtflys.forest.exceptions.ForestNetworkException;
-import com.dtflys.forest.exceptions.ForestRuntimeException;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.media.domain.*;
-import com.ruoyi.media.mapper.VtduMapper;
 import com.ruoyi.media.service.IMediaService;
 import com.ruoyi.utils.forest.MediaClient;
 import com.ruoyi.utils.tools.ArdTool;
-import com.ruoyi.utils.process.CmdUtils;
-import com.sun.jna.Platform;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
 import org.springframework.core.annotation.Order;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
 import javax.annotation.Resource;
-import java.io.File;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -65,34 +52,27 @@
         String rtmpUrl = "rtmp://" + mediamtxHost + ":1935/" + name;
         String webrtcUrl = "http://" + mediamtxHost + ":8889/" + name;
 
-        Conf mediaInfo = new Conf();
+        Conf conf = new Conf();
         String rootPath = System.getProperty("user.dir").replaceAll("\\\\", "/") + "/lib/mediamtx/";
         if (isCode.equals("1")) {
-            mediaInfo.setSource("publisher");
+            conf.setSource("publisher");
             //默认软解码
             String cmd = "ffmpeg -rtsp_transport tcp -i " + sourceUrl + " -vcodec libx264 -preset:v ultrafast -r 25 -keyint_min 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
             if (mode.equals("0")) {//硬解码
                 cmd = "ffmpeg -hwaccel cuvid -c:v hevc_cuvid  -rtsp_transport tcp  -i " + sourceUrl + " -c:v h264_nvenc  -r 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -bf 0 -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
             }
-            mediaInfo.setRunondemand(cmd);
-            mediaInfo.setRunondemandrestart(true);
-            mediaInfo.setRunondemandcloseafter("5s");
+            conf.setRunOnDemand(cmd);
+            conf.setRunOnDemandRestart(true);
+            conf.setRunOnDemandCloseAfter("5s");
         } else {
-            mediaInfo.setSource(sourceUrl);
-            mediaInfo.setSourceondemand(true);
+            conf.setSource(sourceUrl);
+            conf.setSourceOnDemand(true);
         }
-        mediaInfo.setMaxReaders(100);
-        mediaInfo.setSourceprotocol("tcp");
+        conf.setMaxReaders(100);
+        conf.setSourceProtocol("tcp");
 
-        List<String> nameList=new ArrayList<>();
-        String paths = mediaClient.paths();
-        JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class);
-        List<Items> items = jsonsRoot.getItems();
-        for (Items item : items) {
-            nameList.add(item.getName());
-        }
-        if(!nameList.contains(name)) {
-            mediaClient.addPath(name, mediaInfo);
+        if (!checkNameExist(name)) {
+            mediaClient.addPath(name, conf);
         }
         Map<String, String> map = new HashMap<>();
         map.put("rtspUrl", rtspUrl);
@@ -109,27 +89,29 @@
             String rtmpUrl = "rtmp://" + mediamtxHost + ":1935/" + name;
             String webrtcUrl = "http://" + mediamtxHost + ":8889/" + name;
 
-            Conf mediaInfo = new Conf();
+            Conf conf = new Conf();
             String rootPath = System.getProperty("user.dir").replaceAll("\\\\", "/") + "/lib/mediamtx/";
             if (isCode.equals("1")) {
-                mediaInfo.setSource("publisher");
+                conf.setSource("publisher");
                 //默认软解码
                 String cmd = "ffmpeg -rtsp_transport tcp -i " + sourceUrl + " -vcodec libx264 -preset:v ultrafast -r 25 -keyint_min 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
                 if (mode.equals("0")) {//硬解码
                     cmd = "ffmpeg -hwaccel cuvid -c:v hevc_cuvid  -rtsp_transport tcp  -i " + sourceUrl + " -c:v h264_nvenc  -r 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -bf 0 -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
                 }
-                mediaInfo.setRunondemand(cmd);
-                mediaInfo.setRunondemandrestart(true);
-                mediaInfo.setRunondemandcloseafter("5s");
+                conf.setRunOnDemand(cmd);
+                conf.setRunOnDemandRestart(true);
+                conf.setRunOnDemandCloseAfter("5s");
             } else {
-                mediaInfo.setSource(sourceUrl);
+                conf.setSource(sourceUrl);
+                conf.setSourceOnDemand(true);
             }
-            mediaInfo.setMaxReaders(100);
-            mediaInfo.setSourceprotocol("tcp");
+            conf.setMaxReaders(100);
+            conf.setSourceProtocol("tcp");
 
-            mediaClient.editPath(name, mediaInfo);
+            if (checkNameExist(name)) {
+                mediaClient.editPath(name, conf);
+            }
 
-            // Map<String,String> map=new HashMap<>();
             map.put("rtspUrl", rtspUrl);
             map.put("rtmpUrl", rtmpUrl);
             map.put("webrtcUrl", webrtcUrl);
@@ -141,18 +123,14 @@
 
     @Override
     public StreamInfo getPathInfo(String name) {
-        Items item = mediaClient.getPathInfo(name);
+        Conf conf = mediaClient.getPathInfo(name);
         StreamInfo info = new StreamInfo();
         //ID
         info.setName(name);
-        String runOn;
-        if (StringUtils.isNotEmpty(item.getConf().getRunondemand())) {
-            runOn = item.getConf().getRunondemand();
+        String runOn = "";
+        if (StringUtils.isNotEmpty(conf.getRunOnDemand())) {
+            runOn = conf.getRunOnDemand();
             info.setMode("0");
-        } else {
-            //runOn = item.getConf().getRunonready();
-            runOn = item.getConf().getRunoninit();
-            info.setMode("1");
         }
         //RTSP源地址
         Matcher matcher = Pattern.compile("rtsp://[^\\s\"]+").matcher(runOn);
@@ -160,7 +138,7 @@
             info.setRtspSource(matcher.group());
             info.setIsCode("1");
         } else {
-            info.setRtspSource(item.getConf().getSource());
+            info.setRtspSource(conf.getSource());
             info.setIsCode("0");
         }
         return info;
@@ -169,13 +147,17 @@
     @Override
     public void removePath(String[] names) {
         for (String name : names) {
-            mediaClient.removePath(name);
+            if (checkNameExist(name)) {
+                mediaClient.removePath(name);
+            }
         }
     }
 
     @Override
     public void removePath(String name) {
-        mediaClient.removePath(name);
+        if (checkNameExist(name)) {
+            mediaClient.removePath(name);
+        }
     }
 
     @Override
@@ -189,9 +171,11 @@
             //ID
             String name = item.getName();
             info.setName(name);
+
+            Conf conf = mediaClient.getPathInfo(name);
             String runOn = "";
-            if (StringUtils.isNotEmpty(item.getConf().getRunondemand())) {
-                runOn = item.getConf().getRunondemand();
+            if (StringUtils.isNotEmpty(conf.getRunOnDemand())) {
+                runOn = conf.getRunOnDemand();
             }
             //RTSP源地址
             Matcher matcher = Pattern.compile("rtsp://[^\\s\"]+").matcher(runOn);
@@ -199,7 +183,7 @@
                 info.setRtspSource(matcher.group());
                 info.setIsCode("1");
             } else {
-                info.setRtspSource(item.getConf().getSource());
+                info.setRtspSource(conf.getSource());
                 info.setIsCode("0");
             }
             //传输协议
@@ -212,7 +196,6 @@
         }
         return pathInfoList;
     }
-
 
     @Override
     public RtspSession getRtspSessionById(String sessionId) {
@@ -251,6 +234,9 @@
             //ID
             String name = item.getName();
             info.setName(name);
+
+            Conf conf = mediaClient.getPathInfo(name);
+
             //RTMP播放地址
             String rtmpUrl = "rtmp://" + mediamtxHost + ":1935/" + name;
             info.setRtmpUrl(rtmpUrl);
@@ -287,17 +273,17 @@
             }
             //RTSP源地址
             String runOn = "";
-            if (StringUtils.isNotEmpty(item.getConf().getRunondemand())) {
-                runOn = item.getConf().getRunondemand();
+            if (StringUtils.isNotEmpty(conf.getRunOnDemand())) {
+                runOn = conf.getRunOnDemand();
             }
             Matcher matcher = Pattern.compile("rtsp://[^\\s\"]+").matcher(runOn);
             if (matcher.find()) {
                 info.setRtspSource(matcher.group());
             } else {
-                info.setRtspSource(item.getConf().getSource());
+                info.setRtspSource(conf.getSource());
             }
             //传输协议
-            info.setProtocol(item.getConf().getSourceprotocol());
+            info.setProtocol(conf.getSourceProtocol());
             //拉流数量
             List<Readers> readers = item.getReaders();
             info.setNum(readers.size());
@@ -325,8 +311,9 @@
                 //ID
                 String name = item.getName();
                 info.setName(name);
+                Conf conf = mediaClient.getPathInfo(name);
                 //传输协议
-                info.setProtocol(item.getConf().getSourceprotocol());
+                info.setProtocol(conf.getSourceProtocol());
 
                 String type = reader.getType();
                 switch (type) {
@@ -448,14 +435,15 @@
             return false;
         }
     }
+
     /**
-     *  获取流媒体name列表
+     * 获取流媒体name列表
      * 刘苏义
      * 2023/10/13 14:19:07
      */
     @Override
     public List<String> getNameList() {
-        List<String> nameList=new ArrayList<>();
+        List<String> nameList = new ArrayList<>();
         String paths = mediaClient.paths();
         JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class);
         List<Items> items = jsonsRoot.getItems();
@@ -464,6 +452,22 @@
         }
         return nameList;
     }
+
+    /**
+     * 检查名称是否存在
+     * 刘苏义
+     * 2023/10/19 15:18:45
+     */
+    @Override
+    public boolean checkNameExist(String name) {
+        boolean result = false;
+        List<String> nameList = getNameList();
+        if (nameList.contains(name)) {
+            result = true;
+        }
+        return result;
+    }
+
     /**
      * 配置流媒体参数
      */
diff --git a/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaV2ServiceImpl.java b/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaV2ServiceImpl.java
new file mode 100644
index 0000000..fcd2cab
--- /dev/null
+++ b/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaV2ServiceImpl.java
@@ -0,0 +1,490 @@
+package com.ruoyi.media.service.impl;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.dtflys.forest.exceptions.ForestNetworkException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.media.domain.*;
+import com.ruoyi.media.service.IMediaService;
+import com.ruoyi.media.service.IMediaV2Service;
+import com.ruoyi.utils.forest.MediaClient;
+import com.ruoyi.utils.tools.ArdTool;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @Description: 流媒体业务
+ * @ClassName: MediaService
+ * @Author: 刘苏义
+ * @Date: 2023年07月13日9:28
+ * @Version: 1.0
+ **/
+@Service
+@Slf4j(topic = "cmd")
+@Order(2)
+public class MediaV2ServiceImpl implements IMediaV2Service {
+
+    @Resource
+    MediaClient mediaClient;
+
+    @Value("${mediamtx.host}")
+    String mediamtxHost;
+
+    /**
+     * 添加流媒体
+     * name 相机ID
+     * sourceUrl rtsp地址
+     * isCode 0-不转码 1-转码
+     * mode 0-gpu硬解码 1-cpu软解码
+     * <p>
+     * 刘苏义
+     * 2023/10/12 9:03:41
+     */
+    @Override
+    public Map<String, String> addPath(String name, String sourceUrl, String mode, String isCode) {
+
+        String rtspUrl = "rtsp://" + mediamtxHost + ":8554/" + name;
+        String rtmpUrl = "rtmp://" + mediamtxHost + ":1935/" + name;
+        String webrtcUrl = "http://" + mediamtxHost + ":8889/" + name;
+
+        Conf conf = new Conf();
+        String rootPath = System.getProperty("user.dir").replaceAll("\\\\", "/") + "/lib/mediamtx/";
+        if (isCode.equals("1")) {
+            conf.setSource("publisher");
+            //默认软解码
+            String cmd = "ffmpeg -rtsp_transport tcp -i " + sourceUrl + " -vcodec libx264 -preset:v ultrafast -r 25 -keyint_min 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
+            if (mode.equals("0")) {//硬解码
+                cmd = "ffmpeg -hwaccel cuvid -c:v hevc_cuvid  -rtsp_transport tcp  -i " + sourceUrl + " -c:v h264_nvenc  -r 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -bf 0 -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
+            }
+            conf.setRunOnDemand(cmd);
+            conf.setRunOnDemandRestart(true);
+            conf.setRunOnDemandCloseAfter("5s");
+        } else {
+            conf.setSource(sourceUrl);
+            conf.setRunOnDemandRestart(true);
+        }
+        conf.setMaxReaders(100);
+        conf.setSourceProtocol("tcp");
+
+        List<String> nameList = new ArrayList<>();
+        String paths = mediaClient.paths();
+        JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class);
+        List<Items> items = jsonsRoot.getItems();
+        for (Items item : items) {
+            nameList.add(item.getName());
+        }
+        if (!nameList.contains(name)) {
+            mediaClient.addPath(name, conf);
+        }
+        Map<String, String> map = new HashMap<>();
+        map.put("rtspUrl", rtspUrl);
+        map.put("rtmpUrl", rtmpUrl);
+        map.put("webrtcUrl", webrtcUrl);
+        return map;
+    }
+
+    @Override
+    public Map<String, String> editPath(String name, String sourceUrl, String mode, String isCode) {
+        Map<String, String> map = new HashMap<>();
+        try {
+            String rtspUrl = "rtsp://" + mediamtxHost + ":8554/" + name;
+            String rtmpUrl = "rtmp://" + mediamtxHost + ":1935/" + name;
+            String webrtcUrl = "http://" + mediamtxHost + ":8889/" + name;
+
+            Conf mediaInfo = new Conf();
+            String rootPath = System.getProperty("user.dir").replaceAll("\\\\", "/") + "/lib/mediamtx/";
+            if (isCode.equals("1")) {
+                mediaInfo.setSource("publisher");
+                //默认软解码
+                String cmd = "ffmpeg -rtsp_transport tcp -i " + sourceUrl + " -vcodec libx264 -preset:v ultrafast -r 25 -keyint_min 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
+                if (mode.equals("0")) {//硬解码
+                    cmd = "ffmpeg -hwaccel cuvid -c:v hevc_cuvid  -rtsp_transport tcp  -i " + sourceUrl + " -c:v h264_nvenc  -r 25 -g 60 -sc_threshold 0 -threads 6  -b:v 2048k -bf 0 -acodec opus  -strict -2 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
+                }
+                mediaInfo.setRunOnDemand(cmd);
+                mediaInfo.setRunOnDemandRestart(true);
+                mediaInfo.setRunOnDemandCloseAfter("5s");
+            } else {
+                mediaInfo.setSource(sourceUrl);
+            }
+            mediaInfo.setMaxReaders(100);
+            mediaInfo.setSourceProtocol("tcp");
+
+            if (checkNameExist(name)) {
+                mediaClient.editPath(name, mediaInfo);
+            }
+
+            map.put("rtspUrl", rtspUrl);
+            map.put("rtmpUrl", rtmpUrl);
+            map.put("webrtcUrl", webrtcUrl);
+        } catch (ForestNetworkException ex) {
+            log.error(ex.getMessage());
+        }
+        return map;
+    }
+
+    @Override
+    public StreamInfo getPathInfo(String name) {
+        Conf conf = mediaClient.getPathInfo(name);
+        StreamInfo info = new StreamInfo();
+        //ID
+        info.setName(name);
+        String runOn="";
+        if (StringUtils.isNotEmpty(conf.getRunOnDemand())) {
+            runOn = conf.getRunOnDemand();
+        }
+        //RTSP源地址
+        Matcher matcher = Pattern.compile("rtsp://[^\\s\"]+").matcher(runOn);
+        if (matcher.find()) {
+            info.setRtspSource(matcher.group());
+            info.setIsCode("1");
+        } else {
+            info.setRtspSource(conf.getSource());
+            info.setIsCode("0");
+        }
+        return info;
+    }
+
+    @Override
+    public void removePath(String[] names) {
+        for (String name : names) {
+            if(checkNameExist(name)) {
+            mediaClient.removePath(name);}
+        }
+    }
+
+    @Override
+    public void removePath(String name) {
+        if(checkNameExist(name)) {
+            mediaClient.removePath(name);
+        }
+    }
+
+    @Override
+    public List<StreamInfo> paths() {
+        String list = mediaClient.paths();
+        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
+        List<Items> items = jsonsRoot.getItems();
+        List<StreamInfo> pathInfoList = new ArrayList<>();
+        for (Items item : items) {
+            StreamInfo info = new StreamInfo();
+            //ID
+            String name = item.getName();
+            info.setName(name);
+            Conf conf = mediaClient.getPathInfo(name);
+
+            String runOn = "";
+            if (StringUtils.isNotEmpty(conf.getRunOnDemand())) {
+                runOn = conf.getRunOnDemand();
+            }
+            //RTSP源地址
+            Matcher matcher = Pattern.compile("rtsp://[^\\s\"]+").matcher(runOn);
+            if (matcher.find()) {
+                info.setRtspSource(matcher.group());
+                info.setIsCode("1");
+            } else {
+                info.setRtspSource(conf.getSource());
+                info.setIsCode("0");
+            }
+            //传输协议
+            matcher = Pattern.compile("-rtsp_transport\\s+(\\w+)").matcher(runOn);
+            if (matcher.find()) {
+                info.setProtocol(matcher.group(1));
+            }
+
+            pathInfoList.add(info);
+        }
+        return pathInfoList;
+    }
+
+
+    @Override
+    public RtspSession getRtspSessionById(String sessionId) {
+        String list = mediaClient.getRtspsessionById(sessionId);
+        RtspSession rtspSession = JSONObject.parseObject(list, RtspSession.class);
+        return rtspSession;
+    }
+
+    @Override
+    public WebrtcSession getWebrtcSessionById(String sessionId) {
+        String list = mediaClient.getWebrtcsessionById(sessionId);
+        WebrtcSession webrtcSession = JSONObject.parseObject(list, WebrtcSession.class);
+        return webrtcSession;
+    }
+
+    @Override
+    public RtmpSession getRtmpSessionById(String sessionId) {
+        String list = mediaClient.getRtmpsessionById(sessionId);
+        RtmpSession rtmpSession = JSONObject.parseObject(list, RtmpSession.class);
+        return rtmpSession;
+    }
+
+    /**
+     * 获取推流列表
+     * 刘苏义
+     * 2023/8/29 9:37:05
+     */
+    @Override
+    public List<StreamInfo> getPushStreamList() {
+        List<StreamInfo> PushStreamInfoList = new ArrayList<>();
+        String list = mediaClient.paths();
+        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
+        List<Items> items = jsonsRoot.getItems();
+        for (Items item : items) {
+            StreamInfo info = new StreamInfo();
+            //ID
+            String name = item.getName();
+            info.setName(name);
+
+            Conf conf = mediaClient.getPathInfo(name);
+            //RTMP播放地址
+            String rtmpUrl = "rtmp://" + mediamtxHost + ":1935/" + name;
+            info.setRtmpUrl(rtmpUrl);
+            //RTSP播放地址
+            String rtspUrl = "rtsp://" + mediamtxHost + ":8554/" + name;
+            info.setRtspUrl(rtspUrl);
+            //WEBRTC播放地址
+            String webrtcUrl = "http://" + mediamtxHost + ":8889/" + name;
+            info.setWebrtcUrl(webrtcUrl);
+            Source source = item.getSource();
+            if (source == null || source.getId().equals("")) {
+                //会话ID
+                info.setId("0");
+                //上行流量
+                long bytesReceived = item.getBytesReceived();
+                String formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
+                info.setUpTraffic(formatReceivedSize);
+            } else {
+                RtspSession rtspSession = getRtspSessionById(source.getId());
+                //会话ID
+                info.setId(rtspSession.getId());
+                //开始推流时间
+                info.setBeginTime(rtspSession.getCreated());
+                //上行流量
+                long bytesReceived = rtspSession.getBytesReceived();
+                String formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
+                info.setUpTraffic(formatReceivedSize);
+                //下行流量
+                long bytesSent = rtspSession.getBytesSent();
+                String formatSentSize = ArdTool.formatFileSize(bytesSent);
+                info.setDownTraffic(formatSentSize);
+                //推流服务器
+                info.setRemoteAddr(rtspSession.getRemoteAddr());
+            }
+            //RTSP源地址
+            String runOn = "";
+            if (StringUtils.isNotEmpty(conf.getRunOnDemand())) {
+                runOn = conf.getRunOnDemand();
+            }
+            Matcher matcher = Pattern.compile("rtsp://[^\\s\"]+").matcher(runOn);
+            if (matcher.find()) {
+                info.setRtspSource(matcher.group());
+            } else {
+                info.setRtspSource(conf.getSource());
+            }
+            //传输协议
+            info.setProtocol(conf.getSourceProtocol());
+            //拉流数量
+            List<Readers> readers = item.getReaders();
+            info.setNum(readers.size());
+
+            PushStreamInfoList.add(info);
+        }
+        return PushStreamInfoList;
+    }
+
+    /**
+     * 获取拉流列表
+     * 刘苏义
+     * 2023/8/29 9:37:05
+     */
+    @Override
+    public List<StreamInfo> getPullStreamList() {
+        List<StreamInfo> PullStreamInfoList = new ArrayList<>();
+        String list = mediaClient.paths();
+        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
+        List<Items> items = jsonsRoot.getItems();
+        for (Items item : items) {
+            List<Readers> readers = item.getReaders();
+            for (Readers reader : readers) {
+                StreamInfo info = new StreamInfo();
+                //ID
+                String name = item.getName();
+                info.setName(name);
+
+                Conf conf = mediaClient.getPathInfo(name);
+                //传输协议
+                info.setProtocol(conf.getSourceProtocol());
+
+                String type = reader.getType();
+                switch (type) {
+                    case "rtmpConn":
+                        info.setSessionType("rtmp");
+                        //webrtc播放地址
+                        String url = "rtmp://" + mediamtxHost + ":1935/" + name;
+                        info.setRtspUrl(url);
+                        RtmpSession rtmpSession = getRtmpSessionById(reader.getId());
+                        //会话ID
+                        info.setId(rtmpSession.getId());
+                        //开始拉流时间
+                        info.setBeginTime(rtmpSession.getCreated());
+                        //上行流量
+                        long bytesReceived = rtmpSession.getBytesReceived();
+                        String formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
+                        info.setUpTraffic(formatReceivedSize);
+                        //下行流量
+                        long bytesSent = rtmpSession.getBytesSent();
+                        String formatSentSize = ArdTool.formatFileSize(bytesSent);
+                        info.setDownTraffic(formatSentSize);
+                        //拉流服务器
+                        info.setRemoteAddr(rtmpSession.getRemoteAddr());
+                        PullStreamInfoList.add(info);
+                        break;
+                    case "webRTCSession":
+                        info.setSessionType("webrtc");
+                        //webrtc播放地址
+                        url = "http://" + mediamtxHost + ":8889/" + name;
+                        info.setRtspUrl(url);
+                        WebrtcSession webrtcSession = getWebrtcSessionById(reader.getId());
+                        //会话ID
+                        info.setId(webrtcSession.getId());
+                        //开始拉流时间
+                        info.setBeginTime(webrtcSession.getCreated());
+                        //上行流量
+                        bytesReceived = webrtcSession.getBytesReceived();
+                        formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
+                        info.setUpTraffic(formatReceivedSize);
+                        //下行流量
+                        bytesSent = webrtcSession.getBytesSent();
+                        formatSentSize = ArdTool.formatFileSize(bytesSent);
+                        info.setDownTraffic(formatSentSize);
+                        //拉流服务器
+                        info.setRemoteAddr(webrtcSession.getRemoteAddr());
+                        PullStreamInfoList.add(info);
+                        break;
+                    case "rtspSession":
+                        info.setSessionType("rtsp");
+                        //RTSP播放地址
+                        String rtspUrl = "rtsp://" + mediamtxHost + ":8554/" + name;
+                        info.setRtspUrl(rtspUrl);
+                        RtspSession rtspSession = getRtspSessionById(reader.getId());
+                        //会话ID
+                        info.setId(rtspSession.getId());
+                        //开始拉流时间
+                        info.setBeginTime(rtspSession.getCreated());
+                        //上行流量
+                        bytesReceived = rtspSession.getBytesReceived();
+                        formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
+                        info.setUpTraffic(formatReceivedSize);
+                        //下行流量
+                        bytesSent = rtspSession.getBytesSent();
+                        formatSentSize = ArdTool.formatFileSize(bytesSent);
+                        info.setDownTraffic(formatSentSize);
+                        //拉流服务器
+                        info.setRemoteAddr(rtspSession.getRemoteAddr());
+                        PullStreamInfoList.add(info);
+                        break;
+                }
+            }
+        }
+        Comparator<StreamInfo> comparator = Comparator.comparing(streamInfo -> streamInfo.getBeginTime()); // 使用Collections.sort方法进行排序 Collections.sort(personList, comparator);
+        Collections.sort(PullStreamInfoList, comparator.reversed());
+        return PullStreamInfoList;
+    }
+
+    /**
+     * 踢出rtsp会话
+     * 刘苏义
+     * 2023/8/29 9:37:05
+     */
+    @Override
+    public Boolean kickRtspSession(String sessionId) {
+        try {
+            mediaClient.kickRtspSessions(sessionId);
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    /**
+     * 踢出rtmp会话
+     * 刘苏义
+     * 2023/8/29 9:37:05
+     */
+    @Override
+    public Boolean kickRtmpSession(String sessionId) {
+        try {
+            mediaClient.kickRtmpSessions(sessionId);
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    /**
+     * 踢出webrtc会话
+     * 刘苏义
+     * 2023/8/29 9:37:05
+     */
+    @Override
+    public Boolean kickWebrtcSession(String sessionId) {
+        try {
+            mediaClient.kickWebrtcSessions(sessionId);
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    /**
+     * 获取流媒体name列表
+     * 刘苏义
+     * 2023/10/13 14:19:07
+     */
+    @Override
+    public List<String> getNameList() {
+        List<String> nameList = new ArrayList<>();
+        try {
+            String paths = mediaClient.paths();
+            JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class);
+            List<Items> items = jsonsRoot.getItems();
+            for (Items item : items) {
+                nameList.add(item.getName());
+            }
+        }
+        catch (Exception ex)
+        {
+            log.error(ex.getMessage());
+        }
+        return nameList;
+    }
+
+    /**
+     * 检查名称是否存在
+     * 刘苏义
+     * 2023/10/19 15:18:45
+     */
+    @Override
+    public boolean checkNameExist(String name) {
+        boolean result = false;
+        List<String> nameList = getNameList();
+        if (nameList.contains(name)) {
+            result = true;
+        }
+        return result;
+    }
+
+    /**
+     * 配置流媒体参数
+     */
+    @Override
+    public String setConfig(Config config) {
+        return mediaClient.setConfig(config);
+    }
+}
diff --git a/ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java b/ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java
index 05cc175..ee991af 100644
--- a/ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java
@@ -1,19 +1,11 @@
 package com.ruoyi.media.service.impl;
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.uuid.IdUtils;
 import com.ruoyi.media.service.IMediaService;
-import com.ruoyi.utils.forest.MediaClient;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import com.ruoyi.media.mapper.VtduMapper;
 import com.ruoyi.media.domain.Vtdu;
@@ -28,7 +20,7 @@
  * @date 2023-08-29
  */
 @Service
-@Slf4j
+@Slf4j(topic = "sdk")
 public class VtduServiceImpl implements IVtduService {
     @Resource
     private VtduMapper vtduMapper;
@@ -43,6 +35,7 @@
      */
     @Override
     public Vtdu selectVtduByName(String name) {
+
         return vtduMapper.selectVtduByName(name);
     }
 
@@ -65,7 +58,7 @@
      */
     @Override
     public int insertVtdu(Vtdu vtdu) {
-        log.info("流媒体【" + vtdu.getName() + "】通道添加");
+        log.debug("流媒体【" + vtdu.getName() + "】通道添加");
         Map<String, String> map = mediaService.addPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode());
         vtdu.setRtspUrl(map.get("rtspUrl"));
         vtdu.setRtmpUrl(map.get("rtmpUrl"));
@@ -88,7 +81,7 @@
     @Override
     public int updateVtdu(Vtdu vtdu) {
 
-        log.info("流媒体【" + vtdu.getName() + "】通道更新");
+        log.debug("流媒体【" + vtdu.getName() + "】通道更新");
         Map<String, String> map = mediaService.editPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode());
         vtdu.setName(vtdu.getName());
         vtdu.setRtspSource(vtdu.getRtspSource());
@@ -109,6 +102,9 @@
      */
     @Override
     public int deleteVtduByNames(String[] names) {
+        for (String name : names) {
+            log.debug("流媒体【" + name + "】通道删除");
+        }
         mediaService.removePath(names);
         return vtduMapper.deleteVtduByNames(names);
     }
@@ -121,6 +117,8 @@
      */
     @Override
     public int deleteVtduByName(String name) {
+        log.debug("流媒体【" + name + "】通道删除");
+        mediaService.removePath(name);
         return vtduMapper.deleteVtduByName(name);
     }
 
diff --git a/ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java b/ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java
index 70fa4da..392e2fc 100644
--- a/ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java
+++ b/ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java
@@ -1,7 +1,6 @@
 package com.ruoyi.utils.forest;
 
 import com.dtflys.forest.annotation.*;
-import com.dtflys.forest.callback.OnError;
 import com.ruoyi.media.domain.Conf;
 import com.ruoyi.media.domain.Config;
 import com.ruoyi.media.domain.Items;
@@ -13,7 +12,7 @@
  * @Date: 2023年07月06日9:51
  * @Version: 1.0
  **/
-@BaseRequest(baseURL = "http://#{mediamtx.host}:9997/v2")
+@BaseRequest(baseURL = "http://#{mediamtx.host}:9997/v3")
 public interface MediaClient {
     /**
      * 增加路径
@@ -24,20 +23,20 @@
     /**
      * 修改路径
      */
-    @Post(url = "/config/paths/edit/{name}", async = true)
+    @Patch(url = "/config/paths/patch/{name}")
     public String editPath(@Var("name") String name, @JSONBody Conf body);
 
     /**
      * 移除路径
      */
-    @Post("/config/paths/remove/{name}")
+    @Delete("/config/paths/delete/{name}")
     public String removePath(@Var("name") String name);
 
     /**
      * 获取路径详情
      */
-    @Get("/paths/get/{name}")
-    public Items getPathInfo(@Var("name") String name);
+    @Get("/config/paths/get/{name}")
+    public Conf getPathInfo(@Var("name") String name);
 
     /**
      * 查询所有路径
@@ -50,12 +49,6 @@
      */
     @Get("/rtspsessions/list")
     public String rtspsessions();
-
-    /**
-     * 查询所有rtsp连接
-     */
-    @Get("/rtspconns/list")
-    public String rtspconns();
 
     /**
      * 按sessionId查询rtsp会话
diff --git a/ard-work/src/main/java/com/ruoyi/utils/forest/MediaClientV2.java b/ard-work/src/main/java/com/ruoyi/utils/forest/MediaClientV2.java
new file mode 100644
index 0000000..bf83a00
--- /dev/null
+++ b/ard-work/src/main/java/com/ruoyi/utils/forest/MediaClientV2.java
@@ -0,0 +1,100 @@
+package com.ruoyi.utils.forest;
+
+import com.dtflys.forest.annotation.*;
+import com.ruoyi.media.domain.Conf;
+import com.ruoyi.media.domain.Config;
+import com.ruoyi.media.domain.Items;
+
+/**
+ * @Description: mediamtx流媒体客户端
+ * @ClassName: client
+ * @Author: 刘苏义
+ * @Date: 2023年07月06日9:51
+ * @Version: 1.0
+ **/
+@BaseRequest(baseURL = "http://#{mediamtx.host}:9997/v2")
+public interface MediaClientV2 {
+    /**
+     * 增加路径
+     */
+    @Post(url = "/config/paths/add/{name}")
+    public String addPath(@Var("name") String name, @JSONBody Conf body);
+
+    /**
+     * 修改路径
+     */
+    @Post(url = "/config/paths/edit/{name}", async = true)
+    public String editPath(@Var("name") String name, @JSONBody Conf body);
+
+    /**
+     * 移除路径
+     */
+    @Post("/config/paths/remove/{name}")
+    public String removePath(@Var("name") String name);
+
+    /**
+     * 获取路径详情
+     */
+    @Get("/paths/get/{name}")
+    public Items getPathInfo(@Var("name") String name);
+
+    /**
+     * 查询所有路径
+     */
+    @Get("/paths/list")
+    public String paths();
+
+    /**
+     * 查询所有rtsp会话
+     */
+    @Get("/rtspsessions/list")
+    public String rtspsessions();
+
+    /**
+     * 查询所有rtsp连接
+     */
+    @Get("/rtspconns/list")
+    public String rtspconns();
+
+    /**
+     * 按sessionId查询rtsp会话
+     */
+    @Get("/rtspsessions/get/{sessionId}")
+    public String getRtspsessionById(@Var("sessionId") String sessionId);
+
+    /**
+     * 按sessionId查询webrtc会话
+     */
+    @Get("/webrtcsessions/get/{sessionId}")
+    public String getWebrtcsessionById(@Var("sessionId") String sessionId);
+
+    /**
+     * 按sessionId查询rtmp会话
+     */
+    @Get("/rtmpconns/get/{sessionId}")
+    public String getRtmpsessionById(@Var("sessionId") String sessionId);
+
+    /**
+     * 按sessionId删除rtsp会话
+     */
+    @Post("/rtspsessions/kick/{sessionId}")
+    public String kickRtspSessions(@Var("sessionId") String sessionId);
+
+    /**
+     * 按sessionId删除rtmp连接
+     */
+    @Post("/rtmpconns/kick/{sessionId}")
+    public String kickRtmpSessions(@Var("sessionId") String sessionId);
+
+    /**
+     * 按sessionId删除webrtc会话
+     */
+    @Post("/webrtcsessions/kick/{sessionId}")
+    public String kickWebrtcSessions(@Var("sessionId") String sessionId);
+
+    /**
+     * 配置流媒体参数
+     */
+    @Post("/config/set")
+    public String setConfig(@JSONBody Config config);
+}
diff --git a/ard-work/src/main/java/com/ruoyi/utils/tools/ArdTool.java b/ard-work/src/main/java/com/ruoyi/utils/tools/ArdTool.java
index ded00ce..6c3522b 100644
--- a/ard-work/src/main/java/com/ruoyi/utils/tools/ArdTool.java
+++ b/ard-work/src/main/java/com/ruoyi/utils/tools/ArdTool.java
@@ -1,9 +1,7 @@
 package com.ruoyi.utils.tools;
 
-import com.ruoyi.common.core.redis.RedisCache;
 import lombok.extern.slf4j.Slf4j;
 
-import javax.annotation.Resource;
 import java.lang.reflect.Field;
 import java.text.DecimalFormat;
 import java.time.LocalTime;
@@ -121,4 +119,18 @@
         int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
         return new DecimalFormat("#,###.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
     }
+
+    /**
+     * byte数组转字符串
+     * 刘苏义
+     * 2023/10/18 8:42:59
+     * @param byteArray
+     */
+    public static String byteArrayToString(byte[] byteArray) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (byte b : byteArray) {
+            stringBuilder.append(String.valueOf(b));
+        }
+        return stringBuilder.toString();
+    }
 }
diff --git a/ard-work/src/main/resources/templates/preview.html b/ard-work/src/main/resources/templates/preview.html
index 609e256..616b08e 100644
--- a/ard-work/src/main/resources/templates/preview.html
+++ b/ard-work/src/main/resources/templates/preview.html
@@ -101,7 +101,7 @@
             <button class="toggle-button" onclick="changeGrid(7, 7)">7x7</button>
             <button class="toggle-button" onclick="changeGrid(8, 8)">8x8</button>
             <button class="toggle-button" onclick="changeGrid(9, 9)">9x9</button>
-            <input id="videoUrl" type="text" value="http://192.168.1.227:8889/164/" style="width: 250px"/>
+            <input id="videoUrl" type="text" value="" style="width: 250px"/>
         </div>
     </div>
 </div>
@@ -110,6 +110,7 @@
     console.log(RTCRtpReceiver.getCapabilities('video').codecs)
     console.log(RTCRtpReceiver.getCapabilities('audio').codecs)
     //whep操作方法
+    const restartPause = 2000;
     const linkToIceServers = (links) => (
         (links !== null) ? links.split(', ').map((link) => {
             const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
@@ -236,7 +237,7 @@
                     if (res.status !== 201) {
                         throw new Error('bad status code');
                     }
-                   // this.eTag = res.headers.get('ETag');
+                    // this.eTag = res.headers.get('ETag');
                     this.eTag = res.headers.get("ETag") || res.headers.get('E-Tag');
                     return res.text();
                 })
@@ -297,6 +298,7 @@
                     'Content-Type': 'application/trickle-ice-sdpfrag',
                     'If-Match': this.eTag,
                 },
+
                 body: generateSdpFragment(this.offerData, candidates),
             })
                 .then((res) => {
@@ -349,7 +351,7 @@
             chanMap.set("video" + i, videoUrl);
         }
         console.log(chanMap);
-        changeGrid(2, 2);
+        //changeGrid(2, 2);
     }
     //绑定点击事件
     let playMap = new Map();
diff --git a/ard-work/src/main/resources/templates/test.html b/ard-work/src/main/resources/templates/test.html
index 5b3d7d9..8c81faf 100644
--- a/ard-work/src/main/resources/templates/test.html
+++ b/ard-work/src/main/resources/templates/test.html
@@ -136,7 +136,7 @@
     window.onload = function () {
         console.log(RTCRtpReceiver.getCapabilities('video').codecs)
         $.ajax({
-            url: "../hik/list",
+            url: "../cameraSdk/list",
             type: "get",
             success: function (data) {
                 console.log(data);
@@ -144,7 +144,8 @@
                 for (var i = 0; i < arr.length; i++) {
                     console.log(arr[i].id);
                     var camera = {
-                        type: arr[i].gdtype,
+                        name: arr[i].name,
+                        factory: arr[i].factory,
                         ipaddr: arr[i].ip,
                         username: arr[i].username,
                         password: arr[i].password,
@@ -183,125 +184,125 @@
     }
     //云台上下左右
     $("#up").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 2;
         var enable = true;
         commondMethod(url, code, enable);
 
     })
     $("#up").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 2;
         var enable = false;
         commondMethod(url, code, enable);
     })
     $("#down").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 8;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#down").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 8;
         var enable = false;
         commondMethod(url, code, enable);
     })
     $("#left").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 4;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#left").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 4;
         var enable = false;
         commondMethod(url, code, enable);
     })
     $("#right").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 6;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#right").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 6;
         var enable = false;
         commondMethod(url, code, enable);
     })
     //变倍
     $("#controlZoomIn").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 10;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#controlZoomIn").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 10;
         var enable = false;
         commondMethod(url, code, enable);
     })
     $("#controlZoomOut").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 11;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#controlZoomOut").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 11;
         var enable = false;
         commondMethod(url, code, enable);
     })
     //变焦
     $("#controlFocusNear").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 12;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#controlFocusNear").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 12;
         var enable = false;
         commondMethod(url, code, enable);
     })
     $("#controlFocusFar").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 13;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#controlFocusFar").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 13;
         var enable = false;
         commondMethod(url, code, enable);
     })
     //光圈
     $("#controlIrisOpen").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 14;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#controlIrisOpen").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 14;
         var enable = false;
         commondMethod(url, code, enable);
     })
     $("#controlIrisClose").mousedown(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 15;
         var enable = true;
         commondMethod(url, code, enable);
     })
     $("#controlIrisClose").mouseup(function () {
-        var url = "../hik/PTZControlWithSpeed";
+        var url = "../cameraSdk/PTZControlWithSpeed";
         var code = 15;
         var enable = false;
         commondMethod(url, code, enable);
@@ -316,7 +317,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/setPreset",
+            url: "../cameraSdk/setPreset",
             type: "post",
             dataType: "json",
             data: JSON.stringify(opt),
@@ -334,7 +335,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/gotoPreset",
+            url: "../cameraSdk/gotoPreset",
             type: "post",
             dataType: "json",
             data: JSON.stringify(opt),
@@ -352,7 +353,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/getPTZ",
+            url: "../cameraSdk/getPTZ",
             type: "post",
             dataType: "json",
             data: JSON.stringify(opt),
@@ -386,7 +387,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/setPTZ",
+            url: "../cameraSdk/setPTZ",
             type: "post",
             dataType: "json",
             data: JSON.stringify(myEntity),
@@ -414,7 +415,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/setTargetPosition",
+            url: "../cameraSdk/setTargetPosition",
             type: "post",
             dataType: "json",
             data: JSON.stringify(myEntity),
@@ -432,7 +433,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/setZeroPTZ",
+            url: "../cameraSdk/setZeroPTZ",
             type: "post",
             dataType: "json",
             data: JSON.stringify(opt),
@@ -450,7 +451,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/PTZControlWithSpeed",
+            url: "../cameraSdk/PTZControlWithSpeed",
             type: "post",
             dataType: "json",
             data: JSON.stringify(opt),
@@ -473,7 +474,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/defogcfg",
+                url: "../cameraSdk/defogcfg",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optOpen),
@@ -490,7 +491,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/defogcfg",
+                url: "../cameraSdk/defogcfg",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optClose),
@@ -515,7 +516,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/infrarecfg",
+                url: "../cameraSdk/infrarecfg",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optOpen),
@@ -533,7 +534,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/infrarecfg",
+                url: "../cameraSdk/infrarecfg",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optClose),
@@ -557,7 +558,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/focusMode",
+                url: "../cameraSdk/focusMode",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optOpen),
@@ -574,7 +575,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/focusMode",
+                url: "../cameraSdk/focusMode",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optClose),
@@ -593,13 +594,13 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/getFocusPos",
+                url: "../cameraSdk/getFocusPos",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(opt),
                 success: function (datas) {
                     console.log(datas);
-                    $("#focus").val(datas.data.dwFocus);
+                    $("#focus").val(datas.data);
                 }
             })
     })
@@ -617,7 +618,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/heateRpwron",
+                url: "../cameraSdk/heateRpwron",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optOpen),
@@ -634,7 +635,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/heateRpwron",
+                url: "../cameraSdk/heateRpwron",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optClose),
@@ -657,7 +658,7 @@
                     'Accept': 'application/json',
                     'Content-Type': 'application/json'
                 },
-                url: "../hik/cameraDeicing",
+                url: "../cameraSdk/cameraDeicing",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optOpen),
@@ -674,7 +675,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/cameraDeicing",
+                url: "../cameraSdk/cameraDeicing",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optClose),
@@ -693,7 +694,7 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/captureJPEGPicture",
+            url: "../cameraSdk/captureJPEGPicture",
             type: "post",
             dataType: "json",
             data: JSON.stringify(opt),
@@ -712,13 +713,16 @@
                 'Content-Type': 'application/json',
                 'Authorization': token
             },
-            url: "../hik/picCutCate",
+            url: "../cameraSdk/picCutCate",
             type: "post",
             dataType: "json",
             data: JSON.stringify(opt),
             success: function (data) {
                 console.log(data.data);
-                $('#imgContainer').attr('src', data.data);
+                setTimeout(() => {
+                    $('#imgContainer').attr('src', data.data);
+                }, 1000 )
+
             }
         })
     })
@@ -736,7 +740,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/record",
+                url: "../cameraSdk/record",
                 type: "post",
                 dataType: "json",
                 data: JSON.stringify(optOpen),
@@ -753,7 +757,7 @@
                     'Content-Type': 'application/json',
                     'Authorization': token
                 },
-                url: "../hik/record",
+                url: "../cameraSdk/record",
                 dataType: "json",
                 data: JSON.stringify(optClose),
                 type: "post",
@@ -769,7 +773,7 @@
     /*云台公共方法*/
     function commondMethod(url, code, enable) {
         cameraId = $('#select option:selected').val();
-        opt = {"cameraId": cameraId, "chanNo": 1, "speed": 8, "enable": enable, "code": code};
+        opt = {"cameraId": cameraId, "chanNo": 1, "speed": 4, "enable": enable, "code": code};
         $.ajax({
             headers: {
                 'Accept': 'application/json',
@@ -797,9 +801,9 @@
             var cameraId = $('#select option:selected').val();
             let camera = cameraMap.get(cameraId);
             console.log(camera);
-            if (camera.type == "ys") {
+            if (camera.factory == "3") {
                 realViewYs("127.0.0.1", ID, camera.username, camera.password, camera.ipaddr, camera.port);
-            } else if (camera.type == "dh") {
+            } else if (camera.factory == "2") {
                 realViewDh("127.0.0.1", ID, camera.username, camera.password, camera.ipaddr, camera.port);
             } else {
                 realViewHik("127.0.0.1", ID, camera.username, camera.password, camera.ipaddr, camera.port);
diff --git a/lib/mediamtx/LICENSE b/lib/mediamtx/LICENSE
index 50bbbd8..bfbf85a 100644
--- a/lib/mediamtx/LICENSE
+++ b/lib/mediamtx/LICENSE
@@ -19,3 +19,8 @@
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
+
+internal/core/hls.min.js is Copyright (c) Dailymotion and is protected by
+its own license (Apache License, Version 2.0) available at
+
+https://github.com/video-dev/hls.js/blob/master/LICENSE
diff --git a/lib/mediamtx/mediamtx.exe b/lib/mediamtx/mediamtx.exe
index eebaa64..6457d07 100644
--- a/lib/mediamtx/mediamtx.exe
+++ b/lib/mediamtx/mediamtx.exe
Binary files differ
diff --git a/lib/mediamtx/mediamtx.yml b/lib/mediamtx/mediamtx.yml
index 9dfc5b5..53da72c 100644
--- a/lib/mediamtx/mediamtx.yml
+++ b/lib/mediamtx/mediamtx.yml
@@ -1,8 +1,12 @@
+###############################################
+# Global settings
+
+# Settings in this section are applied anywhere.
 
 ###############################################
-# General settings
+# Global settings -> General
 
-# Sets the verbosity of the program; available values are "error", "warn", "info", "debug".
+# Verbosity of the program; available values are "error", "warn", "info", "debug".
 logLevel: info
 # Destinations of log messages; available values are "stdout", "file" and "syslog".
 logDestinations: [stdout]
@@ -40,29 +44,33 @@
 # Enable the HTTP API.
 api: yes
 # Address of the API listener.
-apiAddress: 192.168.1.227:9997
+apiAddress: 112.98.126.2:9997
 
 # Enable Prometheus-compatible metrics.
 metrics: no
 # Address of the metrics listener.
-metricsAddress: 127.0.0.1:9998
+metricsAddress: 112.98.126.2:9998
 
 # Enable pprof-compatible endpoint to monitor performances.
 pprof: no
 # Address of the pprof listener.
-pprofAddress: 127.0.0.1:9999
+pprofAddress: 112.98.126.2:9999
 
 # Command to run when a client connects to the server.
-# Prepend ./ to run an executable in the current folder (example: "./ffmpeg")
 # This is terminated with SIGINT when a client disconnects from the server.
 # The following environment variables are available:
 # * RTSP_PORT: RTSP server port
+# * MTX_CONN_TYPE: connection type
+# * MTX_CONN_ID: connection ID
 runOnConnect:
 # Restart the command if it exits.
 runOnConnectRestart: no
+# Command to run when a client disconnects from the server.
+# Environment variables are the same of runOnConnect.
+runOnDisconnect:
 
 ###############################################
-# RTSP settings
+# Global settings -> RTSP
 
 # Allow publishing and reading streams with the RTSP protocol.
 rtsp: yes
@@ -77,19 +85,19 @@
 # Available values are "no", "strict", "optional".
 encryption: "no"
 # Address of the TCP/RTSP listener. This is needed only when encryption is "no" or "optional".
-rtspAddress: :7554
+rtspAddress: :8554
 # Address of the TCP/TLS/RTSPS listener. This is needed only when encryption is "strict" or "optional".
-rtspsAddress: :7322
+rtspsAddress: :8322
 # Address of the UDP/RTP listener. This is needed only when "udp" is in protocols.
-rtpAddress: :7000
+rtpAddress: :8000
 # Address of the UDP/RTCP listener. This is needed only when "udp" is in protocols.
-rtcpAddress: :7001
+rtcpAddress: :8001
 # IP range of all UDP-multicast listeners. This is needed only when "multicast" is in protocols.
 multicastIPRange: 224.1.0.0/16
 # Port of all UDP-multicast/RTP listeners. This is needed only when "multicast" is in protocols.
-multicastRTPPort: 7002
+multicastRTPPort: 8002
 # Port of all UDP-multicast/RTCP listeners. This is needed only when "multicast" is in protocols.
-multicastRTCPPort: 7003
+multicastRTCPPort: 8003
 # Path to the server key. This is needed only when encryption is "strict" or "optional".
 # This can be generated with:
 # openssl genrsa -out server.key 2048
@@ -102,7 +110,7 @@
 authMethods: [basic]
 
 ###############################################
-# RTMP settings
+# Global settings -> RTMP
 
 # Allow publishing and reading streams with the RTMP protocol.
 rtmp: yes
@@ -122,7 +130,7 @@
 rtmpServerCert: server.crt
 
 ###############################################
-# HLS settings
+# Global settings -> HLS
 
 # Allow reading streams with the HLS protocol.
 hls: no
@@ -178,7 +186,7 @@
 hlsDirectory: ''
 
 ###############################################
-# WebRTC settings
+# Global settings -> WebRTC
 
 # Allow publishing and reading streams with the WebRTC protocol.
 webrtc: yes
@@ -207,27 +215,30 @@
   # needed when server and clients are on different LANs.
   # TURN/TURNS servers are needed when a direct connection between server and
   # clients is not possible. All traffic is routed through them.
-- url: stun:stun.l.google.com:19302
+- url: stun:112.98.126.2:3478
   # if user is "AUTH_SECRET", then authentication is secret based.
   # the secret must be inserted into the password field.
-  username: ''
-  password: ''
+  username: 'admin'
+  password: '123456'
+# List of interfaces that will be used to gather IPs to send
+# to the counterpart to establish a connection.
+webrtcICEInterfaces: []
 # List of public IP addresses that are to be used as a host.
 # This is used typically for servers that are behind 1:1 D-NAT.
-webrtcICEHostNAT1To1IPs: [192.168.1.227]
+webrtcICEHostNAT1To1IPs: [112.98.126.2]
 # Address of a ICE UDP listener in format host:port.
 # If filled, ICE traffic will pass through a single UDP port,
 # allowing the deployment of the server inside a container or behind a NAT.
-webrtcICEUDPMuxAddress: 192.168.1.227:8189
+webrtcICEUDPMuxAddress:
 # Address of a ICE TCP listener in format host:port.
 # If filled, ICE traffic will pass through a single TCP port,
 # allowing the deployment of the server inside a container or behind a NAT.
 # Using this setting forces usage of the TCP protocol, which is not
 # optimal for WebRTC.
-webrtcICETCPMuxAddress: 192.168.1.227:8189
+webrtcICETCPMuxAddress: 112.98.126.2:1234
 
 ###############################################
-# SRT settings
+# Global settings -> SRT
 
 # Allow publishing and reading streams with the SRT protocol.
 srt: yes
@@ -235,246 +246,311 @@
 srtAddress: :8890
 
 ###############################################
+# Default path settings
+
+# Settings in "pathDefaults" are applied anywhere,
+# unless they are overridden in "paths".
+pathDefaults:
+
+  ###############################################
+  # Default path settings -> General
+
+  # Source of the stream. This can be:
+  # * publisher -> the stream is provided by a RTSP, RTMP, WebRTC or SRT client
+  # * rtsp://existing-url -> the stream is pulled from another RTSP server / camera
+  # * rtsps://existing-url -> the stream is pulled from another RTSP server / camera with RTSPS
+  # * rtmp://existing-url -> the stream is pulled from another RTMP server / camera
+  # * rtmps://existing-url -> the stream is pulled from another RTMP server / camera with RTMPS
+  # * http://existing-url/stream.m3u8 -> the stream is pulled from another HLS server / camera
+  # * https://existing-url/stream.m3u8 -> the stream is pulled from another HLS server / camera with HTTPS
+  # * udp://ip:port -> the stream is pulled with UDP, by listening on the specified IP and port
+  # * srt://existing-url -> the stream is pulled from another SRT server / camera
+  # * whep://existing-url -> the stream is pulled from another WebRTC server / camera
+  # * wheps://existing-url -> the stream is pulled from another WebRTC server / camera with HTTPS
+  # * redirect -> the stream is provided by another path or server
+  # * rpiCamera -> the stream is provided by a Raspberry Pi Camera
+  source: publisher
+  # If the source is a URL, and the source certificate is self-signed
+  # or invalid, you can provide the fingerprint of the certificate in order to
+  # validate it anyway. It can be obtained by running:
+  # openssl s_client -connect source_ip:source_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
+  # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
+  sourceFingerprint:
+  # If the source is a URL, it will be pulled only when at least
+  # one reader is connected, saving bandwidth.
+  sourceOnDemand: no
+  # If sourceOnDemand is "yes", readers will be put on hold until the source is
+  # ready or until this amount of time has passed.
+  sourceOnDemandStartTimeout: 10s
+  # If sourceOnDemand is "yes", the source will be closed when there are no
+  # readers connected and this amount of time has passed.
+  sourceOnDemandCloseAfter: 10s
+  # Maximum number of readers. Zero means no limit.
+  maxReaders: 0
+  # SRT encryption passphrase require to read from this path
+  srtReadPassphrase:
+
+  ###############################################
+  # Default path settings -> Recording
+
+  # Record streams to disk.
+  record: no
+  # Path of recording segments.
+  # Extension is added automatically.
+  # Available variables are %path (path name), %Y %m %d %H %M %S %f (time in strftime format)
+  recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f
+  # Format of recorded segments.
+  # Available formats are "fmp4" (fragmented MP4) and "mpegts" (MPEG-TS).
+  recordFormat: fmp4
+  # fMP4 segments are concatenation of small MP4 files (parts), each with this duration.
+  # MPEG-TS segments are concatenation of 188-bytes packets, flushed to disk with this period.
+  # When a system failure occurs, the last part gets lost.
+  # Therefore, the part duration is equal to the RPO (recovery point objective).
+  recordPartDuration: 100ms
+  # Minimum duration of each segment.
+  recordSegmentDuration: 1h
+  # Delete segments after this timespan.
+  # Set to 0s to disable automatic deletion.
+  recordDeleteAfter: 24h
+
+  ###############################################
+  # Default path settings -> Authentication
+
+  # Username required to publish.
+  # SHA256-hashed values can be inserted with the "sha256:" prefix.
+  publishUser:
+  # Password required to publish.
+  # SHA256-hashed values can be inserted with the "sha256:" prefix.
+  publishPass:
+  # IPs or networks (x.x.x.x/24) allowed to publish.
+  publishIPs: []
+
+  # Username required to read.
+  # SHA256-hashed values can be inserted with the "sha256:" prefix.
+  readUser:
+  # password required to read.
+  # SHA256-hashed values can be inserted with the "sha256:" prefix.
+  readPass:
+  # IPs or networks (x.x.x.x/24) allowed to read.
+  readIPs: []
+
+  ###############################################
+  # Default path settings -> Publisher source (when source is "publisher")
+
+  # allow another client to disconnect the current publisher and publish in its place.
+  overridePublisher: yes
+  # if no one is publishing, redirect readers to this path.
+  # It can be can be a relative path (i.e. /otherstream) or an absolute RTSP URL.
+  fallback:
+  # SRT encryption passphrase required to publish to this path
+  srtPublishPassphrase:
+
+  ###############################################
+  # Default path settings -> RTSP source (when source is a RTSP or a RTSPS URL)
+
+  # protocol used to pull the stream. available values are "automatic", "udp", "multicast", "tcp".
+  sourceProtocol: automatic
+  # support sources that don't provide server ports or use random server ports. This is a security issue
+  # and must be used only when interacting with sources that require it.
+  sourceAnyPortEnable: no
+  # range header to send to the source, in order to start streaming from the specified offset.
+  # available values:
+  # * clock: Absolute time
+  # * npt: Normal Play Time
+  # * smpte: SMPTE timestamps relative to the start of the recording
+  rtspRangeType:
+  # available values:
+  # * clock: UTC ISO 8601 combined date and time string, e.g. 20230812T120000Z
+  # * npt: duration such as "300ms", "1.5m" or "2h45m", valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h"
+  # * smpte: duration such as "300ms", "1.5m" or "2h45m", valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h"
+  rtspRangeStart:
+
+  ###############################################
+  # Default path settings -> Redirect source (when source is "redirect")
+
+  # RTSP URL which clients will be redirected to.
+  sourceRedirect:
+
+  ###############################################
+  # Default path settings -> Raspberry Pi Camera source (when source is "rpiCamera")
+
+  # ID of the camera
+  rpiCameraCamID: 0
+  # width of frames
+  rpiCameraWidth: 1920
+  # height of frames
+  rpiCameraHeight: 1080
+  # flip horizontally
+  rpiCameraHFlip: false
+  # flip vertically
+  rpiCameraVFlip: false
+  # brightness [-1, 1]
+  rpiCameraBrightness: 0
+  # contrast [0, 16]
+  rpiCameraContrast: 1
+  # saturation [0, 16]
+  rpiCameraSaturation: 1
+  # sharpness [0, 16]
+  rpiCameraSharpness: 1
+  # exposure mode.
+  # values: normal, short, long, custom
+  rpiCameraExposure: normal
+  # auto-white-balance mode.
+  # values: auto, incandescent, tungsten, fluorescent, indoor, daylight, cloudy, custom
+  rpiCameraAWB: auto
+  # denoise operating mode.
+  # values: off, cdn_off, cdn_fast, cdn_hq
+  rpiCameraDenoise: "off"
+  # fixed shutter speed, in microseconds.
+  rpiCameraShutter: 0
+  # metering mode of the AEC/AGC algorithm.
+  # values: centre, spot, matrix, custom
+  rpiCameraMetering: centre
+  # fixed gain
+  rpiCameraGain: 0
+  # EV compensation of the image [-10, 10]
+  rpiCameraEV: 0
+  # Region of interest, in format x,y,width,height
+  rpiCameraROI:
+  # whether to enable HDR on Raspberry Camera 3.
+  rpiCameraHDR: false
+  # tuning file
+  rpiCameraTuningFile:
+  # sensor mode, in format [width]:[height]:[bit-depth]:[packing]
+  # bit-depth and packing are optional.
+  rpiCameraMode:
+  # frames per second
+  rpiCameraFPS: 30
+  # period between IDR frames
+  rpiCameraIDRPeriod: 60
+  # bitrate
+  rpiCameraBitrate: 1000000
+  # H264 profile
+  rpiCameraProfile: main
+  # H264 level
+  rpiCameraLevel: '4.1'
+  # Autofocus mode
+  # values: auto, manual, continuous
+  rpiCameraAfMode: auto
+  # Autofocus range
+  # values: normal, macro, full
+  rpiCameraAfRange: normal
+  # Autofocus speed
+  # values: normal, fast
+  rpiCameraAfSpeed: normal
+  # Lens position (for manual autofocus only), will be set to focus to a specific distance
+  # calculated by the following formula: d = 1 / value
+  # Examples: 0 moves the lens to infinity.
+  #           0.5 moves the lens to focus on objects 2m away.
+  #           2 moves the lens to focus on objects 50cm away.
+  rpiCameraLensPosition: 0.0
+  # Specifies the autofocus window, in the form x,y,width,height where the coordinates
+  # are given as a proportion of the entire image.
+  rpiCameraAfWindow:
+  # enables printing text on each frame.
+  rpiCameraTextOverlayEnable: false
+  # text that is printed on each frame.
+  # format is the one of the strftime() function.
+  rpiCameraTextOverlay: '%Y-%m-%d %H:%M:%S - MediaMTX'
+
+  ###############################################
+  # Default path settings -> Hooks
+
+  # Command to run when this path is initialized.
+  # This can be used to publish a stream when the server is launched.
+  # This is terminated with SIGINT when the program closes.
+  # The following environment variables are available:
+  # * MTX_PATH: path name
+  # * RTSP_PORT: RTSP server port
+  # * G1, G2, ...: regular expression groups, if path name is
+  #   a regular expression.
+  runOnInit:
+  # Restart the command if it exits.
+  runOnInitRestart: no
+
+  # Command to run when this path is requested by a reader.
+  # This can be used to publish a stream on demand.
+  # This is terminated with SIGINT when the path is not requested anymore.
+  # The following environment variables are available:
+  # * MTX_PATH: path name
+  # * RTSP_PORT: RTSP server port
+  # * G1, G2, ...: regular expression groups, if path name is
+  #   a regular expression.
+  runOnDemand:
+  # Restart the command if it exits.
+  runOnDemandRestart: no
+  # Readers will be put on hold until the runOnDemand command starts publishing
+  # or until this amount of time has passed.
+  runOnDemandStartTimeout: 10s
+  # The command will be closed when there are no
+  # readers connected and this amount of time has passed.
+  runOnDemandCloseAfter: 10s
+
+  # Command to run when the stream is ready to be read, whenever it is
+  # published by a client or pulled from a server / camera.
+  # This is terminated with SIGINT when the stream is not ready anymore.
+  # The following environment variables are available:
+  # * MTX_PATH: path name
+  # * RTSP_PORT: RTSP server port
+  # * G1, G2, ...: regular expression groups, if path name is
+  #   a regular expression.
+  # * MTX_SOURCE_TYPE: source type
+  # * MTX_SOURCE_ID: source ID
+  runOnReady:
+  # Restart the command if it exits.
+  runOnReadyRestart: no
+  # Command to run when the stream is not available anymore.
+  # Environment variables are the same of runOnReady.
+  runOnNotReady:
+
+  # Command to run when a client starts reading.
+  # This is terminated with SIGINT when a client stops reading.
+  # The following environment variables are available:
+  # * MTX_PATH: path name
+  # * RTSP_PORT: RTSP server port
+  # * G1, G2, ...: regular expression groups, if path name is
+  #   a regular expression.
+  # * MTX_READER_TYPE: reader type
+  # * MTX_READER_ID: reader ID
+  runOnRead:
+  # Restart the command if it exits.
+  runOnReadRestart: no
+  # Command to run when a client stops reading.
+  # Environment variables are the same of runOnRead.
+  runOnUnread:
+
+  # Command to run when a recording segment is created.
+  # The following environment variables are available:
+  # * MTX_PATH: path name
+  # * RTSP_PORT: RTSP server port
+  # * G1, G2, ...: regular expression groups, if path name is
+  #   a regular expression.
+  # * MTX_SEGMENT_PATH: segment file path
+  runOnRecordSegmentCreate:
+
+  # Command to run when a recording segment is complete.
+  # The following environment variables are available:
+  # * MTX_PATH: path name
+  # * RTSP_PORT: RTSP server port
+  # * G1, G2, ...: regular expression groups, if path name is
+  #   a regular expression.
+  # * MTX_SEGMENT_PATH: segment file path
+  runOnRecordSegmentComplete:
+
+###############################################
 # Path settings
 
-# These settings are path-dependent, and the map key is the name of the path.
+# Settings in "paths" are applied to specific paths, and the map key
+# is the name of the path.
+# Any setting in "pathDefaults" can be overridden here.
 # It's possible to use regular expressions by using a tilde as prefix,
 # for example "~^(test1|test2)$" will match both "test1" and "test2",
 # for example "~^prefix" will match all paths that start with "prefix".
-# Settings under the path "all" are applied to all paths that do not match
-# another entry.
 paths:
-  all:
-    ###############################################
-    # General path settings
+  # example:
+  # my_camera:
+  #   source: rtsp://my_camera
 
-    # Source of the stream. This can be:
-    # * publisher -> the stream is provided by a RTSP, RTMP, WebRTC or SRT client
-    # * rtsp://existing-url -> the stream is pulled from another RTSP server / camera
-    # * rtsps://existing-url -> the stream is pulled from another RTSP server / camera with RTSPS
-    # * rtmp://existing-url -> the stream is pulled from another RTMP server / camera
-    # * rtmps://existing-url -> the stream is pulled from another RTMP server / camera with RTMPS
-    # * http://existing-url/stream.m3u8 -> the stream is pulled from another HLS server / camera
-    # * https://existing-url/stream.m3u8 -> the stream is pulled from another HLS server / camera with HTTPS
-    # * udp://ip:port -> the stream is pulled with UDP, by listening on the specified IP and port
-    # * srt://existing-url -> the stream is pulled from another SRT server / camera
-    # * whep://existing-url -> the stream is pulled from another WebRTC server / camera
-    # * wheps://existing-url -> the stream is pulled from another WebRTC server / camera with HTTPS
-    # * redirect -> the stream is provided by another path or server
-    # * rpiCamera -> the stream is provided by a Raspberry Pi Camera
-    source: publisher
-    # If the source is a URL, and the source certificate is self-signed
-    # or invalid, you can provide the fingerprint of the certificate in order to
-    # validate it anyway. It can be obtained by running:
-    # openssl s_client -connect source_ip:source_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
-    # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
-    sourceFingerprint:
-    # If the source is a URL, it will be pulled only when at least
-    # one reader is connected, saving bandwidth.
-    sourceOnDemand: no
-    # If sourceOnDemand is "yes", readers will be put on hold until the source is
-    # ready or until this amount of time has passed.
-    sourceOnDemandStartTimeout: 10s
-    # If sourceOnDemand is "yes", the source will be closed when there are no
-    # readers connected and this amount of time has passed.
-    sourceOnDemandCloseAfter: 10s
-    # Maximum number of readers. Zero means no limit.
-    maxReaders: 0
-
-    ###############################################
-    # Authentication path settings
-
-    # Username required to publish.
-    # SHA256-hashed values can be inserted with the "sha256:" prefix.
-    publishUser:
-    # Password required to publish.
-    # SHA256-hashed values can be inserted with the "sha256:" prefix.
-    publishPass:
-    # IPs or networks (x.x.x.x/24) allowed to publish.
-    publishIPs: []
-
-    # Username required to read.
-    # SHA256-hashed values can be inserted with the "sha256:" prefix.
-    readUser:
-    # password required to read.
-    # SHA256-hashed values can be inserted with the "sha256:" prefix.
-    readPass:
-    # IPs or networks (x.x.x.x/24) allowed to read.
-    readIPs: []
-
-    ###############################################
-    # Publisher path settings (when source is "publisher")
-
-    # allow another client to disconnect the current publisher and publish in its place.
-    overridePublisher: yes
-    # if no one is publishing, redirect readers to this path.
-    # It can be can be a relative path  (i.e. /otherstream) or an absolute RTSP URL.
-    fallback:
-
-    ###############################################
-    # RTSP path settings (when source is a RTSP or a RTSPS URL)
-
-    # protocol used to pull the stream. available values are "automatic", "udp", "multicast", "tcp".
-    sourceProtocol: automatic
-    # support sources that don't provide server ports or use random server ports. This is a security issue
-    # and must be used only when interacting with sources that require it.
-    sourceAnyPortEnable: no
-    # range header to send to the source, in order to start streaming from the specified offset.
-    # available values:
-    # * clock: Absolute time
-    # * npt: Normal Play Time
-    # * smpte: SMPTE timestamps relative to the start of the recording
-    rtspRangeType:
-    # available values:
-    # * clock: UTC ISO 8601 combined date and time string, e.g. 20230812T120000Z
-    # * npt: duration such as "300ms", "1.5m" or "2h45m", valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h"
-    # * smpte: duration such as "300ms", "1.5m" or "2h45m", valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h"
-    rtspRangeStart:
-
-    ###############################################
-    # Redirect path settings (when source is "redirect")
-
-    # RTSP URL which clients will be redirected to.
-    sourceRedirect:
-
-    ###############################################
-    # Raspberry Pi Camera path settings (when source is "rpiCamera")
-
-    # ID of the camera
-    rpiCameraCamID: 0
-    # width of frames
-    rpiCameraWidth: 1920
-    # height of frames
-    rpiCameraHeight: 1080
-    # flip horizontally
-    rpiCameraHFlip: false
-    # flip vertically
-    rpiCameraVFlip: false
-    # brightness [-1, 1]
-    rpiCameraBrightness: 0
-    # contrast [0, 16]
-    rpiCameraContrast: 1
-    # saturation [0, 16]
-    rpiCameraSaturation: 1
-    # sharpness [0, 16]
-    rpiCameraSharpness: 1
-    # exposure mode.
-    # values: normal, short, long, custom
-    rpiCameraExposure: normal
-    # auto-white-balance mode.
-    # values: auto, incandescent, tungsten, fluorescent, indoor, daylight, cloudy, custom
-    rpiCameraAWB: auto
-    # denoise operating mode.
-    # values: off, cdn_off, cdn_fast, cdn_hq
-    rpiCameraDenoise: "off"
-    # fixed shutter speed, in microseconds.
-    rpiCameraShutter: 0
-    # metering mode of the AEC/AGC algorithm.
-    # values: centre, spot, matrix, custom
-    rpiCameraMetering: centre
-    # fixed gain
-    rpiCameraGain: 0
-    # EV compensation of the image [-10, 10]
-    rpiCameraEV: 0
-    # Region of interest, in format x,y,width,height
-    rpiCameraROI:
-    # whether to enable HDR on Raspberry Camera 3.
-    rpiCameraHDR: false
-    # tuning file
-    rpiCameraTuningFile:
-    # sensor mode, in format [width]:[height]:[bit-depth]:[packing]
-    # bit-depth and packing are optional.
-    rpiCameraMode:
-    # frames per second
-    rpiCameraFPS: 30
-    # period between IDR frames
-    rpiCameraIDRPeriod: 60
-    # bitrate
-    rpiCameraBitrate: 1000000
-    # H264 profile
-    rpiCameraProfile: main
-    # H264 level
-    rpiCameraLevel: '4.1'
-    # Autofocus mode
-    # values: auto, manual, continuous
-    rpiCameraAfMode: auto
-    # Autofocus range
-    # values: normal, macro, full
-    rpiCameraAfRange: normal
-    # Autofocus speed
-    # values: normal, fast
-    rpiCameraAfSpeed: normal
-    # Lens position (for manual autofocus only), will be set to focus to a specific distance
-    # calculated by the following formula: d = 1 / value
-    # Examples: 0 moves the lens to infinity.
-    #           0.5 moves the lens to focus on objects 2m away.
-    #           2 moves the lens to focus on objects 50cm away.
-    rpiCameraLensPosition: 0.0
-    # Specifies the autofocus window, in the form x,y,width,height where the coordinates
-    # are given as a proportion of the entire image.
-    rpiCameraAfWindow:
-    # enables printing text on each frame.
-    rpiCameraTextOverlayEnable: false
-    # text that is printed on each frame.
-    # format is the one of the strftime() function.
-    rpiCameraTextOverlay: '%Y-%m-%d %H:%M:%S - MediaMTX'
-
-    ###############################################
-    # External commands path settings
-
-    # Command to run when this path is initialized.
-    # This can be used to publish a stream and keep it always opened.
-    # Prepend ./ to run an executable in the current folder (example: "./ffmpeg")
-    # This is terminated with SIGINT when the program closes.
-    # The following environment variables are available:
-    # * MTX_PATH: path name
-    # * RTSP_PORT: RTSP server port
-    # * G1, G2, ...: regular expression groups, if path name is
-    #   a regular expression.
-    runOnInit:
-    # Restart the command if it exits.
-    runOnInitRestart: no
-
-    # Command to run when this path is requested.
-    # This can be used to publish a stream on demand.
-    # Prepend ./ to run an executable in the current folder (example: "./ffmpeg")
-    # This is terminated with SIGINT when the path is not requested anymore.
-    # The following environment variables are available:
-    # * MTX_PATH: path name
-    # * RTSP_PORT: RTSP server port
-    # * G1, G2, ...: regular expression groups, if path name is
-    #   a regular expression.
-    runOnDemand:
-    # Restart the command if it exits.
-    runOnDemandRestart: no
-    # Readers will be put on hold until the runOnDemand command starts publishing
-    # or until this amount of time has passed.
-    runOnDemandStartTimeout: 10s
-    # The command will be closed when there are no
-    # readers connected and this amount of time has passed.
-    runOnDemandCloseAfter: 10s
-
-    # Command to run when the stream is ready to be read, whether it is
-    # published by a client or pulled from a server / camera.
-    # Prepend ./ to run an executable in the current folder (example: "./ffmpeg")
-    # This is terminated with SIGINT when the stream is not ready anymore.
-    # The following environment variables are available:
-    # * MTX_PATH: path name
-    # * RTSP_PORT: RTSP server port
-    # * G1, G2, ...: regular expression groups, if path name is
-    #   a regular expression.
-    runOnReady:
-    # Restart the command if it exits.
-    runOnReadyRestart: no
-
-    # Command to run when a clients starts reading.
-    # Prepend ./ to run an executable in the current folder (example: "./ffmpeg")
-    # This is terminated with SIGINT when a client stops reading.
-    # The following environment variables are available:
-    # * MTX_PATH: path name
-    # * RTSP_PORT: RTSP server port
-    # * G1, G2, ...: regular expression groups, if path name is
-    #   a regular expression.
-    runOnRead:
-    # Restart the command if it exits.
-    runOnReadRestart: no
+  # Settings under path "all_others" are applied to all paths that
+  # do not match another entry.
+  all_others:
diff --git a/ruoyi-admin/src/main/resources/logback.xml b/ruoyi-admin/src/main/resources/logback.xml
index 4fa36cf..fe75824 100644
--- a/ruoyi-admin/src/main/resources/logback.xml
+++ b/ruoyi-admin/src/main/resources/logback.xml
@@ -107,6 +107,19 @@
             <pattern>${log.pattern}</pattern>
         </encoder>
     </appender>
+    <!--dhSdk日志输出-->
+    <appender name="sdk" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/sdk.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!--按天回滚daily-->
+            <fileNamePattern>${log.path}/sdk.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!--日志最大的历史60天-->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
     <!--minio日志输出-->
     <appender name="minio" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <file>${log.path}/minio.log</file>
@@ -262,6 +275,10 @@
     <logger name="dhSdk" level="INFO">
         <appender-ref ref="dhSdk"/>
     </logger>
+    <!--sdk日志-->
+    <logger name="sdk" level="INFO">
+        <appender-ref ref="sdk"/>
+    </logger>
     <!--mqtt日志-->
     <logger name="mqtt" level="INFO">
         <appender-ref ref="mqtt"/>
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/SdkOperateAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/SdkOperateAspect.java
index 32d77f4..bf0718e 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/SdkOperateAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/SdkOperateAspect.java
@@ -29,7 +29,7 @@
  */
 @Aspect
 @Component
-@Slf4j(topic = "hikSdk")
+@Slf4j(topic = "sdk")
 public class SdkOperateAspect {
 
     @Resource
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java
index b9d9170..559f8cd 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java
@@ -9,11 +9,14 @@
 import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.device.camera.domain.ArdCameras;
 import com.ruoyi.device.camera.domain.CameraCmd;
+import com.ruoyi.device.camera.service.ICameraSdkService;
 import com.ruoyi.device.hiksdk.common.GlobalVariable;
 import com.ruoyi.device.hiksdk.service.IHikClientService;
 import com.ruoyi.utils.websocket.util.WebSocketUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
 import java.util.*;
 import static com.ruoyi.utils.websocket.util.WebSocketUtils.ONLINE_USER_SESSIONS;
 
@@ -28,6 +31,12 @@
 @Slf4j
 public class PushTask {
 
+    @Resource
+    RedisCache redisCache;
+    @Resource
+    ICameraSdkService cameraSdkService;
+    @Resource
+    IGlobalAlarmService globalAlarmService;
     /**
      * @描述 定时推送所有报警的点位数量
      * @参数 []
@@ -38,7 +47,6 @@
      */
     public void globalAlarmCountPush() {
         try {
-            IGlobalAlarmService globalAlarmService = SpringUtils.getBean(IGlobalAlarmService.class);
             Map<String, Object> stringIntegerMap = globalAlarmService.selectAlarmLogsCount();
             if (ONLINE_USER_SESSIONS.size() > 0) {
                 WebSocketUtils.sendMessageAll(stringIntegerMap);
@@ -59,8 +67,6 @@
      */
     public void ptzPush() {
         try {
-            RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
-            IHikClientService hikClientService = SpringUtils.getBean(IHikClientService.class);
             List<Map<String, Object>> list = new ArrayList<>();
             List<Object> Objects = redisCache.getListKey(CacheConstants.CAMERA_LIST_KEY);
             if (Objects.size() > 0) {
@@ -70,7 +76,6 @@
                     {
                         continue;
                     }
-                    //推送大光电
                     if(!"1".equals(camera.getGdtype()))
                     {
                         continue;
@@ -80,12 +85,12 @@
                     cmd.setChanNo(1);
                     cmd.setOperator(camera.getOperatorId());
                     //推送在线的相机
-                    boolean onLine = hikClientService.isOnLine(cmd);
+                    boolean onLine = cameraSdkService.isOnLine(cmd);
                     if(!onLine)
                     {
                         continue;
                     }
-                    Map<String, Object> ptz = hikClientService.getGisInfo(cmd);
+                    Map<String, Object> ptz = cameraSdkService.getGisInfo(cmd);
                     if (StringUtils.isNull(ptz)) {
                         continue;
                     }
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java
index c2fee6a..ad26400 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java
@@ -6,6 +6,7 @@
 import com.ruoyi.device.camera.domain.CameraCmd;
 import com.ruoyi.device.camera.service.IArdCamerasService;
 import com.ruoyi.device.channel.domain.ArdChannel;
+import com.ruoyi.device.dhsdk.service.IDhClientService;
 import com.ruoyi.device.hiksdk.service.IHikClientService;
 import com.ruoyi.media.domain.Items;
 import com.ruoyi.media.domain.JsonsRoot;
@@ -37,7 +38,9 @@
     @Resource
     IArdCamerasService iArdCamerasService;
     @Resource
-    IHikClientService iHikClientService;
+    IHikClientService hikClientService;
+    @Resource
+    IDhClientService dhClientService;
     @Resource
     IVtduService vtduService;
     @Resource
@@ -50,15 +53,20 @@
      */
     public void cameraState() {
         try {
-            ArdCameras ardCamera = new ArdCameras();
-            ardCamera.setFactory("1");
+           ArdCameras ardCamera = new ArdCameras();
+            //调用查询方法
             List<ArdCameras> ardCameras = iArdCamerasService.selectArdCamerasListNoDataScope(ardCamera);
             for (ArdCameras camera : ardCameras) {
                 CameraCmd cmd = new CameraCmd();
                 cmd.setCameraId(camera.getId());
-                boolean onLineNew = iHikClientService.isOnLine(cmd);//相机实时状态
-                boolean onLineOld = "1".equals(camera.getState());//相机历史状态
-                //当状态发生变化时,更新实时状态
+                boolean onLineNew = false;
+                // 判断是1还是2
+                if (camera.getFactory().equals("1")) {
+                    onLineNew = hikClientService.isOnLine(cmd);
+                } else if (camera.getFactory().equals("2")) {
+                    onLineNew = dhClientService.isOnLine(cmd);
+                }
+                boolean onLineOld = "1".equals(camera.getState());
                 if (onLineNew != onLineOld) {
                     if (onLineNew) {
                         camera.setState("1");
@@ -67,7 +75,6 @@
                     }
                     iArdCamerasService.updateArdCameras(camera);
                 }
-
             }
         } catch (Exception ex) {
             log.error("同步相机在线状态异常:" + ex.getMessage());
@@ -107,10 +114,11 @@
      * 2023/10/13 14:13:53
      */
     public void vtdu() {
-        List<String> nameList = mediaService.getNameList();
+
         List<Vtdu> vtdus = vtduService.selectVtduList(new Vtdu());
         for (Vtdu vtdu : vtdus) {
-            if (!nameList.contains(vtdu.getName())) {
+            boolean nameExist = mediaService.checkNameExist(vtdu.getName());
+            if (!nameExist) {
                 mediaService.addPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode());
             }
         }

--
Gitblit v1.9.3