From b1084891961232e3c697ea9fc52f127cdccffb6b Mon Sep 17 00:00:00 2001 From: liusuyi <1951119284@qq.com> Date: 星期四, 11 七月 2024 17:28:44 +0800 Subject: [PATCH] 优化:流媒体 --- ard-work/src/main/resources/templates/test.html | 548 ++++++++--- ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java | 18 ard-work/src/main/resources/templates/test1.html | 1161 +++++++++++++++++++++++++ ard-work/src/main/java/com/ruoyi/device/camera/domain/ArdCameras.java | 4 ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java | 6 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java | 19 ard-work/src/main/java/com/ruoyi/device/camera/factory/CameraSDK.java | 2 ard-work/src/main/resources/mapper/device/ArdCamerasMapper.xml | 7 /dev/null | 484 ---------- ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java | 22 ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java | 74 ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java | 82 + ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java | 124 +- ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java | 20 ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java | 29 ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/module/ConfigModule.java | 13 server/mediamtx/mediamtx.yml | 6 ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java | 4 ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/lib/LoginResultCallBack.java | 6 ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java | 65 20 files changed, 1,809 insertions(+), 885 deletions(-) diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/domain/ArdCameras.java b/ard-work/src/main/java/com/ruoyi/device/camera/domain/ArdCameras.java index 696247d..317c818 100644 --- a/ard-work/src/main/java/com/ruoyi/device/camera/domain/ArdCameras.java +++ b/ard-work/src/main/java/com/ruoyi/device/camera/domain/ArdCameras.java @@ -178,7 +178,7 @@ /** * 鐧诲綍ID */ - private Integer loginId; + private Long loginId; /** * 鍦ㄧ嚎鐘舵�� 0-绂荤嚎 1-鍦ㄧ嚎 */ @@ -192,7 +192,7 @@ /** * 璧峰閫氶亾鍙� */ - private Integer startDChan; + private Integer startChan; /** * 閫氶亾鏁� */ diff --git a/ard-work/src/main/java/com/ruoyi/device/camera/factory/CameraSDK.java b/ard-work/src/main/java/com/ruoyi/device/camera/factory/CameraSDK.java index 5b435a0..d535bbd 100644 --- a/ard-work/src/main/java/com/ruoyi/device/camera/factory/CameraSDK.java +++ b/ard-work/src/main/java/com/ruoyi/device/camera/factory/CameraSDK.java @@ -4,6 +4,7 @@ import com.ruoyi.device.camera.domain.ArdCameras; import com.ruoyi.device.camera.domain.CameraCmd; import com.ruoyi.device.channel.domain.ArdChannel; +import com.ruoyi.media.domain.Vtdu; import javax.servlet.http.HttpServletResponse; import java.util.List; @@ -116,4 +117,5 @@ //鏈湴褰曞儚鍋滄 AjaxResult localRecordStop(CameraCmd cmd); + } diff --git a/ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java b/ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java index eea7265..17a7a6d 100644 --- a/ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java +++ b/ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java @@ -1,6 +1,8 @@ package com.ruoyi.device.channel.service; import java.util.List; + +import com.ruoyi.device.camera.domain.ArdCameras; import com.ruoyi.device.channel.domain.ArdChannel; /** @@ -65,22 +67,6 @@ * @return 缁撴灉 */ public int deleteArdChannelByDeviceId(String deviceId); - /** - * @Author 鍒樿嫃涔� - * @Description 鑾峰彇2涓�氶亾鍒楄〃鐨勪氦闆� - * @Date 2024/7/10 9:38 - * @Param - * @return - */ - public List<ArdChannel> sameList(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList); - /** - * @Author 鍒樿嫃涔� - * @Description 鍙�2涓�氶亾鍒楄〃鐨勫樊闆� - * @Date 2024/7/10 9:39 - * @Param - * @return - */ - public List<ArdChannel> diffList(List<ArdChannel> firstArrayList, List<ArdChannel> secondArrayList); /** * @Author 鍒樿嫃涔� @@ -89,5 +75,5 @@ * @Param * @return */ - public void asyncChannel(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList); + public void asyncChannel(ArdCameras ardCameras, List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList); } diff --git a/ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java b/ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java index ce6565d..c715669 100644 --- a/ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java +++ b/ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java @@ -1,9 +1,16 @@ package com.ruoyi.device.channel.service.impl; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import com.ruoyi.common.utils.uuid.IdUtils; +import com.ruoyi.device.camera.domain.ArdCameras; +import com.ruoyi.device.camera.factory.CameraSDK; +import com.ruoyi.device.camera.factory.CameraSDKFactory; +import com.ruoyi.device.camera.mapper.ArdCamerasMapper; +import com.ruoyi.media.mapper.VtduMapper; +import com.ruoyi.media.service.IVtduService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.device.channel.mapper.ArdChannelMapper; @@ -22,7 +29,10 @@ public class ArdChannelServiceImpl implements IArdChannelService { @Resource private ArdChannelMapper ardChannelMapper; - + @Resource + private CameraSDKFactory cameraSDKFactory; + @Resource + private IVtduService vtduService; /** * 鏌ヨ閫氶亾绠$悊 * @@ -101,38 +111,40 @@ return ardChannelMapper.deleteArdChannelByDeviceId(deviceId); } - //姹備袱涓璞ist鐨勪氦闆� @Override - public List<ArdChannel> sameList(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList) { - List<ArdChannel> resultList = newArrayList.stream() - .filter(item -> oldArrayList.stream().map(e -> e.getChanNo()) - .collect(Collectors.toList()).contains(item.getChanNo())) - .collect(Collectors.toList()); - return resultList; - } + public void asyncChannel(ArdCameras ardCameras,List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList) { + // 灏嗗垪琛ㄨ浆鎹负鏄犲皠浠ユ彁楂樻�ц兘 + Map<Integer, ArdChannel> oldMap = oldArrayList.stream() + .collect(Collectors.toMap(ArdChannel::getChanNo, channel -> channel)); + Map<Integer, ArdChannel> newMap = newArrayList.stream() + .collect(Collectors.toMap(ArdChannel::getChanNo, channel -> channel)); - //姹備袱涓璞ist鐨勫樊闆� - @Override - public List<ArdChannel> diffList(List<ArdChannel> firstArrayList, List<ArdChannel> secondArrayList) { - List<ArdChannel> resultList = firstArrayList.stream() - .filter(item -> !secondArrayList.stream().map(e -> e.getChanNo()).collect(Collectors.toList()).contains(item.getChanNo())) - .collect(Collectors.toList()); - return resultList; - } + // 闇�瑕佹洿鏂扮殑鏁版嵁 + newArrayList.stream() + .filter(channel -> { + ArdChannel oldChannel = oldMap.get(channel.getChanNo()); + return oldChannel != null && !oldChannel.getName().equals(channel.getName()); + }) + .forEach(channel -> { + ArdChannel oldChannel = oldMap.get(channel.getChanNo()); + channel.setId(oldChannel.getId()); + updateArdChannel(channel); + }); - @Override - public void asyncChannel(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList) { - //闇�瑕佹洿鏂扮殑鏁版嵁,鍙傛暟椤哄簭娉ㄦ剰 - sameList(oldArrayList, newArrayList).stream().forEach(ardChannel -> { - updateArdChannel(ardChannel); - }); - //闇�瑕佸垹闄ょ殑鏁版嵁 - diffList(oldArrayList, newArrayList).stream().forEach(ardChannel -> { - deleteArdChannelById(ardChannel.getId()); - }); - //闇�瑕佹柊澧炵殑鏁版嵁 - diffList(newArrayList, oldArrayList).stream().forEach(ardChannel -> { - insertArdChannel(ardChannel); - }); + // 闇�瑕佸垹闄ょ殑鏁版嵁 + oldArrayList.stream() + .filter(channel -> !newMap.containsKey(channel.getChanNo())) + .forEach(channel -> { + deleteArdChannelById(channel.getId()); + vtduService.deleteVtduByName(channel.getDeviceId() + "_" + channel.getChanNo()); + }); + + // 闇�瑕佹柊澧炵殑鏁版嵁 + newArrayList.stream() + .filter(channel -> !oldMap.containsKey(channel.getChanNo())) + .forEach(channel -> { + insertArdChannel(channel); + vtduService.addChanToVtdu(ardCameras, channel); + }); } } \ No newline at end of file diff --git a/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java b/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java index 7232194..6d89b58 100644 --- a/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java +++ b/ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java @@ -4,10 +4,12 @@ import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.media.domain.Config; +import com.ruoyi.media.domain.Paths; import com.ruoyi.media.domain.StreamInfo; import com.ruoyi.media.domain.Vtdu; import com.ruoyi.media.service.IMediaService; @@ -112,7 +114,7 @@ @PreAuthorize("@ss.hasPermi('media:stream:remove')") @DeleteMapping("/{sessionId}") public AjaxResult removePullStreamSession(@PathVariable String sessionId) { - List<StreamInfo> pullStreamList = mediaService.getPullStreamList(); + List<StreamInfo> pullStreamList = mediaService.getPullStreamList(1,1000); StreamInfo streamInfo = pullStreamList.stream() .filter(object -> object.getId().equals(sessionId)) .collect(Collectors.toList()).get(0); @@ -143,9 +145,9 @@ @GetMapping("/path/list") @ApiOperation("鑾峰彇褰撳墠閫氶亾鍒楄〃") @ApiOperationSupport(order = 5) - public TableDataInfo getPaths() { + public TableDataInfo getPaths(Integer pageNum,Integer pageSize) { startPage(); - return getDataTable(mediaService.paths()); + return getDataTable(mediaService.paths(pageNum,pageSize)); } /** @@ -154,7 +156,7 @@ @GetMapping("/getRtspSessionById") @ApiOperation("鎸塈D鏌ヨ鎷夋祦璇︽儏") public AjaxResult getRtspSessionById(String sessionId) { - List<StreamInfo> pullStreamList = mediaService.getPullStreamList(); + List<StreamInfo> pullStreamList = mediaService.getPullStreamList(1,1000); StreamInfo streamInfo = pullStreamList.stream() .filter(object -> object.getId().equals(sessionId)) .collect(Collectors.toList()).get(0); @@ -176,9 +178,9 @@ @GetMapping("/pushList") @ApiOperation("鑾峰彇鎺ㄦ祦鍒楄〃") @ApiOperationSupport(order = 6) - public TableDataInfo getPushStreamList() { + public TableDataInfo getPushStreamList(Integer pageNum,Integer pageSize) { startPage(); - return getDataTable(mediaService.getPushStreamList()); + return getDataTable(mediaService.getPushStreamList(pageNum,pageSize)); } /** @@ -188,9 +190,9 @@ @GetMapping("/pullList") @ApiOperation("鑾峰彇鎷夋祦鍒楄〃") @ApiOperationSupport(order = 7) - public TableDataInfo getPullStreamList() { + public TableDataInfo getPullStreamList(Integer pageNum,Integer pageSize) { startPage(); - return getDataTable(mediaService.getPullStreamList()); + return getDataTable(mediaService.getPullStreamList(pageNum,pageSize)); } } 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 360b7fe..9c0602e 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 @@ -33,7 +33,7 @@ void removePath(String name); - List<StreamInfo> paths(); + List<StreamInfo> paths(Integer pageNum,Integer pageSize); List<String> getNameList(); @@ -45,9 +45,9 @@ RtmpSession getRtmpSessionById(String sessionId); - List<StreamInfo> getPushStreamList(); + List<StreamInfo> getPushStreamList(Integer pageNum,Integer pageSize); - List<StreamInfo> getPullStreamList(); + List<StreamInfo> getPullStreamList(Integer pageNum,Integer pageSize); Boolean kickRtspSession(String sessionId); diff --git a/ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java b/ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java deleted file mode 100644 index cccbc36..0000000 --- a/ard-work/src/main/java/com/ruoyi/media/service/IMediaV2Service.java +++ /dev/null @@ -1,65 +0,0 @@ -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/IVtduService.java b/ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java index 7775461..dca1a55 100644 --- a/ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java +++ b/ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java @@ -2,6 +2,7 @@ import java.util.List; +import com.ruoyi.device.camera.domain.ArdCameras; import com.ruoyi.device.channel.domain.ArdChannel; import com.ruoyi.media.domain.Vtdu; @@ -103,4 +104,7 @@ * @Param */ public void asyncVtdu(List<Vtdu> vtdus, List<String> names); + + //娣诲姞閫氶亾鑷虫祦濯掍綋 + void addChanToVtdu(ArdCameras camera, ArdChannel channel); } 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 de4f9fc..0079687 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 @@ -8,6 +8,7 @@ import com.ruoyi.media.service.IMediaService; import com.ruoyi.utils.forest.MediaClient; import com.ruoyi.utils.tools.ArdTool; +import io.swagger.models.auth.In; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.ApplicationArguments; @@ -146,6 +147,8 @@ if (StringUtils.isNotEmpty(conf.getRunOnDemand())) { runOn = conf.getRunOnDemand(); info.setMode("0"); + } else { + info.setMode("1"); } //RTSP婧愬湴鍧� Matcher matcher = Pattern.compile("rtsp://[^\\s\"]+").matcher(runOn); @@ -184,8 +187,8 @@ } @Override - public List<StreamInfo> paths() { - Paths paths = mediaClient.paths(); + public List<StreamInfo> paths(Integer pageNum, Integer pageSize) { + Paths paths = mediaClient.paths(pageNum - 1, pageSize); List<Items> items = paths.getItems(); List<StreamInfo> pathInfoList = new ArrayList<>(); for (Items item : items) { @@ -221,23 +224,17 @@ @Override public RtspSession getRtspSessionById(String sessionId) { - String list = mediaClient.getRtspsessionById(sessionId); - RtspSession rtspSession = JSONObject.parseObject(list, RtspSession.class); - return rtspSession; + return mediaClient.getRtspsessionById(sessionId); } @Override public WebrtcSession getWebrtcSessionById(String sessionId) { - String list = mediaClient.getWebrtcsessionById(sessionId); - WebrtcSession webrtcSession = JSONObject.parseObject(list, WebrtcSession.class); - return webrtcSession; + return mediaClient.getWebrtcsessionById(sessionId); } @Override public RtmpSession getRtmpSessionById(String sessionId) { - String list = mediaClient.getRtmpsessionById(sessionId); - RtmpSession rtmpSession = JSONObject.parseObject(list, RtmpSession.class); - return rtmpSession; + return mediaClient.getRtmpsessionById(sessionId); } /** @@ -246,9 +243,9 @@ * 2023/8/29 9:37:05 */ @Override - public List<StreamInfo> getPushStreamList() { + public List<StreamInfo> getPushStreamList(Integer pageNum, Integer pageSize) { List<StreamInfo> PushStreamInfoList = new ArrayList<>(); - Paths paths = mediaClient.paths(); + Paths paths = mediaClient.paths(pageNum - 1, pageSize); List<Items> items = paths.getItems(); for (Items item : items) { StreamInfo info = new StreamInfo(); @@ -321,9 +318,9 @@ * 2023/8/29 9:37:05 */ @Override - public List<StreamInfo> getPullStreamList() { + public List<StreamInfo> getPullStreamList(Integer pageNum, Integer pageSize) { List<StreamInfo> PullStreamInfoList = new ArrayList<>(); - Paths paths = mediaClient.paths(); + Paths paths = mediaClient.paths(pageNum - 1, pageSize); List<Items> items = paths.getItems(); for (Items item : items) { List<Readers> readers = item.getReaders(); @@ -467,7 +464,7 @@ public List<String> getNameList() { List<String> nameList = new ArrayList<>(); try { - Paths paths = mediaClient.paths(); + Paths paths = mediaClient.paths(0, 1000); List<Items> items = paths.getItems(); for (Items item : items) { nameList.add(item.getName()); 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 deleted file mode 100644 index ec24786..0000000 --- a/ard-work/src/main/java/com/ruoyi/media/service/impl/MediaV2ServiceImpl.java +++ /dev/null @@ -1,484 +0,0 @@ -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.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<>(); - Paths paths = mediaClient.paths(); - List<Items> items = paths.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() { - Paths paths = mediaClient.paths(); - List<Items> items = paths.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<>(); - Paths paths = mediaClient.paths(); - List<Items> items = paths.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<>(); - Paths paths = mediaClient.paths(); - List<Items> items = paths.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 { - Paths paths = mediaClient.paths(); - List<Items> items = paths.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 36a8628..f0be3d3 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 @@ -6,9 +6,15 @@ import java.util.stream.Collectors; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.device.camera.domain.ArdCameras; +import com.ruoyi.device.camera.domain.CameraCmd; +import com.ruoyi.device.camera.factory.CameraSDK; +import com.ruoyi.device.camera.factory.CameraSDKFactory; import com.ruoyi.device.channel.domain.ArdChannel; +import com.ruoyi.media.domain.StreamInfo; import com.ruoyi.media.service.IMediaService; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.ruoyi.media.mapper.VtduMapper; import com.ruoyi.media.domain.Vtdu; @@ -30,7 +36,10 @@ private VtduMapper vtduMapper; @Resource private IMediaService mediaService; - + @Resource + private CameraSDKFactory cameraSDKFactory; + @Value("${mediamtx.host}") + String mediamtxHost; /** * 鏌ヨ娴佸獟浣撶鐞� * @@ -39,7 +48,6 @@ */ @Override public Vtdu selectVtduByName(String name) { - return vtduMapper.selectVtduByName(name); } @@ -62,17 +70,6 @@ */ @Override public int insertVtdu(Vtdu vtdu) { - 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")); - vtdu.setWebrtcUrl(map.get("webrtcUrl")); - - vtdu.setName(vtdu.getName()); - vtdu.setRtspSource(vtdu.getRtspSource()); - vtdu.setIsCode(vtdu.getIsCode()); - vtdu.setMode(vtdu.getMode()); - vtdu.setCreateTime(DateUtils.getNowDate()); return vtduMapper.insertVtdu(vtdu); } @@ -84,7 +81,6 @@ */ @Override public int updateVtdu(Vtdu vtdu) { - 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()); @@ -171,12 +167,10 @@ .collect(Collectors.toList()); return nameList; } else { - List<String> nameList = names.stream().filter(item -> !vtdus.stream().map(Vtdu::getName).collect(Collectors.toList()).contains(item)) .collect(Collectors.toList()); return nameList; } - } //闇�瑕佹柊澧炵殑锛堟祦濯掍綋涓皯鐨勶級 @@ -186,18 +180,21 @@ } /** - * @Author 鍒樿嫃涔� - * @Description 鍚屾鏈湴vtdu搴撳拰娴佸獟浣撲腑鐨勬暟鎹� - * @Date 2024/7/10 15:26 - * @Param vtdus vtdu搴撶殑闆嗗悎 - * @Param names 娴佸獟浣撶殑name闆嗗悎 * @return + * @Author 鍒樿嫃涔� + * @Description 鍚屾鏈湴vtdu搴撳拰娴佸獟浣撲腑鐨勬暟鎹� + * @Date 2024/7/10 15:26 + * @Param vtdus vtdu搴撶殑闆嗗悎 + * @Param names 娴佸獟浣撶殑name闆嗗悎 */ @Override public void asyncVtdu(List<Vtdu> vtdus, List<String> names) { //闇�瑕佹洿鏂扮殑鏁版嵁,鍙傛暟椤哄簭娉ㄦ剰 sameList(vtdus, names).stream().forEach(vtdu -> { - mediaService.editPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode()); + StreamInfo streamInfo = mediaService.getPathInfo(vtdu.getName()); + if (!streamInfo.getRtspSource().equals(vtdu.getRtspSource())) { + mediaService.editPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode()); + } }); //闇�瑕佸垹闄ょ殑鏁版嵁 diffListToDel(vtdus, names).stream().forEach(name -> { @@ -208,4 +205,45 @@ mediaService.addPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode()); }); } + @Override + public void addChanToVtdu(ArdCameras camera, ArdChannel channel) { + String name = camera.getId() + "_" + channel.getChanNo(); + String rtspSource=""; + switch (camera.getFactory()) + { + case "1": rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream";break; + case "2": rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0";break; + } + + //鍒犻櫎娴佸獟浣� + if (selectVtduByName(name) != null) { + deleteVtduByName(name); + } + //娣诲姞鍒版祦濯掍綋 + CameraCmd cmd = new CameraCmd(camera.getId(), channel.getChanNo()); + CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(camera.getFactory()); + Map<String, Object> videoCompressionCfg = cameraSDK.getVideoCompressionCfg(cmd); + Vtdu vtdu = new Vtdu(); + if (videoCompressionCfg.get("videoEncType") != null) { + if (videoCompressionCfg.get("videoEncType").equals("鏍囧噯h264")) { + vtdu.setIsCode("0");//榛樿涓嶈浆鐮� + } else { + vtdu.setIsCode("1");//榛樿杞爜 + } + } else { + vtdu.setIsCode("0");//榛樿涓嶈浆鐮� + } + vtdu.setRtspSource(rtspSource); + vtdu.setName(name); + vtdu.setMode("1");//榛樿CPU杞В鐮� + vtdu.setCameraId(camera.getId()); + String rtspUrl = "rtsp://" + mediamtxHost + ":8554/" + name; + String rtmpUrl = "rtmp://" + mediamtxHost + ":1935/" + name; + String webrtcUrl = "http://" + mediamtxHost + ":8889/" + name; + vtdu.setRtmpUrl(rtmpUrl); + vtdu.setWebrtcUrl(webrtcUrl); + vtdu.setRtspUrl(rtspUrl); + insertVtdu(vtdu); + } + } 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 158a6ee..e441bc0 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,10 +1,7 @@ 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; -import com.ruoyi.media.domain.Paths; +import com.ruoyi.media.domain.*; import java.nio.file.Path; @@ -38,14 +35,14 @@ /** * 鑾峰彇璺緞璇︽儏 */ - @Get(url ="/config/paths/get/{name}") + @Get(url = "/config/paths/get/{name}") public Conf getPathInfo(@Var("name") String name); /** * 鏌ヨ鎵�鏈夎矾寰� */ - @Get("/paths/list") - public Paths paths(); + @Get("/paths/list?page={pageNum}&itemsPerPage={pageSize}") + public Paths paths(@Var("pageNum") Integer pageNum, @Var("pageSize") Integer pageSize); /** * 鏌ヨ鎵�鏈塺tsp浼氳瘽 @@ -57,19 +54,19 @@ * 鎸塻essionId鏌ヨrtsp浼氳瘽 */ @Get("/rtspsessions/get/{sessionId}") - public String getRtspsessionById(@Var("sessionId") String sessionId); + public RtspSession getRtspsessionById(@Var("sessionId") String sessionId); /** * 鎸塻essionId鏌ヨwebrtc浼氳瘽 */ @Get("/webrtcsessions/get/{sessionId}") - public String getWebrtcsessionById(@Var("sessionId") String sessionId); + public WebrtcSession getWebrtcsessionById(@Var("sessionId") String sessionId); /** * 鎸塻essionId鏌ヨrtmp浼氳瘽 */ @Get("/rtmpconns/get/{sessionId}") - public String getRtmpsessionById(@Var("sessionId") String sessionId); + public RtmpSession getRtmpsessionById(@Var("sessionId") String sessionId); /** * 鎸塻essionId鍒犻櫎rtsp浼氳瘽 @@ -89,9 +86,4 @@ @Post("/webrtcsessions/kick/{sessionId}") public String kickWebrtcSessions(@Var("sessionId") String sessionId); - /** - * 閰嶇疆娴佸獟浣撳弬鏁� - */ - @Post("/config/set") - public String setConfig(@JSONBody Config config); } diff --git a/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/module/ConfigModule.java b/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/module/ConfigModule.java index 631218d..e5c60f4 100644 --- a/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/module/ConfigModule.java +++ b/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/module/ConfigModule.java @@ -81,10 +81,12 @@ return result; } - public static String getChannelName(NetSDKLib.LLong hLoginHandle,Integer channel) { + + //鏌ヨ閫氶亾鍚嶇О + public static String getChannelName(NetSDKLib.LLong hLoginHandle, Integer channel) { String channelName = ""; NetSDKLib.AV_CFG_ChannelName channelTitleName = new NetSDKLib.AV_CFG_ChannelName(); - if (ToolKits.GetDevConfig(hLoginHandle, channel, NetSDKLib.CFG_CMD_CHANNELTITLE, channelTitleName)) { + if (ToolKits.GetDevConfig(hLoginHandle, channel - 1, NetSDKLib.CFG_CMD_CHANNELTITLE, channelTitleName)) { try { channelName = new String(channelTitleName.szName, "GBK"); } catch (Exception e) { @@ -95,6 +97,7 @@ } return channelName; } + public static boolean GetDevConfig(NetSDKLib.LLong hLoginHandle, int nChn, String strCmd, Structure cmdObject) { boolean result = true; IntByReference error = new IntByReference(0); @@ -111,6 +114,7 @@ return result; } + //鏌ヨ鐩告満鐘舵�� public static boolean queryCameraState(NetSDKLib.LLong hLoginHandle, Integer chanNum, Integer chanNo) { boolean bRet = false; try { @@ -141,9 +145,9 @@ stOut.read(); ToolKits.GetPointerDataToStructArr(stOut.pCameraStateInfo, arrCameraStatus); // 灏哖ointer鎷疯礉鍒版暟缁勫唴瀛� final String[] connectionState = {"鏈煡", "姝e湪杩炴帴", "宸茶繛鎺�", "鏈繛鎺�", "閫氶亾鏈厤缃�,鏃犱俊鎭�", "閫氶亾鏈夐厤缃�,浣嗚绂佺敤"}; - log.debug(connectionState[arrCameraStatus[chanNo - 1].emConnectionState]); + if (connectionState[arrCameraStatus[chanNo - 1].emConnectionState].equals("宸茶繛鎺�")) { - log.debug("閫氶亾" + arrCameraStatus[chanNo - 1].nChannel + connectionState[arrCameraStatus[chanNo - 1].emConnectionState]); + //log.debug("閫氶亾锛�" + arrCameraStatus[chanNo - 1].nChannel + "鐘舵�侊細" + connectionState[arrCameraStatus[chanNo - 1].emConnectionState]); bRet = true; } else { bRet = false; @@ -205,6 +209,5 @@ return result; } - } diff --git a/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java b/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java index 3957ce6..be1a771 100644 --- a/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java +++ b/ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java @@ -104,7 +104,7 @@ NetSDKLib.LLong loginId = LoginModule.login(camera.getIp(), camera.getPort(), camera.getUsername(), camera.getPassword(), m_stDeviceInfo); if (loginId.longValue() <= 0) { camera.setChanNum(0); - camera.setLoginId(-1); + camera.setLoginId(-1l); camera.setState("0"); ardCamerasService.updateArdCameras(camera); //鍒犻櫎绠$悊閫氶亾 @@ -112,11 +112,11 @@ log.error("璁惧[" + camera.getIp() + ":" + camera.getPort() + "]鐧诲綍澶辫触:" + getErrorCodePrint()); return AjaxResult.warn(ErrorCode.getErrorCode(LoginModule.netsdk.CLIENT_GetLastError())); } - + log.debug("璁惧[" + camera.getIp() + ":" + camera.getPort() + "]鐧诲綍鎴愬姛:" + (int) loginId.longValue()); camera.setState("1"); camera.setChanNum(m_stDeviceInfo.byChanNum); - camera.setStartDChan(1); - camera.setLoginId((int) loginId.longValue()); + camera.setStartChan(1); + camera.setLoginId(loginId.longValue()); GlobalVariable.loginMap.put(camera.getId(), loginId); //鑾峰彇鏈�鏂伴�氶亾 List<ArdChannel> ardChannelList = getChannels(camera); @@ -125,12 +125,11 @@ ardChannelList.stream().forEach(channel -> { ardChannelService.insertArdChannel(channel); }); - camera.setChanNum(ardChannelList.size()); camera.setChannelList(ardChannelList); - ardCamerasService.updateArdCameras(camera); - //閰嶇疆鍒版祦濯掍綋 - addVtdu(camera); + //閫氶亾鎵归噺娣诲姞鍒版祦濯掍綋 + batchAddVtdu(camera); } + ardCamerasService.updateArdCameras(camera); //鍒涘缓寮曞闃熷垪 createGuideQueue(camera); return AjaxResult.success("璁惧鐧诲綍鎴愬姛"); @@ -149,7 +148,7 @@ NetSDKLib.LLong loginId = LoginModule.login(camera.getIp(), camera.getPort(), camera.getUsername(), camera.getPassword(), m_stDeviceInfo); if (loginId.longValue() <= 0) { camera.setChanNum(0); - camera.setLoginId(-1); + camera.setLoginId(-1l); camera.setState("0"); ardCamerasService.updateArdCameras(camera); //鍒犻櫎绠$悊閫氶亾 @@ -157,10 +156,11 @@ log.error("璁惧[" + camera.getIp() + ":" + camera.getPort() + "]鐧诲綍澶辫触:" + getErrorCodePrint()); return AjaxResult.warn(getErrorCodePrint()); } + log.debug("璁惧[" + camera.getIp() + ":" + camera.getPort() + "]鐧诲綍鎴愬姛:" + loginId); camera.setState("1"); camera.setChanNum(m_stDeviceInfo.byChanNum); - camera.setStartDChan(1); - camera.setLoginId((int) loginId.longValue()); + camera.setStartChan(1); + camera.setLoginId((Long) loginId.longValue()); ardCamerasService.updateArdCameras(camera); GlobalVariable.loginMap.put(camera.getId(), loginId); @@ -171,12 +171,11 @@ ardChannelList.stream().forEach(channel -> { ardChannelService.insertArdChannel(channel); }); - camera.setChanNum(ardChannelList.size()); camera.setChannelList(ardChannelList); - ardCamerasService.updateArdCameras(camera); - //閰嶇疆鍒版祦濯掍綋 - addVtdu(camera); + //閫氶亾鎵归噺娣诲姞鍒版祦濯掍綋 + batchAddVtdu(camera); } + ardCamerasService.updateArdCameras(camera); //鍒涘缓寮曞闃熷垪 createGuideQueue(camera); return AjaxResult.success("鐧诲綍鎴愬姛"); @@ -186,35 +185,13 @@ } } - //娣诲姞鍒版祦濯掍綋 - private void addVtdu(ArdCameras camera) { + //閫氶亾鎵归噺娣诲姞鍒版祦濯掍綋 + public void batchAddVtdu(ArdCameras camera) { camera.getChannelList().stream().forEach(channel -> { - String name = camera.getId() + "_" + channel.getChanNo(); - String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0"; - //鍒犻櫎娴佸獟浣� - if (vtduService.selectVtduByName(name) != null) { - vtduService.deleteVtduByName(name); - } - //娣诲姞鍒版祦濯掍綋 - CameraCmd cmd = new CameraCmd(camera.getId(), channel.getChanNo()); - Map<String, Object> videoCompressionCfg = getVideoCompressionCfg(cmd); - Vtdu vtdu = new Vtdu(); - if (videoCompressionCfg.get("videoEncType") != null) { - if (videoCompressionCfg.get("videoEncType").equals("鏍囧噯h264")) { - vtdu.setIsCode("0");//榛樿涓嶈浆鐮� - } else { - vtdu.setIsCode("1");//榛樿杞爜 - } - } else { - vtdu.setIsCode("0");//榛樿涓嶈浆鐮� - } - vtdu.setRtspSource(rtspSource); - vtdu.setName(name); - vtdu.setMode("1");//榛樿CPU杞В鐮� - vtdu.setCameraId(camera.getId()); - vtduService.insertVtdu(vtdu); + vtduService.addChanToVtdu(camera, channel); }); } + //鍒涘缓寮曞闃熷垪 private void createGuideQueue(ArdCameras camera) { @@ -231,12 +208,14 @@ //鑾峰彇閫氶亾 public List<ArdChannel> getChannels(ArdCameras camera) { + if (camera.getLoginId().equals(-1)) { + return new ArrayList<>(); + } LLong loginId = new LLong(camera.getLoginId()); List<ArdChannel> ardChannelList = new ArrayList<>(); for (int i = 1; i < camera.getChanNum() + 1; i++) { ArdChannel channel = new ArdChannel(); - String chanName = ConfigModule.getChannelName(loginId, i - 1).trim(); - log.debug("鑾峰彇閫氶亾鍚嶇О锛�" + chanName); + String chanName = ConfigModule.getChannelName(loginId, i).trim(); channel.setName(chanName.equals("") ? "閫氶亾" + i : chanName); channel.setDeviceId(camera.getId()); channel.setChanNo(i); diff --git a/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/lib/LoginResultCallBack.java b/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/lib/LoginResultCallBack.java index 8e05ebe..b1ecad8 100644 --- a/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/lib/LoginResultCallBack.java +++ b/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/lib/LoginResultCallBack.java @@ -48,10 +48,10 @@ if (dwResult == 1) { GlobalVariable.loginMap.put(camera.getId(), lUserID); log.debug(camera.getIp() + ":" + camera.getPort() + "鐧诲綍鎴愬姛"); - camera.setLoginId(lUserID); + camera.setLoginId((long)lUserID); camera.setState("1"); camera.setChanNum((int) lpDeviceinfo.byChanNum); - camera.setStartDChan((int) lpDeviceinfo.byStartDChan); + camera.setStartChan((int) lpDeviceinfo.byStartDChan); //鑾峰彇鏈�鏂伴�氶亾 List<ArdChannel> cameraChannelList = hikClientService.getChannels(camera); if (cameraChannelList.size() > 0) { @@ -89,7 +89,7 @@ } else { log.debug(camera.getIp() + ":" + camera.getPort() + "鐧诲綍澶辫触"); camera.setChanNum(0); - camera.setLoginId(-1); + camera.setLoginId(-1l); camera.setState("0"); } ardCamerasService.updateArdCameras(camera); diff --git a/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java b/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java index 0269e99..36d5d94 100644 --- a/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java +++ b/ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java @@ -94,7 +94,7 @@ String WIN_PATH = System.getProperty("user.dir") + File.separator + "ardLog" + File.separator + "logs" + File.separator; hCNetSDK.NET_DVR_SetLogToFile(3, WIN_PATH, true); } else { - hCNetSDK.NET_DVR_SetLogToFile(3, "/home/ardLog/hiklog" , true); + hCNetSDK.NET_DVR_SetLogToFile(3, "/home/ardLog/hiklog", true); } String m_sDeviceIP = camera.getIp(); String m_sUsername = camera.getUsername(); @@ -125,7 +125,7 @@ if (lUserID < 0) { int errorCode = hCNetSDK.NET_DVR_GetLastError(); camera.setChanNum(0); - camera.setLoginId(-1); + camera.setLoginId(-1l); camera.setState("0"); //鍒犻櫎绠$悊閫氶亾 ardChannelService.deleteArdChannelByDeviceId(camera.getId()); @@ -146,7 +146,7 @@ } GlobalVariable.loginMap.put(camera.getId(), lUserID); GlobalVariable.loginCameraMap.put(lUserID, camera); - camera.setLoginId(lUserID); + camera.setLoginId((long)lUserID); camera.setState("1"); int chanNum = m_strDeviceInfo.struDeviceV30.byChanNum; int startDchan = m_strDeviceInfo.struDeviceV30.byStartDChan + 1; @@ -155,7 +155,7 @@ startDchan = m_strDeviceInfo.struDeviceV30.byStartDChan; } camera.setChanNum(chanNum); - camera.setStartDChan(startDchan); + camera.setStartChan(startDchan); //鑾峰彇鏈�鏂伴�氶亾 List<ArdChannel> cameraChannelList = getChannels(camera); if (cameraChannelList.size() > 0) { @@ -164,16 +164,16 @@ ardChannelService.insertArdChannel(channel); }); camera.setChannelList(cameraChannelList); - camera.setChanNum(cameraChannelList.size()); - ardCamerasService.updateArdCameras(camera); - //娣诲姞鍒版祦濯掍綋 - addVtdu(camera); + //camera.setChanNum(cameraChannelList.size()); + //閫氶亾鎵归噺娣诲姞鍒版祦濯掍綋 + batchAddVtdu(camera); } + ardCamerasService.updateArdCameras(camera); //鍒涘缓寮曞闃熷垪 createGuideQueue(camera); return AjaxResult.success("璁惧鐧诲綍鎴愬姛"); } catch (Exception ex) { - log.error("璁惧鐧诲綍寮傚父" , ex); + log.error("璁惧鐧诲綍寮傚父", ex); return AjaxResult.error("璁惧鐧诲綍寮傚父" + ex.getMessage()); } } @@ -200,7 +200,7 @@ String WIN_PATH = System.getProperty("user.dir") + File.separator + "ardLog" + File.separator + "logs" + File.separator; hCNetSDK.NET_DVR_SetLogToFile(3, WIN_PATH, true); } else { - hCNetSDK.NET_DVR_SetLogToFile(3, "/home/ardLog/hiklog" , true); + hCNetSDK.NET_DVR_SetLogToFile(3, "/home/ardLog/hiklog", true); } String m_sDeviceIP = camera.getIp(); String m_sUsername = camera.getUsername(); @@ -231,7 +231,7 @@ if (lUserID < 0) { int errorCode = hCNetSDK.NET_DVR_GetLastError(); camera.setChanNum(0); - camera.setLoginId(-1); + camera.setLoginId(-1l); camera.setState("0"); //鍒犻櫎绠$悊閫氶亾 ardChannelService.deleteArdChannelByDeviceId(camera.getId()); @@ -254,7 +254,7 @@ GlobalVariable.loginMap.put(camera.getId(), lUserID); GlobalVariable.loginCameraMap.put(lUserID, camera); - camera.setLoginId(lUserID); + camera.setLoginId((long)lUserID); camera.setState("1"); int chanNum = m_strDeviceInfo.struDeviceV30.byChanNum; int startDchan = m_strDeviceInfo.struDeviceV30.byStartDChan + 1; @@ -263,7 +263,7 @@ startDchan = m_strDeviceInfo.struDeviceV30.byStartDChan; } camera.setChanNum(chanNum); - camera.setStartDChan(startDchan); + camera.setStartChan(startDchan); //鑾峰彇鏈�鏂伴�氶亾 List<ArdChannel> cameraChannelList = getChannels(camera); if (cameraChannelList.size() > 0) { @@ -272,16 +272,16 @@ ardChannelService.insertArdChannel(channel); }); camera.setChannelList(cameraChannelList); - camera.setChanNum(cameraChannelList.size()); - ardCamerasService.updateArdCameras(camera); - //娣诲姞鍒版祦濯掍綋 - addVtdu(camera); + //camera.setChanNum(cameraChannelList.size()); + //閫氶亾鎵归噺娣诲姞鍒版祦濯掍綋 + batchAddVtdu(camera); } + ardCamerasService.updateArdCameras(camera); //鍒涘缓寮曞闃熷垪 createGuideQueue(camera); return AjaxResult.success("璁惧鐧诲綍鎴愬姛"); } catch (Exception ex) { - log.error("娉ㄥ唽璁惧寮傚父" , ex); + log.error("娉ㄥ唽璁惧寮傚父", ex); return AjaxResult.error("娉ㄥ唽璁惧寮傚父" + ex.getMessage()); } } @@ -299,36 +299,19 @@ } } - //娣诲姞鍒版祦濯掍綋 - private void addVtdu(ArdCameras camera) { + //閫氶亾鎵归噺娣诲姞鍒版祦濯掍綋 + public void batchAddVtdu(ArdCameras camera) { try { - camera.getChannelList().stream().forEach(channel->{ - String name = camera.getId() + "_" + channel.getChanNo(); - String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream"; - //鍒犻櫎娴佸獟浣� - if (vtduService.selectVtduByName(name) != null) { - vtduService.deleteVtduByName(name); - } - //娣诲姞鍒版祦濯掍綋 - Vtdu vtdu = new Vtdu(); - vtdu.setRtspSource(rtspSource); - vtdu.setName(name); - 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); + camera.getChannelList().stream().forEach(channel -> { + vtduService.addChanToVtdu(camera, channel); }); } catch (Exception ex) { log.error("閫氶亾娣诲姞鍒版祦濯掍綋寮傚父锛�" + ex.getMessage()); } } + + /** * @鎻忚堪 娉ㄩ攢鐧诲綍 @@ -875,10 +858,10 @@ nFrameRate = "鏈煡"; break; } - map.put("resolution" , resolution);//鍒嗚鲸鐜� - map.put("videoBitrate" , videoBitrate);//姣旂壒鐜� - map.put("videoEncType" , videoEncType);//缂栫爜 - map.put("nFrameRate" , nFrameRate);//甯х巼 + map.put("resolution", resolution);//鍒嗚鲸鐜� + map.put("videoBitrate", videoBitrate);//姣旂壒鐜� + map.put("videoEncType", videoEncType);//缂栫爜 + map.put("nFrameRate", nFrameRate);//甯х巼 } else { int code = hCNetSDK.NET_DVR_GetLastError(); @@ -931,9 +914,9 @@ double z = d.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue(); //log.debug("T鍨傜洿鍙傛暟涓�: " + p + "P姘村钩鍙傛暟涓�: " + t + "Z鍙樺�嶅弬鏁颁负: " + z); Map<String, Object> ptzMap = new HashMap<>(); - ptzMap.put("p" , p); - ptzMap.put("t" , t); - ptzMap.put("z" , z); + ptzMap.put("p", p); + ptzMap.put("t", t); + ptzMap.put("z", z); return AjaxResult.success(ptzMap); } @@ -980,9 +963,9 @@ float fTilt = lpPTZAbsoluteEX_cfg.struPTZCtrl.fTilt; float t = fTilt < 0 ? fTilt + 360 : fTilt; float z = lpPTZAbsoluteEX_cfg.struPTZCtrl.fZoom; - ptzMap.put("p" , p); - ptzMap.put("t" , t); - ptzMap.put("z" , z); + ptzMap.put("p", p); + ptzMap.put("t", t); + ptzMap.put("z", z); return AjaxResult.success(ptzMap); } catch (Exception ex) { log.error("鑾峰彇楂樼簿搴TZ缁濆浣嶇疆寮傚父:" + ex.getMessage()); @@ -1087,7 +1070,7 @@ return AjaxResult.success("璁剧疆楂樼簿搴TZ鍙傛暟鎴愬姛"); } catch (Exception ex) { - log.error("璁剧疆楂樼簿搴TZ鍙傛暟寮傚父" , ex); + log.error("璁剧疆楂樼簿搴TZ鍙傛暟寮傚父", ex); return AjaxResult.error("璁剧疆楂樼簿搴TZ鍙傛暟寮傚父:" + ex); } } @@ -1125,7 +1108,7 @@ log.error("璁剧疆ptz澶辫触,璇风◢鍚庨噸璇�" + code); return AjaxResult.warn("璁剧疆ptz澶辫触:" + SdkErrorCodeEnum.getDescByCode(code) + "(" + code + ")"); } - return AjaxResult.success("寮曞鍧愭爣鎴愬姛",correctPitch); + return AjaxResult.success("寮曞鍧愭爣鎴愬姛", correctPitch); } catch (Exception ex) { log.error("寮曞鍧愭爣寮傚父:" + ex.getMessage()); return AjaxResult.error("寮曞鍧愭爣寮傚父:" + ex.getMessage()); @@ -1234,12 +1217,12 @@ String wZoomPosMax = df.format((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wZoomPosMax)) / 10); String wZoomPosMin = df.format((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wZoomPosMin)) / 10); Map<String, Object> ptzScopeMap = new HashMap<>(); - ptzScopeMap.put("pMax" , wPanPosMax); - ptzScopeMap.put("pMin" , wPanPosMin); - ptzScopeMap.put("tMax" , wTiltPosMax); - ptzScopeMap.put("tMin" , wTiltPosMin); - ptzScopeMap.put("zMax" , wZoomPosMax); - ptzScopeMap.put("zMin" , wZoomPosMin); + ptzScopeMap.put("pMax", wPanPosMax); + ptzScopeMap.put("pMin", wPanPosMin); + ptzScopeMap.put("tMax", wTiltPosMax); + ptzScopeMap.put("tMin", wTiltPosMin); + ptzScopeMap.put("zMax", wZoomPosMax); + ptzScopeMap.put("zMin", wZoomPosMin); return AjaxResult.success(ptzScopeMap); } } @@ -1335,7 +1318,7 @@ boolean bool = hCNetSDK.NET_DVR_SetDVRConfig(userId, NET_DVR_SET_CCDPARAMCFG, chanNo, point, struDayNigh.size()); if (!bool) { int code = hCNetSDK.NET_DVR_GetLastError(); - log.error("鍒囨崲绾㈠澶辫触 ErrorCode:{},ErrorInfo:{}" , code, SdkErrorCodeEnum.getDescByCode(code)); + log.error("鍒囨崲绾㈠澶辫触 ErrorCode:{},ErrorInfo:{}", code, SdkErrorCodeEnum.getDescByCode(code)); return AjaxResult.warn("鍒囨崲绾㈠澶辫触:" + SdkErrorCodeEnum.getDescByCode(code) + "(" + code + ")"); } log.debug("鍒囨崲绾㈠鎴愬姛"); @@ -1848,6 +1831,9 @@ //鑾峰彇IP閫氶亾 public List<ArdChannel> getChannels(ArdCameras camera) { + if (camera.getLoginId().equals(-1)) { + return new ArrayList<>(); + } //鑾峰彇閫氶亾 List<ArdChannel> channelList = new ArrayList<>(); try { @@ -1856,19 +1842,19 @@ m_strIpparaCfg.write(); //lpIpParaConfig 鎺ユ敹鏁版嵁鐨勭紦鍐叉寚閽� Pointer lpIpParaConfig = m_strIpparaCfg.getPointer(); - boolean bRet = hCNetSDK.NET_DVR_GetDVRConfig(camera.getLoginId(), HCNetSDK.NET_DVR_GET_IPPARACFG_V40, 0, lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned); + boolean bRet = hCNetSDK.NET_DVR_GetDVRConfig(camera.getLoginId().intValue(), HCNetSDK.NET_DVR_GET_IPPARACFG_V40, 0, lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned); m_strIpparaCfg.read(); //log.debug("璧峰鏁板瓧閫氶亾鍙凤細" + m_strIpparaCfg.dwStartDChan);//m_strIpparaCfg.dwDChanNum for (int iChannum = 0; iChannum < camera.getChanNum(); iChannum++) { ArdChannel channel = new ArdChannel(); - int chanNo = iChannum + camera.getStartDChan(); + int chanNo = iChannum + camera.getStartChan(); HCNetSDK.NET_DVR_PICCFG_V40 strPicCfg = new HCNetSDK.NET_DVR_PICCFG_V40(); strPicCfg.dwSize = strPicCfg.size(); strPicCfg.write(); Pointer pStrPicCfg = strPicCfg.getPointer(); NativeLong lChannel = new NativeLong(chanNo); IntByReference pInt = new IntByReference(0); - boolean b_GetPicCfg = hCNetSDK.NET_DVR_GetDVRConfig(camera.getLoginId(), HCNetSDK.NET_DVR_GET_PICCFG_V40, lChannel.intValue(), pStrPicCfg, strPicCfg.size(), pInt); + boolean b_GetPicCfg = hCNetSDK.NET_DVR_GetDVRConfig(camera.getLoginId().intValue(), HCNetSDK.NET_DVR_GET_PICCFG_V40, lChannel.intValue(), pStrPicCfg, strPicCfg.size(), pInt); if (!b_GetPicCfg) { // log.error("鑾峰彇鍥惧儚鍙傛暟澶辫触锛岄敊璇爜锛�" + hCNetSDK.NET_DVR_GetLastError()); } @@ -1932,11 +1918,11 @@ } struGisInfo.read(); Map<String, Object> map = new HashMap<>(); - map.put("p" , struGisInfo.struPtzPos.fPanPos); - map.put("t" , struGisInfo.struPtzPos.fTiltPos < 0 ? struGisInfo.struPtzPos.fTiltPos + 360 : struGisInfo.struPtzPos.fTiltPos); - map.put("z" , struGisInfo.struPtzPos.fZoomPos); - map.put("fHorFieldAngle" , struGisInfo.fHorizontalValue);// 姘村钩瑙嗗満瑙� - map.put("fVerFieldAngle" , struGisInfo.fVerticalValue);// 鍨傜洿瑙嗗満瑙� + map.put("p", struGisInfo.struPtzPos.fPanPos); + map.put("t", struGisInfo.struPtzPos.fTiltPos < 0 ? struGisInfo.struPtzPos.fTiltPos + 360 : struGisInfo.struPtzPos.fTiltPos); + map.put("z", struGisInfo.struPtzPos.fZoomPos); + map.put("fHorFieldAngle", struGisInfo.fHorizontalValue);// 姘村钩瑙嗗満瑙� + map.put("fVerFieldAngle", struGisInfo.fVerticalValue);// 鍨傜洿瑙嗗満瑙� return AjaxResult.success(map); } @@ -1996,7 +1982,7 @@ return AjaxResult.warn("鏈湴褰曞儚鍙栨祦澶辫触:" + SdkErrorCodeEnum.getDescByCode(code) + "(" + code + ")"); } log.debug("鏈湴褰曞儚寮�濮�"); - return AjaxResult.success("褰曞儚寮�濮�" , lRealHandle); + return AjaxResult.success("褰曞儚寮�濮�", lRealHandle); } catch (Exception ex) { log.error("鏈湴褰曞儚寮�濮嬪紓甯�" + ex.getMessage()); return AjaxResult.error("鏈湴褰曞儚寮�濮嬪紓甯�" + ex.getMessage()); diff --git a/ard-work/src/main/resources/mapper/device/ArdCamerasMapper.xml b/ard-work/src/main/resources/mapper/device/ArdCamerasMapper.xml index 78083d2..318e511 100644 --- a/ard-work/src/main/resources/mapper/device/ArdCamerasMapper.xml +++ b/ard-work/src/main/resources/mapper/device/ArdCamerasMapper.xml @@ -15,6 +15,7 @@ <result property="gdtype" column="gdtype"/> <result property="factory" column="factory"/> <result property="chanNum" column="channel"/> + <result property="startChan" column="start_chan"/> <result property="longitude" column="longitude"/> <result property="latitude" column="latitude"/> <result property="altitude" column="altitude"/> @@ -48,6 +49,7 @@ c.gdtype, c.factory, c.channel, + c.start_chan, c.longitude, c.latitude, c.altitude, @@ -86,6 +88,7 @@ <if test="gdtype != null and gdtype != ''">and c.gdtype = #{gdtype}</if> <if test="factory != null and factory != ''">and c.factory = #{factory}</if> <if test="chanNum != null ">and c.channel = #{chanNum}</if> + <if test="startChan != null ">and c.start_chan = #{startChan}</if> <if test="longitude != null ">and c.longitude = #{longitude}</if> <if test="latitude != null ">and c.latitude = #{latitude}</if> <if test="altitude != null ">and c.altitude = #{altitude}</if> @@ -123,6 +126,7 @@ <if test="gdtype != null and gdtype != ''">and c.gdtype = #{gdtype}</if> <if test="factory != null and factory != ''">and c.factory = #{factory}</if> <if test="chanNum != null ">and c.channel = #{chanNum}</if> + <if test="startChan != null ">and c.start_chan= #{startChan}</if> <if test="longitude != null ">and c.longitude = #{longitude}</if> <if test="latitude != null ">and c.latitude = #{latitude}</if> <if test="altitude != null ">and c.altitude = #{altitude}</if> @@ -163,6 +167,7 @@ <if test="factory != null">factory,</if> <if test="towerId != null">tower_id,</if> <if test="chanNum != null">channel,</if> + <if test="startChan != null">start_chan,</if> <if test="longitude != null">longitude,</if> <if test="latitude != null">latitude,</if> <if test="altitude != null">altitude,</if> @@ -197,6 +202,7 @@ <if test="factory != null">#{factory},</if> <if test="towerId != null">#{towerId},</if> <if test="chanNum != null">#{chanNum},</if> + <if test="startChan != null">#{startChan},</if> <if test="longitude != null">#{longitude},</if> <if test="latitude != null">#{latitude},</if> <if test="altitude != null">#{altitude},</if> @@ -234,6 +240,7 @@ <if test="factory != null">factory = #{factory},</if> <if test="towerId != null">tower_id = #{towerId},</if> <if test="chanNum != null">channel = #{chanNum},</if> + <if test="startChan != null">start_chan = #{startChan},</if> <if test="longitude != null">longitude = #{longitude},</if> <if test="latitude != null">latitude = #{latitude},</if> <if test="altitude != null">altitude = #{altitude},</if> diff --git a/ard-work/src/main/resources/templates/test.html b/ard-work/src/main/resources/templates/test.html index 5623b4b..e805ee4 100644 --- a/ard-work/src/main/resources/templates/test.html +++ b/ard-work/src/main/resources/templates/test.html @@ -916,10 +916,32 @@ let webrtcClient; //whep鎿嶄綔鏂规硶 - const restartPause = 2000; + const retryPause = 2000; + + const video = document.getElementById('video'); + const message = document.getElementById('message'); + + let nonAdvertisedCodecs = []; + let pc = null; + let restartTimeout = null; + let sessionUrl = ''; + let offerData = ''; + let queuedCandidates = []; + let defaultControls = false; + + const setMessage = (str) => { + if (str !== '') { + video.controls = false; + } else { + video.controls = defaultControls; + } + message.innerText = str; + }; + const unquoteCredential = (v) => ( JSON.parse(`"${v}"`) ); + const linkToIceServers = (links) => ( (links !== null) ? links.split(', ').map((link) => { const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i); @@ -930,20 +952,21 @@ if (m[3] !== undefined) { ret.username = unquoteCredential(m[3]); ret.credential = unquoteCredential(m[4]); - ret.credentialType = "password"; + ret.credentialType = 'password'; } return ret; }) : [] ); - const parseOffer = (offer) => { + + const parseOffer = (sdp) => { const ret = { iceUfrag: '', icePwd: '', medias: [], }; - for (const line of offer.split('\r\n')) { + for (const line of sdp.split('\r\n')) { if (line.startsWith('m=')) { ret.medias.push(line.slice('m='.length)); } else if (ret.iceUfrag === '' && line.startsWith('a=ice-ufrag:')) { @@ -955,7 +978,131 @@ return ret; }; - const generateSdpFragment = (offerData, candidates) => { + + const enableStereoPcmau = (section) => { + let lines = section.split('\r\n'); + + lines[0] += ' 118'; + lines.splice(lines.length - 1, 0, 'a=rtpmap:118 PCMU/8000/2'); + lines.splice(lines.length - 1, 0, 'a=rtcp-fb:118 transport-cc'); + + lines[0] += ' 119'; + lines.splice(lines.length - 1, 0, 'a=rtpmap:119 PCMA/8000/2'); + lines.splice(lines.length - 1, 0, 'a=rtcp-fb:119 transport-cc'); + + return lines.join('\r\n'); + }; + + const enableMultichannelOpus = (section) => { + let lines = section.split('\r\n'); + + lines[0] += " 112"; + lines.splice(lines.length - 1, 0, "a=rtpmap:112 multiopus/48000/3"); + lines.splice(lines.length - 1, 0, "a=fmtp:112 channel_mapping=0,2,1;num_streams=2;coupled_streams=1"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:112 transport-cc"); + + lines[0] += " 113"; + lines.splice(lines.length - 1, 0, "a=rtpmap:113 multiopus/48000/4"); + lines.splice(lines.length - 1, 0, "a=fmtp:113 channel_mapping=0,1,2,3;num_streams=2;coupled_streams=2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:113 transport-cc"); + + lines[0] += " 114"; + lines.splice(lines.length - 1, 0, "a=rtpmap:114 multiopus/48000/5"); + lines.splice(lines.length - 1, 0, "a=fmtp:114 channel_mapping=0,4,1,2,3;num_streams=3;coupled_streams=2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:114 transport-cc"); + + lines[0] += " 115"; + lines.splice(lines.length - 1, 0, "a=rtpmap:115 multiopus/48000/6"); + lines.splice(lines.length - 1, 0, "a=fmtp:115 channel_mapping=0,4,1,2,3,5;num_streams=4;coupled_streams=2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:115 transport-cc"); + + lines[0] += " 116"; + lines.splice(lines.length - 1, 0, "a=rtpmap:116 multiopus/48000/7"); + lines.splice(lines.length - 1, 0, "a=fmtp:116 channel_mapping=0,4,1,2,3,5,6;num_streams=4;coupled_streams=4"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:116 transport-cc"); + + lines[0] += " 117"; + lines.splice(lines.length - 1, 0, "a=rtpmap:117 multiopus/48000/8"); + lines.splice(lines.length - 1, 0, "a=fmtp:117 channel_mapping=0,6,1,4,5,2,3,7;num_streams=5;coupled_streams=4"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:117 transport-cc"); + + return lines.join('\r\n'); + }; + + const enableL16 = (section) => { + let lines = section.split('\r\n'); + + lines[0] += " 120"; + lines.splice(lines.length - 1, 0, "a=rtpmap:120 L16/8000/2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:120 transport-cc"); + + lines[0] += " 121"; + lines.splice(lines.length - 1, 0, "a=rtpmap:121 L16/16000/2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:121 transport-cc"); + + lines[0] += " 122"; + lines.splice(lines.length - 1, 0, "a=rtpmap:122 L16/48000/2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:122 transport-cc"); + + return lines.join('\r\n'); + }; + + const enableStereoOpus = (section) => { + let opusPayloadFormat = ''; + let lines = section.split('\r\n'); + + for (let i = 0; i < lines.length; i++) { + if (lines[i].startsWith('a=rtpmap:') && lines[i].toLowerCase().includes('opus/')) { + opusPayloadFormat = lines[i].slice('a=rtpmap:'.length).split(' ')[0]; + break; + } + } + + if (opusPayloadFormat === '') { + return section; + } + + for (let i = 0; i < lines.length; i++) { + if (lines[i].startsWith('a=fmtp:' + opusPayloadFormat + ' ')) { + if (!lines[i].includes('stereo')) { + lines[i] += ';stereo=1'; + } + if (!lines[i].includes('sprop-stereo')) { + lines[i] += ';sprop-stereo=1'; + } + } + } + + return lines.join('\r\n'); + }; + + const editOffer = (sdp) => { + const sections = sdp.split('m='); + + for (let i = 0; i < sections.length; i++) { + if (sections[i].startsWith('audio')) { + sections[i] = enableStereoOpus(sections[i]); + + if (nonAdvertisedCodecs.includes('pcma/8000/2')) { + sections[i] = enableStereoPcmau(sections[i]); + } + + if (nonAdvertisedCodecs.includes('multiopus/48000/6')) { + sections[i] = enableMultichannelOpus(sections[i]); + } + + if (nonAdvertisedCodecs.includes('L16/48000/2')) { + sections[i] = enableL16(sections[i]); + } + + break; + } + } + + return sections.join('m='); + }; + + const generateSdpFragment = (od, candidates) => { const candidatesByMedia = {}; for (const candidate of candidates) { const mid = candidate.sdpMLineIndex; @@ -965,12 +1112,12 @@ candidatesByMedia[mid].push(candidate); } - let frag = 'a=ice-ufrag:' + offerData.iceUfrag + '\r\n' - + 'a=ice-pwd:' + offerData.icePwd + '\r\n'; + let frag = 'a=ice-ufrag:' + od.iceUfrag + '\r\n' + + 'a=ice-pwd:' + od.icePwd + '\r\n'; let mid = 0; - for (const media of offerData.medias) { + for (const media of od.medias) { if (candidatesByMedia[mid] !== undefined) { frag += 'm=' + media + '\r\n' + 'a=mid:' + mid + '\r\n'; @@ -983,174 +1130,269 @@ } return frag; - } + }; - class WHEPClient { - constructor(whepUrl, videoId) { - this.video = videoId; - this.wurl = new URL('whep', whepUrl); - this.pc = null; - this.restartTimeout = null; - this.eTag = ''; - this.queuedCandidates = []; - this.start(); - } + const loadStream = () => { + requestICEServers(); + }; - start() { - console.log("requesting ICE servers"); - fetch(this.wurl, { - method: 'OPTIONS', - }) - .then((res) => this.onIceServers(res)) + const supportsNonAdvertisedCodec = (codec, fmtp) => ( + new Promise((resolve, reject) => { + const pc = new RTCPeerConnection({ iceServers: [] }); + pc.addTransceiver('audio', { direction: 'recvonly' }); + pc.createOffer() + .then((offer) => { + if (offer.sdp.includes(' ' + codec)) { // codec is advertised, there's no need to add it manually + resolve(false); + return; + } + const sections = offer.sdp.split('m=audio'); + const lines = sections[1].split('\r\n'); + lines[0] += ' 118'; + lines.splice(lines.length - 1, 0, 'a=rtpmap:118 ' + codec); + if (fmtp !== undefined) { + lines.splice(lines.length - 1, 0, 'a=fmtp:118 ' + fmtp); + } + sections[1] = lines.join('\r\n'); + offer.sdp = sections.join('m=audio'); + return pc.setLocalDescription(offer); + }) + .then(() => { + return pc.setRemoteDescription(new RTCSessionDescription({ + type: 'answer', + sdp: 'v=0\r\n' + + 'o=- 6539324223450680508 0 IN IP4 0.0.0.0\r\n' + + 's=-\r\n' + + 't=0 0\r\n' + + 'a=fingerprint:sha-256 0D:9F:78:15:42:B5:4B:E6:E2:94:3E:5B:37:78:E1:4B:54:59:A3:36:3A:E5:05:EB:27:EE:8F:D2:2D:41:29:25\r\n' + + 'm=audio 9 UDP/TLS/RTP/SAVPF 118\r\n' + + 'c=IN IP4 0.0.0.0\r\n' + + 'a=ice-pwd:7c3bf4770007e7432ee4ea4d697db675\r\n' + + 'a=ice-ufrag:29e036dc\r\n' + + 'a=sendonly\r\n' + + 'a=rtcp-mux\r\n' + + 'a=rtpmap:118 ' + codec + '\r\n' + + ((fmtp !== undefined) ? 'a=fmtp:118 ' + fmtp + '\r\n' : ''), + })); + }) + .then(() => { + resolve(true); + }) .catch((err) => { - console.log('error: ' + err); - this.scheduleRestart(); + resolve(false); + }) + .finally(() => { + pc.close(); }); - } + }) + ); - onIceServers(res) { - this.pc = new RTCPeerConnection({ - iceServers: linkToIceServers(res.headers.get('Link')), + const getNonAdvertisedCodecs = () => { + Promise.all([ + ['pcma/8000/2'], + ['multiopus/48000/6', 'channel_mapping=0,4,1,2,3,5;num_streams=4;coupled_streams=2'], + ['L16/48000/2'] + ].map((c) => supportsNonAdvertisedCodec(c[0], c[1]).then((r) => (r) ? c[0] : false))) + .then((c) => c.filter((e) => e !== false)) + .then((codecs) => { + nonAdvertisedCodecs = codecs; + loadStream(); }); + }; - const direction = "sendrecv"; - this.pc.addTransceiver("video", {direction}); - this.pc.addTransceiver("audio", {direction}); + const onError = (err) => { + if (restartTimeout === null) { + setMessage(err + ', retrying in some seconds'); - this.pc.onicecandidate = (evt) => this.onLocalCandidate(evt); - this.pc.oniceconnectionstatechange = () => this.onConnectionState(); + if (pc !== null) { + pc.close(); + pc = null; + } - this.pc.ontrack = (evt) => { - console.log("new track:", evt.track.kind); - document.getElementById(this.video).srcObject = evt.streams[0]; - }; + restartTimeout = window.setTimeout(() => { + restartTimeout = null; + loadStream(); + }, retryPause); - this.pc.createOffer() - .then((offer) => this.onLocalOffer(offer)); - } - - onLocalOffer(offer) { - this.offerData = parseOffer(offer.sdp); - this.pc.setLocalDescription(offer); - - console.log("sending offer"); - console.log(this.wurl); - fetch(this.wurl, { - method: 'POST', - headers: { - 'Content-Type': 'application/sdp', - }, - body: offer.sdp, - }) - .then((res) => { - if (res.status !== 201) { - throw new Error('bad status code'); - } - // this.eTag = res.headers.get('ETag'); - this.eTag = res.headers.get("ETag") || res.headers.get('E-Tag'); - return res.text(); - }) - .then((sdp) => this.onRemoteAnswer(new RTCSessionDescription({ - type: 'answer', - sdp, - }))) - .catch((err) => { - console.log('error: ' + err); - this.scheduleRestart(); + if (sessionUrl) { + fetch(sessionUrl, { + method: 'DELETE', }); + } + sessionUrl = ''; + + queuedCandidates = []; } + }; - onConnectionState() { - if (this.restartTimeout !== null) { - return; - } - - console.log("peer connection state:", this.pc.iceConnectionState); - - switch (this.pc.iceConnectionState) { - case "disconnected": - this.scheduleRestart(); - } - } - - onRemoteAnswer(answer) { - if (this.restartTimeout !== null) { - return; - } - - this.pc.setRemoteDescription(new RTCSessionDescription(answer)); - - if (this.queuedCandidates.length !== 0) { - this.sendLocalCandidates(this.queuedCandidates); - this.queuedCandidates = []; - } - } - - onLocalCandidate(evt) { - if (this.restartTimeout !== null) { - return; - } - - if (evt.candidate !== null) { - if (this.eTag === '') { - this.queuedCandidates.push(evt.candidate); - } else { - this.sendLocalCandidates([evt.candidate]) + const sendLocalCandidates = (candidates) => { + fetch(sessionUrl + window.location.search, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/trickle-ice-sdpfrag', + 'If-Match': '*', + }, + body: generateSdpFragment(offerData, candidates), + }) + .then((res) => { + switch (res.status) { + case 204: + break; + case 404: + throw new Error('stream not found'); + default: + throw new Error(`bad status code ${res.status}`); } - } - } - - sendLocalCandidates(candidates) { - fetch(this.wurl, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/trickle-ice-sdpfrag', - 'If-Match': this.eTag, - }, - - body: generateSdpFragment(this.offerData, candidates), }) - .then((res) => { - if (res.status !== 204) { - throw new Error('bad status code'); - } - }) - .catch((err) => { - console.log('error: ' + err); - this.scheduleRestart(); - }); + .catch((err) => { + onError(err.toString()); + }); + }; + + const onLocalCandidate = (evt) => { + if (restartTimeout !== null) { + return; } - scheduleRestart() { - if (this.restartTimeout !== null) { - return; + if (evt.candidate !== null) { + if (sessionUrl === '') { + queuedCandidates.push(evt.candidate); + } else { + sendLocalCandidates([evt.candidate]) } + } + }; - if (this.pc !== null) { - this.pc.close(); - this.pc = null; - } - - this.restartTimeout = window.setTimeout(() => { - this.restartTimeout = null; - this.start(); - }, restartPause); - - this.eTag = ''; - this.queuedCandidates = []; + const onRemoteAnswer = (sdp) => { + if (restartTimeout !== null) { + return; } - stop() { - if (this.pc) { - try { - this.pc.close(); - } catch (e) { - console.log("Failure close peer connection:" + e); + pc.setRemoteDescription(new RTCSessionDescription({ + type: 'answer', + sdp, + })) + .then(() => { + if (queuedCandidates.length !== 0) { + sendLocalCandidates(queuedCandidates); + queuedCandidates = []; } - this.pc = null; - } + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const sendOffer = (offer) => { + fetch(new URL('whep', window.location.href) + window.location.search, { + method: 'POST', + headers: { + 'Content-Type': 'application/sdp', + }, + body: offer.sdp, + }) + .then((res) => { + switch (res.status) { + case 201: + break; + case 404: + throw new Error('stream not found'); + case 400: + return res.json().then((e) => { throw new Error(e.error); }); + default: + throw new Error(`bad status code ${res.status}`); + } + + sessionUrl = new URL(res.headers.get('location'), window.location.href).toString(); + + return res.text() + .then((sdp) => onRemoteAnswer(sdp)); + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const createOffer = () => { + pc.createOffer() + .then((offer) => { + offer.sdp = editOffer(offer.sdp); + offerData = parseOffer(offer.sdp); + pc.setLocalDescription(offer) + .then(() => { + sendOffer(offer); + }) + .catch((err) => { + onError(err.toString()); + }); + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const onConnectionState = () => { + if (restartTimeout !== null) { + return; } - } + + if (pc.iceConnectionState === 'disconnected') { + onError('peer connection closed'); + } + }; + + const onTrack = (evt) => { + setMessage(''); + video.srcObject = evt.streams[0]; + }; + + const requestICEServers = () => { + fetch(new URL('whep', window.location.href) + window.location.search, { + method: 'OPTIONS', + }) + .then((res) => { + pc = new RTCPeerConnection({ + iceServers: linkToIceServers(res.headers.get('Link')), + // https://webrtc.org/getting-started/unified-plan-transition-guide + sdpSemantics: 'unified-plan', + }); + + const direction = 'sendrecv'; + pc.addTransceiver('video', { direction }); + pc.addTransceiver('audio', { direction }); + + pc.onicecandidate = (evt) => onLocalCandidate(evt); + pc.oniceconnectionstatechange = () => onConnectionState(); + pc.ontrack = (evt) => onTrack(evt); + + createOffer(); + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const parseBoolString = (str, defaultVal) => { + str = (str || ''); + + if (['1', 'yes', 'true'].includes(str.toLowerCase())) { + return true; + } + if (['0', 'no', 'false'].includes(str.toLowerCase())) { + return false; + } + return defaultVal; + }; + + const loadAttributesFromQuery = () => { + const params = new URLSearchParams(window.location.search); + video.controls = parseBoolString(params.get('controls'), true); + video.muted = parseBoolString(params.get('muted'), true); + video.autoplay = parseBoolString(params.get('autoplay'), true); + video.playsInline = parseBoolString(params.get('playsinline'), true); + defaultControls = video.controls; + }; + function realView(whepUrl, videoId) { console.log(whepUrl) diff --git a/ard-work/src/main/resources/templates/test1.html b/ard-work/src/main/resources/templates/test1.html new file mode 100644 index 0000000..5623b4b --- /dev/null +++ b/ard-work/src/main/resources/templates/test1.html @@ -0,0 +1,1161 @@ +<!DOCTYPE html> +<html lang="en" xmlns:th="http://www.thymeleaf.org"> +<head> + <meta charset="UTF-8"> + <title>娴嬭瘯椤�</title> + <script th:src="@{/js/jquery-3.6.4.min.js}"></script> + <link rel="stylesheet" th:href="@{/css/bootstrap.css}"/> + <script th:src="@{/js/bootstrap.js}"></script> + <style> + .top-buffer { + margin-top: 10px; + } + .container { + border: 2px solid #1b6d85; + padding: 15px; + } + </style> +<body> +<div class="container"> + <div class="row"> + <div class="col-md-5"> + <div class="row top-buffer"> + 璁惧锛�<select id="selectDev" style="width: 330px;"> + </select> + </div> + <div class="row top-buffer"> + 閫氶亾锛�<select id="selectChn" style="width: 330px;"> + </select> + </div> + <div class="row top-buffer"> + <div class="col-md-1 col-md-offset-1"> + <button id="up" type="button" class="btn btn-primary">涓�</button> + </div> + <div class="col-md-6 col-md-offset-2"> + <div class="btn-group" role="group"> + <button id="controlZoomIn" type="button" class="btn btn-primary">璋冪劍-</button> + <button id="controlZoomOut" type="button" class="btn btn-primary">璋冪劍+</button> + </div> + </div> + </div> + <div class="row "> + <div class="col-md-1"> + <button id="left" type="button" class="btn btn-primary">宸�</button> + </div> + <div class="col-md-1 col-md-offset-1"> + <button id="right" type="button" class="btn btn-primary">鍙�</button> + </div> + <div class="col-md-6 col-md-offset-1"> + <div class="btn-group" role="group"> + <button id="controlFocusNear" type="button" class="btn btn-primary">鑱氱劍-</button> + <button id="controlFocusFar" type="button" class="btn btn-primary">鑱氱劍+</button> + </div> + </div> + </div> + <div class="row "> + <div class="col-md-1 col-md-offset-1"> + <button id="down" type="button" class="btn btn-primary">涓�</button> + </div> + <div class="col-md-6 col-md-offset-2"> + <div class="btn-group" role="group"> + <button id="controlIrisOpen" type="button" class="btn btn-primary">鍏夊湀-</button> + <button id="controlIrisClose" type="button" class="btn btn-primary">鍏夊湀+</button> + </div> + </div> + </div> + <div class="row "> + <div class="col-md-10"> + <div class="row top-buffer"> + <div class="input-group"> + <span class="input-group-addon">鐩殑鍧愭爣鍊硷細</span> + <input id="targetPostion" class="form-control" placeholder="鐩殑鍧愭爣"/> + <button id="setTargetPostion" type="button" class="btn btn-default">鎸囧悜鍧愭爣</button> + </div> + <div class="input-group"> + <span class="input-group-addon">P鍊硷細</span> + <input id="p" class="form-control" placeholder="璇疯緭鍏鍊�"/> + </div> + <div class="input-group"> + <span class="input-group-addon">T鍊硷細</span> + <input id="t" class="form-control" placeholder="璇疯緭鍏鍊�"/> + </div> + <div class="input-group"> + <span class="input-group-addon">Z鍊硷細</span> + <input id="z" class="form-control" placeholder="璇疯緭鍏鍊�"/> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="getPTZ" type="button" class="btn btn-default">鑾峰彇ptz</button> + <button id="setPTZ" type="button" class="btn btn-default">璁剧疆ptz</button> + <button id="setPreset" type="button" class="btn btn-default">璁鹃缃偣</button> + <button id="gotoPreset" type="button" class="btn btn-default">璋冮缃偣</button> + <button id="setZeroPTZ" type="button" class="btn btn-default">璁剧疆闆舵柟浣嶈</button> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="FocusMode" type="button" class="btn btn-default">鎵嬪姩鑱氱劍</button> + <div id="focusDiv" class="input-group"> + <span class="input-group-addon">鑱氱劍鍊硷細</span> + <input id="focus" class="form-control" placeholder="鑱氱劍鍊�"/> + </div> + <button id="getFocusPos" type="button" class="btn btn-default">鑾峰彇鑱氱劍鍊�</button> + <button id="setFocusPos" type="button" class="btn btn-default">璁剧疆鑱氱劍鍊�</button> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="WiperPwron" type="button" class="btn btn-default">寮�鍚洦鍒�</button> + <button id="Defogcfg" type="button" class="btn btn-default">寮�鍚�忛浘</button> + <button id="Infrarecfg" type="button" class="btn btn-default">寮�鍚孩澶�</button> + <button id="HeateRpwron" type="button" class="btn btn-default">寮�鍚簯鍙板姞鐑�</button> + <button id="CameraDeicing" type="button" class="btn btn-default">寮�鍚暅澶村姞鐑�</button> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="voice" type="button" class="btn btn-default">寮�濮嬭闊冲璁�</button> + <button id="record" type="button" class="btn btn-default">寮�濮嬪綍鍍�</button> + <button id="saveCutPic" type="button" class="btn btn-default">瀛樺偍鎶撳浘</button> + </div> + </div> + </div> + </div> + </div> + <div class="col-md-6"> + <div class="row"> + <div class="row top-buffer"> + <button id="preview" type="button" class="btn btn-primary">棰勮</button> + <button id="previewStop" type="button" class="btn btn-primary">鍋滄</button> + </div> + <div class="row top-buffer"> + <video id="video" muted autoplay loop controls + style="width: 100%; height: 360px; object-fit: fill; border: 2px solid #3498db;"/> + </div> + <div class="row"> + <img class="thumbnail" id="imgContainer" + style="width: 100%; height: 360px; border: 2px solid #3498db;"/> + </div> + </div> + </div> + </div> +</div> +<script th:inline="javascript"> + var cameraId, chanNo,opt, optOpen, optClose, token; + window.onload = function () { + console.log(RTCRtpReceiver.getCapabilities('video').codecs) + opt = {"username": "admin", "password": "admin123"}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + url: "../login", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + token = data.token; + getDeviceList();// 鑾峰彇璁惧鍒楄〃 + } + }) + // 鍒濆鍖栧唴瀹� + console.log(cameraMap); + } + + //鑾峰彇璁惧 + function getDeviceList() { + $.ajax({ + url: "../cameraSdk/list", + type: "get", + success: function (data) { + console.log(data); + var arr = data.data; + for (var i = 0; i < arr.length; i++) { + console.log(arr[i].id); + console.log(arr[i].name) + var camera = { + name: arr[i].name, + factory: arr[i].factory, + ipaddr: arr[i].ip, + username: arr[i].username, + password: arr[i].password, + port: arr[i].rtspPort, + longitude: arr[i].longitude, + latitude: arr[i].latitude, + altitude: arr[i].altitude + }; + cameraMap.set(arr[i].id, camera); + //鍏堝垱寤哄ソselect閲岄潰鐨刼ption鍏冪礌 + var option = $("<option>"); + //缁檕ption鐨則ext璧嬪��,杩欏氨鏄綘鐐瑰紑涓嬫媺妗嗚兘澶熺湅鍒扮殑涓滆タ + $(option).val(arr[i].id); + $(option).text(arr[i].name); + //鑾峰彇select 涓嬫媺妗嗗璞�,骞跺皢option娣诲姞杩泂elect + $('#selectDev').append(option); + } + $("#selectDev").trigger("change"); + } + }) + } + + //閫夋嫨璁惧 + $("#selectDev").change(function () { + // 鍦ㄨ繖閲屽鐞嗛�夋嫨浜嬩欢 + var cameraId = $(this).find("option:selected").val(); + var name = $(this).find("option:selected").text(); + getChannelList(cameraId); + console.log("閫夋嫨浜嗭細" + cameraId + "---" + name); + }); + + //鑾峰彇閫氶亾 + function getChannelList(cameraId) { + console.log(cameraId) + var myEntity = { + deviceId: cameraId, + pageNum: 1, + pageSize: 64 + } + var queryString = $.param(myEntity); + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../device/channel/list?" + queryString, + type: "get", + success: function (data) { + console.log(data); + var arr = data.rows; + $('#selectChn').empty(); + for (var i = 0; i < arr.length; i++) { + console.log(arr[i].chanNo); + console.log(arr[i].name); + //鍏堝垱寤哄ソselect閲岄潰鐨刼ption鍏冪礌 + var option = document.createElement("option"); + //缁檕ption鐨則ext璧嬪��,杩欏氨鏄綘鐐瑰紑涓嬫媺妗嗚兘澶熺湅鍒扮殑涓滆タ + $(option).text(arr[i].name); + $(option).val(arr[i].chanNo); + //鑾峰彇select 涓嬫媺妗嗗璞�,骞跺皢option娣诲姞杩泂elect + $('#selectChn').append(option); + } + } + }) + } + + //棰勮 + $('#preview').click(() => { + var cameraId = $('#selectDev option:selected').val(); + var chanNo = $('#selectChn option:selected').val(); + console.log(cameraId + " " + chanNo) + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../vtdu/media/" + cameraId + "_" + chanNo, + type: "get", + dataType: "json", + success: function (data) { + realView(data.data.webrtcUrl + "/", "video"); + } + }) + }); + //鍋滄 + $('#previewStop').click(() => { + webrtcClient.stop(); + }); + //浜戝彴涓婁笅宸﹀彸 + $("#up").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 2; + var enable = true; + commondMethod(url, code, enable); + + }) + $("#up").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 2; + var enable = false; + commondMethod(url, code, enable); + }) + $("#down").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 8; + var enable = true; + commondMethod(url, code, enable); + }) + $("#down").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 8; + var enable = false; + commondMethod(url, code, enable); + }) + $("#left").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 4; + var enable = true; + commondMethod(url, code, enable); + }) + $("#left").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 4; + var enable = false; + commondMethod(url, code, enable); + }) + $("#right").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 6; + var enable = true; + commondMethod(url, code, enable); + }) + $("#right").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 6; + var enable = false; + commondMethod(url, code, enable); + }) + //鍙樺�� + $("#controlZoomIn").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 10; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlZoomIn").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 10; + var enable = false; + commondMethod(url, code, enable); + }) + $("#controlZoomOut").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 11; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlZoomOut").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 11; + var enable = false; + commondMethod(url, code, enable); + }) + //鍙樼劍 + $("#controlFocusNear").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 12; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlFocusNear").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 12; + var enable = false; + commondMethod(url, code, enable); + }) + $("#controlFocusFar").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 13; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlFocusFar").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 13; + var enable = false; + commondMethod(url, code, enable); + }) + //鍏夊湀 + $("#controlIrisOpen").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 14; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlIrisOpen").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 14; + var enable = false; + commondMethod(url, code, enable); + }) + $("#controlIrisClose").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 15; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlIrisClose").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 15; + var enable = false; + commondMethod(url, code, enable); + }) + + $("#setPreset").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 8, "presetIndex": 1}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/setPreset", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + console.log(data); + } + }) + }) + $("#gotoPreset").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 8, "presetIndex": 1}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/gotoPreset", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + console.log(data); + } + }) + }) + $("#getPTZ").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/getPTZ", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (datas) { + console.log(datas); + $("#p").val(datas.data.p); + $("#t").val(datas.data.t); + $("#z").val(datas.data.z); + } + }) + }) + $("#setPTZ").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + var p = $('#p').val(); + var t = $('#t').val(); + var z = $('#z').val(); + //瀹氫箟涓�涓甫鏈塎ap瀛楁鐨勫疄浣撳璞� + var myEntity = { + chanNo: chanNo, + cameraId: cameraId, + ptzMap: { + p: p, + t: t, + z: z + } + }; + console.log(opt) + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/setPTZ", + type: "post", + dataType: "json", + data: JSON.stringify(myEntity), + success: function (data) { + console.log(data); + } + }) + }) + $("#setTargetPostion").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + var camera = cameraMap.get(cameraId); + var camP = camera.longitude + ',' + camera.latitude + ',' + camera.altitude; + var targetP = $('#targetPostion').val(); + var arr = targetP.split(","); + arr = arr.map(item => parseFloat(item)); + //瀹氫箟涓�涓甫鏈塎ap瀛楁鐨勫疄浣撳璞� + var myEntity = { + chanNo: chanNo, + cameraId: cameraId, + targetPosition: arr + }; + console.log(myEntity) + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/setTargetPosition", + type: "post", + dataType: "json", + data: JSON.stringify(myEntity), + success: function (data) { + console.log(data); + } + }) + }) + $("#setZeroPTZ").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/setZeroPTZ", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + console.log(data); + } + }) + }) + $("#WiperPwron").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 8, "enable": true, "code": 16}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/PTZControlWithSpeed", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + console.log(data); + } + }) + }) + var defogflag = true; + $("#Defogcfg").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; + if (defogflag) { + $(this).text("鍏抽棴閫忛浘"); + defogflag = false; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/defogcfg", + type: "post", + dataType: "json", + data: JSON.stringify(optOpen), + success: function (data) { + console.log(data); + } + }) + } else { + $(this).text("寮�鍚�忛浘"); + defogflag = true; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/defogcfg", + type: "post", + dataType: "json", + data: JSON.stringify(optClose), + success: function (data) { + console.log(data); + } + }) + } + + }) + var infrareflag = true; + $("#Infrarecfg").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; + if (infrareflag) { + $(this).text("鍏抽棴绾㈠"); + infrareflag = false; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/infrarecfg", + type: "post", + dataType: "json", + data: JSON.stringify(optOpen), + success: function (data) { + console.log(data); + } + }) + } else { + + $(this).text("寮�鍚孩澶�"); + infrareflag = true; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/infrarecfg", + type: "post", + dataType: "json", + data: JSON.stringify(optClose), + success: function (data) { + console.log(data); + } + }) + } + }) + var focusModeflag = true; + $("#FocusMode").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; + if (focusModeflag) { + $(this).text("鑷姩鑱氱劍"); + focusModeflag = false; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/focusMode", + type: "post", + dataType: "json", + data: JSON.stringify(optOpen), + success: function (data) { + console.log(data); + } + }) + } else { + $(this).text("鎵嬪姩鑱氱劍"); + focusModeflag = true; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/focusMode", + type: "post", + dataType: "json", + data: JSON.stringify(optClose), + success: function (data) { + console.log(data); + } + }) + } + }) + $("#getFocusPos").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/getFocusPos", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (datas) { + console.log(datas); + $("#focus").val(datas.data); + } + }) + }) + var heateRpwronflag = true; + $("#HeateRpwron").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; + if (heateRpwronflag) { + $(this).text("鍏抽棴浜戝彴鍔犵儹"); + heateRpwronflag = false; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/heateRpwron", + type: "post", + dataType: "json", + data: JSON.stringify(optOpen), + success: function (data) { + console.log(data); + } + }) + } else { + $(this).text("寮�鍚簯鍙板姞鐑�"); + heateRpwronflag = true; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/heateRpwron", + type: "post", + dataType: "json", + data: JSON.stringify(optClose), + success: function (data) { + console.log(data); + } + }) + } + }) + var CameraDeicingflag = true; + $("#CameraDeicing").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; + if (CameraDeicingflag) { + $(this).text("鍏抽棴闀滃ご鍔犵儹"); + CameraDeicingflag = false; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/cameraDeicing", + type: "post", + dataType: "json", + data: JSON.stringify(optOpen), + success: function (data) { + console.log(data); + } + }) + } else { + $(this).text("寮�鍚暅澶村姞鐑�"); + CameraDeicingflag = true; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/cameraDeicing", + type: "post", + dataType: "json", + data: JSON.stringify(optClose), + success: function (data) { + console.log(data); + } + }) + } + }) + $("#realCutPic").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/captureJPEGPicture", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + console.log(data.data); + $("#imgContainer").attr("src", "data:image/png;base64," + data.data); + } + }) + }) + $("#saveCutPic").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/picCutCate", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + console.log(data.data); + setTimeout(() => { + $('#imgContainer').attr('src', data.data); + }, 1000) + + } + }) + }) + var recordflag = true; + $("#record").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; + if (recordflag) { + $(this).text("鍋滄褰曞儚"); + recordflag = false; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/record", + type: "post", + dataType: "json", + data: JSON.stringify(optOpen), + success: function (data) { + console.log(data); + } + }) + } else { + $(this).text("寮�濮嬪綍鍍�"); + recordflag = true; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/record", + dataType: "json", + data: JSON.stringify(optClose), + type: "post", + success: function (data) { + console.log(data); + } + }) + } + }) + + var cameraMap = new Map(); + + /*浜戝彴鍏叡鏂规硶*/ + function commondMethod(url, code, enable) { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 4, "enable": enable, "code": code}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: url, + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (data) { + console.log(data); + } + }) + } + + $('video').click(function (e) { + var cameraId = $('#selectDev option:selected').val(); + var chanNo = $('#selectChn option:selected').val(); + console.log(cameraId + " " + chanNo) + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../vtdu/media/" + cameraId + "_" + chanNo, + type: "get", + dataType: "json", + success: function (data) { + realView(data.data.webrtcUrl + "/", e.target.id); + } + }) + }); + + let webrtcClient; + //whep鎿嶄綔鏂规硶 + const restartPause = 2000; + const unquoteCredential = (v) => ( + JSON.parse(`"${v}"`) + ); + const linkToIceServers = (links) => ( + (links !== null) ? links.split(', ').map((link) => { + const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i); + const ret = { + urls: [m[1]], + }; + + if (m[3] !== undefined) { + ret.username = unquoteCredential(m[3]); + ret.credential = unquoteCredential(m[4]); + ret.credentialType = "password"; + } + + return ret; + }) : [] + ); + const parseOffer = (offer) => { + const ret = { + iceUfrag: '', + icePwd: '', + medias: [], + }; + + for (const line of offer.split('\r\n')) { + if (line.startsWith('m=')) { + ret.medias.push(line.slice('m='.length)); + } else if (ret.iceUfrag === '' && line.startsWith('a=ice-ufrag:')) { + ret.iceUfrag = line.slice('a=ice-ufrag:'.length); + } else if (ret.icePwd === '' && line.startsWith('a=ice-pwd:')) { + ret.icePwd = line.slice('a=ice-pwd:'.length); + } + } + + return ret; + }; + const generateSdpFragment = (offerData, candidates) => { + const candidatesByMedia = {}; + for (const candidate of candidates) { + const mid = candidate.sdpMLineIndex; + if (candidatesByMedia[mid] === undefined) { + candidatesByMedia[mid] = []; + } + candidatesByMedia[mid].push(candidate); + } + + let frag = 'a=ice-ufrag:' + offerData.iceUfrag + '\r\n' + + 'a=ice-pwd:' + offerData.icePwd + '\r\n'; + + let mid = 0; + + for (const media of offerData.medias) { + if (candidatesByMedia[mid] !== undefined) { + frag += 'm=' + media + '\r\n' + + 'a=mid:' + mid + '\r\n'; + + for (const candidate of candidatesByMedia[mid]) { + frag += 'a=' + candidate.candidate + '\r\n'; + } + } + mid++; + } + + return frag; + } + + class WHEPClient { + constructor(whepUrl, videoId) { + this.video = videoId; + this.wurl = new URL('whep', whepUrl); + this.pc = null; + this.restartTimeout = null; + this.eTag = ''; + this.queuedCandidates = []; + this.start(); + } + + start() { + console.log("requesting ICE servers"); + fetch(this.wurl, { + method: 'OPTIONS', + }) + .then((res) => this.onIceServers(res)) + .catch((err) => { + console.log('error: ' + err); + this.scheduleRestart(); + }); + } + + onIceServers(res) { + this.pc = new RTCPeerConnection({ + iceServers: linkToIceServers(res.headers.get('Link')), + }); + + const direction = "sendrecv"; + this.pc.addTransceiver("video", {direction}); + this.pc.addTransceiver("audio", {direction}); + + this.pc.onicecandidate = (evt) => this.onLocalCandidate(evt); + this.pc.oniceconnectionstatechange = () => this.onConnectionState(); + + this.pc.ontrack = (evt) => { + console.log("new track:", evt.track.kind); + document.getElementById(this.video).srcObject = evt.streams[0]; + }; + + this.pc.createOffer() + .then((offer) => this.onLocalOffer(offer)); + } + + onLocalOffer(offer) { + this.offerData = parseOffer(offer.sdp); + this.pc.setLocalDescription(offer); + + console.log("sending offer"); + console.log(this.wurl); + fetch(this.wurl, { + method: 'POST', + headers: { + 'Content-Type': 'application/sdp', + }, + body: offer.sdp, + }) + .then((res) => { + if (res.status !== 201) { + throw new Error('bad status code'); + } + // this.eTag = res.headers.get('ETag'); + this.eTag = res.headers.get("ETag") || res.headers.get('E-Tag'); + return res.text(); + }) + .then((sdp) => this.onRemoteAnswer(new RTCSessionDescription({ + type: 'answer', + sdp, + }))) + .catch((err) => { + console.log('error: ' + err); + this.scheduleRestart(); + }); + } + + onConnectionState() { + if (this.restartTimeout !== null) { + return; + } + + console.log("peer connection state:", this.pc.iceConnectionState); + + switch (this.pc.iceConnectionState) { + case "disconnected": + this.scheduleRestart(); + } + } + + onRemoteAnswer(answer) { + if (this.restartTimeout !== null) { + return; + } + + this.pc.setRemoteDescription(new RTCSessionDescription(answer)); + + if (this.queuedCandidates.length !== 0) { + this.sendLocalCandidates(this.queuedCandidates); + this.queuedCandidates = []; + } + } + + onLocalCandidate(evt) { + if (this.restartTimeout !== null) { + return; + } + + if (evt.candidate !== null) { + if (this.eTag === '') { + this.queuedCandidates.push(evt.candidate); + } else { + this.sendLocalCandidates([evt.candidate]) + } + } + } + + sendLocalCandidates(candidates) { + fetch(this.wurl, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/trickle-ice-sdpfrag', + 'If-Match': this.eTag, + }, + + body: generateSdpFragment(this.offerData, candidates), + }) + .then((res) => { + if (res.status !== 204) { + throw new Error('bad status code'); + } + }) + .catch((err) => { + console.log('error: ' + err); + this.scheduleRestart(); + }); + } + + scheduleRestart() { + if (this.restartTimeout !== null) { + return; + } + + if (this.pc !== null) { + this.pc.close(); + this.pc = null; + } + + this.restartTimeout = window.setTimeout(() => { + this.restartTimeout = null; + this.start(); + }, restartPause); + + this.eTag = ''; + this.queuedCandidates = []; + } + + stop() { + if (this.pc) { + try { + this.pc.close(); + } catch (e) { + console.log("Failure close peer connection:" + e); + } + this.pc = null; + } + } + } + + function realView(whepUrl, videoId) { + console.log(whepUrl) + webrtcClient = new WHEPClient(whepUrl, videoId); + } +</script> +</body> +</html> diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java index 4e7d4ff..0b089e4 100644 --- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java @@ -84,28 +84,24 @@ /** * @Author 鍒樿嫃涔� - * @Description 鍚屾nvr閫氶亾鐘舵�佸疄鏃跺悓姝ユ祦濯掍綋 + * @Description 鍚屾閫氶亾鐘舵�佸疄鏃跺悓姝ユ祦濯掍綋 * @Date 2024/7/9 16:01 */ - public void nvrChannelState() { + public void syncChannelState() { + log.warn("瀹氭椂鍚屾閫氶亾浠诲姟寮�濮�"); //鑾峰彇鎵�鏈塶vr璁惧 List<ArdCameras> ardCamerasList = iArdCamerasService.selectArdCamerasListNoDataScope(new ArdCameras()); if (ardCamerasList.size() > 0) { ardCamerasList.stream() - .filter(ardCameras -> ardCameras.getGdtype().equals("2")) .forEach(ardCameras -> { - //閫氳繃SDK鑾峰彇NVR褰撳墠閫氶亾 + //閫氳繃SDK鑾峰彇NVR瀹為檯閫氶亾 CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(ardCameras.getFactory()); List<ArdChannel> ardChannelList = cameraSDK.getChannels(ardCameras); //鍚屾閫氶亾琛� ArdChannel ardChannel=new ArdChannel(); ardChannel.setDeviceId(ardCameras.getId()); List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel); - ardChannelService.asyncChannel(ardChannelListDb,ardChannelList); - //鍚屾娴佸獟浣撹〃 - - //鍚屾娴佸獟浣揳pi - + ardChannelService.asyncChannel(ardCameras,ardChannelListDb,ardChannelList); }); } } @@ -142,9 +138,10 @@ * 鍒樿嫃涔� * 2023/10/13 14:13:53 */ - public void vtdu() { + public void syncVtdu() { + log.warn("瀹氭椂鍚屾娴佸獟浣撲换鍔″紑濮�"); List<String> nameList = mediaService.getNameList(); List<Vtdu> vtduList = vtduService.selectVtduList(new Vtdu()); vtduService.asyncVtdu(vtduList,nameList); } -} +} \ No newline at end of file diff --git a/server/mediamtx/mediamtx.yml b/server/mediamtx/mediamtx.yml index cbe09e8..81ca38d 100644 --- a/server/mediamtx/mediamtx.yml +++ b/server/mediamtx/mediamtx.yml @@ -225,17 +225,17 @@ 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: [] +webrtcICEHostNAT1To1IPs: [192.168.1.227] # 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: +webrtcICEUDPMuxAddress: :8189 # 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:19302 +webrtcICETCPMuxAddress: ############################################### # Global settings -> SRT -- Gitblit v1.9.3