From d353fdce7cb957aa0f5d9d51d0ad4205c96e156c Mon Sep 17 00:00:00 2001 From: ‘liusuyi’ <1951119284@qq.com> Date: 星期六, 21 十月 2023 11:57:12 +0800 Subject: [PATCH] 1、流媒体升级1.2.0,修改部分forest接口 2、登录设备判断编码自动配置转码 3、增加sdk聚焦模式切换 4、增加sdk视场角获取并定时上传 --- ard-work/src/main/java/com/ruoyi/device/dhsdk/service/IDhClientService.java | 8 ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java | 3 ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java | 4 ard-work/src/main/java/com/ruoyi/device/dhsdk/module/ConfigModule.java | 33 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/media/service/impl/VtduServiceImpl.java | 20 lib/mediamtx/mediamtx.exe | 0 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java | 17 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/domain/CameraCmd.java | 10 ard-work/src/main/java/com/ruoyi/device/dhsdk/service/impl/DhClientServiceImpl.java | 101 ++ ard-work/src/main/java/com/ruoyi/device/camera/controller/CameraSdkController.java | 3 ard-work/src/main/java/com/ruoyi/device/hiksdk/service/IHikClientService.java | 1 ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java | 65 ++ ard-work/src/main/resources/templates/preview.html | 6 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 | 1 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 | 121 +-- ard-work/src/main/java/com/ruoyi/device/hiksdk/service/impl/HikClientServiceImpl.java | 11 ruoyi-admin/src/main/resources/logback.xml | 17 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/SdkOperateAspect.java | 2 ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/LoginResultCallBack.java | 2 29 files changed, 1,301 insertions(+), 569 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 d67db60..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 @@ -47,6 +47,7 @@ IArdAlarmExternalService ardAlarmExternalService; @Resource IArdAlarmAccessService ardAlarmAccessService; + public void processTask(GuideTask guideTask) { try { CameraCmd cmd = new CameraCmd(); 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 186424c..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 @@ -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,7 +329,7 @@ @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()); 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/impl/CameraSdkServiceImpl.java b/ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java index 00fb04a..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 @@ -315,7 +315,7 @@ if (factory.equals("1")) { result = hikClientService.getFocusMode(cmd); } else if (factory.equals("2")) { - + result = dhClientService.getFocusMode(cmd); } } } catch (Exception ex) { @@ -659,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/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 6e99ee6..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/module/ConfigModule.java b/ard-work/src/main/java/com/ruoyi/device/dhsdk/module/ConfigModule.java index cf30284..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 @@ -32,6 +32,21 @@ } /** + * 鏌ヨ杩滅▼璁惧鐘舵�� + */ + 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 鐧婚檰鍙ユ焺 @@ -69,7 +84,7 @@ 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); + boolean bRet = netsdk.CLIENT_QueryNewSystemInfo(hLoginHandle, strCmd, nChn, strBuffer, cmdObject.size(), error, 3000); if (bRet) { cmdObject.read(); } else { @@ -78,7 +93,20 @@ } 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; + } /** * 璁剧疆鍗曚釜閰嶇疆 * @@ -112,4 +140,5 @@ return result; } + } 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 7c9fd83..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 @@ -55,8 +55,12 @@ boolean gotoPreset(CameraCmd cmd); //璁剧疆棰勭疆浣� boolean setPreset(CameraCmd cmd); - //鑱氱劍妯″紡 + + //璁剧疆鑱氱劍妯″紡 boolean controlFocusMode(CameraCmd cmd); + //鑾峰彇鑱氱劍妯″紡 + String getFocusMode(CameraCmd cmd); + //閫忛浘 boolean controlDefogcfg(CameraCmd cmd); //绾㈠ @@ -67,4 +71,6 @@ 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 ed12a00..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,31 +3,25 @@ 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_FOCUS_LIMIT_SELECT_MODE; 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.lib.structure.NET_ENCODE_VIDEO_INFO; +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.media.service.impl.VtduServiceImpl; import com.ruoyi.utils.gis.GisUtil; import com.ruoyi.utils.minio.MinioUtil; -import com.ruoyi.utils.tools.ArdTool; import com.sun.jna.Pointer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -150,11 +144,18 @@ 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.setIsCode("0");//榛樿涓嶈浆鐮� vtdu.setMode("1");//榛樿CPU杞В鐮� vtdu.setCameraId(camera.getId()); vtduService.insertVtdu(vtdu); @@ -312,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); @@ -648,10 +650,12 @@ 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 = 1;//鑱氱劍鏋侀檺Manual + 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 = 0;//鑱氱劍鏋侀檺Auto + cfg_video_in_focus.stVideoInFocusUnit[i].emFocusMode = 1;//鑱氱劍鏋侀檺Auto + log.debug("褰撳墠涓鸿嚜鍔ㄨ仛鐒︽ā寮�"); } } cfg_video_in_focus.nChannelIndex = chanNo - 1; @@ -666,6 +670,49 @@ } } + @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) { @@ -677,9 +724,9 @@ } LLong loginId = (LLong) GlobalVariable.loginMap.get(cameraId); try { - EM_NEW_CONFIG config = EM_NEW_CONFIG.CFG_CMD_VIDEOINDEFOG; + 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, config.getValue(), null); + boolean bool = ConfigModule.SetDevConfig(loginId, chanNo - 1, command, null); if (!bool) { log.error("鎺у埗澶辫触,璇风◢鍚庨噸璇�" + getErrorCodePrint()); } @@ -836,6 +883,32 @@ 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; + } + // 璁惧鏂嚎鍥炶皟: 褰撹澶囧嚭鐜版柇绾挎椂锛孲DK浼氳皟鐢ㄨ鍑芥暟 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/sdk/LoginResultCallBack.java b/ard-work/src/main/java/com/ruoyi/device/hiksdk/sdk/LoginResultCallBack.java index 5c7bcf1..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; 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 a5606ed..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 @@ -84,6 +84,7 @@ //鑾峰彇ptz鑼冨洿 Map<String, Object> getPtzScope(CameraCmd cmd); + //璁剧疆ptz boolean setPtz(CameraCmd cmd); //璁剧疆闆舵柟浣嶈 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 b937b71..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 @@ -25,7 +25,9 @@ import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; + import java.util.Base64; import javax.annotation.Resource; import java.io.*; @@ -109,6 +111,7 @@ * @鍒涘缓鏃堕棿 2023/1/17 16:12 * @淇敼浜哄拰鍏跺畠淇℃伅 */ + @Async public void syncLogin(ArdCameras camera) { // 鍒濆鍖� if (!hCNetSDK.NET_DVR_Init()) { @@ -188,7 +191,13 @@ vtdu = new Vtdu(); vtdu.setRtspSource(rtspSource); vtdu.setName(camera.getId() + "_" + channel.getChanNo()); - vtdu.setIsCode("0");//榛樿涓嶈浆鐮� + 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); 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 { /*鎺у埗澶辫触,褰撳墠姝ラ鍚姩鏃堕棿缃畁ull*/ 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) { /*鎺у埗澶辫触,褰撳墠姝ラ鍚姩鏃堕棿缃畁ull*/ 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/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 9f35a32..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; 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 妯″紡锛歡pu纭В鐮�/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 bbd910c..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,26 +89,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); + conf.setSource(sourceUrl); + conf.setSourceOnDemand(true); } - mediaInfo.setMaxReaders(100); - mediaInfo.setSourceprotocol("tcp"); + conf.setMaxReaders(100); + conf.setSourceProtocol("tcp"); if (checkNameExist(name)) { - mediaClient.editPath(name, mediaInfo); + mediaClient.editPath(name, conf); } map.put("rtspUrl", rtspUrl); @@ -142,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); @@ -161,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; @@ -170,14 +147,15 @@ @Override public void removePath(String[] names) { for (String name : names) { - if(checkNameExist(name)) { - mediaClient.removePath(name);} + if (checkNameExist(name)) { + mediaClient.removePath(name); + } } } @Override public void removePath(String name) { - if(checkNameExist(name)) { + if (checkNameExist(name)) { mediaClient.removePath(name); } } @@ -193,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); @@ -203,7 +183,7 @@ info.setRtspSource(matcher.group()); info.setIsCode("1"); } else { - info.setRtspSource(item.getConf().getSource()); + info.setRtspSource(conf.getSource()); info.setIsCode("0"); } //浼犺緭鍗忚 @@ -216,7 +196,6 @@ } return pathInfoList; } - @Override public RtspSession getRtspSessionById(String sessionId) { @@ -255,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); @@ -291,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()); @@ -329,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) { @@ -461,17 +444,11 @@ @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()); + String paths = mediaClient.paths(); + JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class); + List<Items> items = jsonsRoot.getItems(); + for (Items item : items) { + nameList.add(item.getName()); } return nameList; } 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; + } + } + + /** + * 鑾峰彇娴佸獟浣搉ame鍒楄〃 + * 鍒樿嫃涔� + * 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 aac11e5..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,21 +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.device.camera.domain.CameraCmd; -import com.ruoyi.device.camera.service.ICameraSdkService; 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; @@ -30,7 +20,7 @@ * @date 2023-08-29 */ @Service -@Slf4j +@Slf4j(topic = "sdk") public class VtduServiceImpl implements IVtduService { @Resource private VtduMapper vtduMapper; @@ -68,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")); @@ -91,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()); @@ -112,6 +102,9 @@ */ @Override public int deleteVtduByNames(String[] names) { + for (String name : names) { + log.debug("娴佸獟浣撱��" + name + "銆戦�氶亾鍒犻櫎"); + } mediaService.removePath(names); return vtduMapper.deleteVtduByNames(names); } @@ -124,6 +117,7 @@ */ @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(); - - /** - * 鏌ヨ鎵�鏈塺tsp杩炴帴 - */ - @Get("/rtspconns/list") - public String rtspconns(); /** * 鎸塻essionId鏌ヨ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(); + + /** + * 鏌ヨ鎵�鏈塺tsp浼氳瘽 + */ + @Get("/rtspsessions/list") + public String rtspsessions(); + + /** + * 鏌ヨ鎵�鏈塺tsp杩炴帴 + */ + @Get("/rtspconns/list") + public String rtspconns(); + + /** + * 鎸塻essionId鏌ヨrtsp浼氳瘽 + */ + @Get("/rtspsessions/get/{sessionId}") + public String getRtspsessionById(@Var("sessionId") String sessionId); + + /** + * 鎸塻essionId鏌ヨwebrtc浼氳瘽 + */ + @Get("/webrtcsessions/get/{sessionId}") + public String getWebrtcsessionById(@Var("sessionId") String sessionId); + + /** + * 鎸塻essionId鏌ヨrtmp浼氳瘽 + */ + @Get("/rtmpconns/get/{sessionId}") + public String getRtmpsessionById(@Var("sessionId") String sessionId); + + /** + * 鎸塻essionId鍒犻櫎rtsp浼氳瘽 + */ + @Post("/rtspsessions/kick/{sessionId}") + public String kickRtspSessions(@Var("sessionId") String sessionId); + + /** + * 鎸塻essionId鍒犻櫎rtmp杩炴帴 + */ + @Post("/rtmpconns/kick/{sessionId}") + public String kickRtmpSessions(@Var("sessionId") String sessionId); + + /** + * 鎸塻essionId鍒犻櫎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/resources/templates/preview.html b/ard-work/src/main/resources/templates/preview.html index 609e256..f3ec144 100644 --- a/ard-work/src/main/resources/templates/preview.html +++ b/ard-work/src/main/resources/templates/preview.html @@ -190,6 +190,9 @@ console.log("requesting ICE servers"); fetch(this.wurl, { method: 'OPTIONS', + headers: { + 'Referer': this.wurl, + }, }) .then((res) => this.onIceServers(res)) .catch((err) => { @@ -229,6 +232,7 @@ method: 'POST', headers: { 'Content-Type': 'application/sdp', + 'Referer': this.wurl, }, body: offer.sdp, }) @@ -296,7 +300,9 @@ headers: { 'Content-Type': 'application/trickle-ice-sdpfrag', 'If-Match': this.eTag, + 'Referer': this.wurl, }, + body: generateSdpFragment(this.offerData, candidates), }) .then((res) => { 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; } -- Gitblit v1.9.3