From 3b4a6018cb53fc1f8a36b092267e7b263a3648f4 Mon Sep 17 00:00:00 2001 From: lin <648540858@qq.com> Date: Wed, 16 Apr 2025 18:07:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=91=E7=AB=AF=E5=BD=95?= =?UTF-8?q?=E5=83=8Fseek=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/conf/UserSetting.java | 2 +- .../iot/vmp/media/bean/RecordInfo.java | 66 +------------------ .../service/IMediaNodeServerService.java | 4 +- .../media/service/IMediaServerService.java | 4 +- .../service/impl/MediaServerServiceImpl.java | 8 +-- .../vmp/media/zlm/ZLMHttpHookListener.java | 1 - .../media/zlm/ZLMMediaNodeServerService.java | 8 +-- .../iot/vmp/media/zlm/ZLMRESTfulUtils.java | 1 - .../iot/vmp/service/ICloudRecordService.java | 4 +- .../service/impl/CloudRecordServiceImpl.java | 23 +++---- .../cloudRecord/CloudRecordController.java | 23 ++++--- .../vmanager/user/UserApiKeyController.java | 6 +- src/main/resources/配置详情.yml | 4 ++ zlm.md | 16 +++++ 14 files changed, 67 insertions(+), 103 deletions(-) create mode 100644 zlm.md diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java index c4f2c4bae..8c064f409 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java @@ -178,7 +178,7 @@ public class UserSetting { /** * 登录超时时间(分钟), */ - private long loginTimeout = 30; + private long loginTimeout = 60; /** * jwk文件路径,若不指定则使用resources目录下的jwk.json diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java b/src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java index 399645708..35b023f78 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java @@ -1,7 +1,9 @@ package com.genersoft.iot.vmp.media.bean; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; +import lombok.Data; +@Data public class RecordInfo { private String fileName; private String filePath; @@ -24,70 +26,6 @@ public class RecordInfo { return recordInfo; } - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - - public String getFilePath() { - return filePath; - } - - public void setFilePath(String filePath) { - this.filePath = filePath; - } - - public long getFileSize() { - return fileSize; - } - - public void setFileSize(long fileSize) { - this.fileSize = fileSize; - } - - public String getFolder() { - return folder; - } - - public void setFolder(String folder) { - this.folder = folder; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public long getStartTime() { - return startTime; - } - - public void setStartTime(long startTime) { - this.startTime = startTime; - } - - public double getTimeLen() { - return timeLen; - } - - public void setTimeLen(double timeLen) { - this.timeLen = timeLen; - } - - public String getParams() { - return params; - } - - public void setParams(String params) { - this.params = params; - } - @Override public String toString() { return "RecordInfo{" + diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java index 074e47f2c..e3256d18e 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java @@ -72,7 +72,7 @@ public interface IMediaNodeServerService { void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath); - void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp); + void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp, String schema); - void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed); + void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed, String schema); } diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java index f87ba10c5..4eda22704 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java @@ -162,7 +162,7 @@ public interface IMediaServerService { StreamInfo loadMP4File(MediaServer mediaServer, String app, String stream, String datePath); - void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp); + void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp, String schema); - void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed); + void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed, String schema); } diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java index 3f3b00ae9..8d4ef0a5c 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java @@ -983,22 +983,22 @@ public class MediaServerServiceImpl implements IMediaServerService { } @Override - public void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp) { + public void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp, String schema) { IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType()); if (mediaNodeServerService == null) { log.info("[seekRecordStamp] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType()); throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类"); } - mediaNodeServerService.seekRecordStamp(mediaServer, app, stream, stamp); + mediaNodeServerService.seekRecordStamp(mediaServer, app, stream, stamp, schema); } @Override - public void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed) { + public void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed, String schema) { IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType()); if (mediaNodeServerService == null) { log.info("[setRecordSpeed] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType()); throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类"); } - mediaNodeServerService.setRecordSpeed(mediaServer, app, stream, speed); + mediaNodeServerService.setRecordSpeed(mediaServer, app, stream, speed, schema); } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index b6a8b5fbd..399d4cac7 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -126,7 +126,6 @@ public class ZLMHttpHookListener { @ResponseBody @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) { - MediaServer mediaServer = mediaServerService.getOne(param.getMediaServerId()); if (mediaServer == null) { return HookResult.SUCCESS(); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java index 69814c2bb..6786404aa 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java @@ -562,8 +562,8 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { } @Override - public void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp) { - JSONObject jsonObject = zlmresTfulUtils.seekRecordStamp(mediaServer, app, stream, stamp, "ts"); + public void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp, String schema) { + JSONObject jsonObject = zlmresTfulUtils.seekRecordStamp(mediaServer, app, stream, stamp, schema); if (jsonObject == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "请求失败"); } @@ -573,8 +573,8 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { } @Override - public void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed) { - JSONObject jsonObject = zlmresTfulUtils.setRecordSpeed(mediaServer, app, stream, speed, "ts"); + public void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed, String schema) { + JSONObject jsonObject = zlmresTfulUtils.setRecordSpeed(mediaServer, app, stream, speed, schema); if (jsonObject == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "请求失败"); } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java index 89cb1938e..7a766eb56 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java @@ -424,7 +424,6 @@ public class ZLMRESTfulUtils { param.put("stream", stream); param.put("file_path", datePath); param.put("file_repeat", "0"); - param.put("auto_close", "1"); return sendPost(mediaServer, "loadMP4File",param, null); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java index 39c3f2cc8..6fdda6df6 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java @@ -61,9 +61,9 @@ public interface ICloudRecordService { */ void loadRecord(String app, String stream, String date, ErrorCallback callback); - void seekRecord(String mediaServerId,String app, String stream, Double seek); + void seekRecord(String mediaServerId,String app, String stream, Double seek, String schema); - void setRecordSpeed(String mediaServerId, String app, String stream, Integer speed); + void setRecordSpeed(String mediaServerId, String app, String stream, Integer speed, String schema); void deleteFileByIds(Set ids); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java index 1acb6dbb7..150a8a33e 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java @@ -297,43 +297,44 @@ public class CloudRecordServiceImpl implements ICloudRecordService { if (mediaServer == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "媒体节点不存在: " + mediaServerId); } - String buildStream = stream + "_" + date; - MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, app, buildStream); + String buildApp = "mp4_record"; + String buildStream = app + "_" + stream + "_" + date; + MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, buildApp, buildStream); if (mediaInfo != null) { if (callback != null) { - StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServer, app, buildStream, mediaInfo, null); + StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServer, buildApp, buildStream, mediaInfo, null); callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); } return; } - Hook hook = Hook.getInstance(HookType.on_media_arrival, app, buildStream, mediaServerId); + Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServerId); subscribe.addSubscribe(hook, (hookData) -> { - StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServer, app, buildStream, hookData.getMediaInfo(), null); + StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServer, buildApp, buildStream, hookData.getMediaInfo(), null); if (callback != null) { callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); } }); String dateDir = recordItemList.get(0).getFilePath().substring(0, recordItemList.get(0).getFilePath().lastIndexOf("/")); - mediaServerService.loadMP4File(mediaServer, app, buildStream, dateDir); + mediaServerService.loadMP4File(mediaServer, buildApp, buildStream, dateDir); } @Override - public void seekRecord(String mediaServerId,String app, String stream, Double seek) { + public void seekRecord(String mediaServerId,String app, String stream, Double seek, String schema) { MediaServer mediaServer = mediaServerService.getOne(mediaServerId); if (mediaServer == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "媒体节点不存在: " + mediaServerId); } - mediaServerService.seekRecordStamp(mediaServer, app, stream, seek); + mediaServerService.seekRecordStamp(mediaServer, app, stream, seek, schema); } @Override - public void setRecordSpeed(String mediaServerId, String app, String stream, Integer speed) { + public void setRecordSpeed(String mediaServerId, String app, String stream, Integer speed, String schema) { MediaServer mediaServer = mediaServerService.getOne(mediaServerId); if (mediaServer == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "媒体节点不存在: " + mediaServerId); } - mediaServerService.setRecordSpeed(mediaServer, app, stream, speed); + mediaServerService.setRecordSpeed(mediaServer, app, stream, speed, schema); } @Override @@ -352,7 +353,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService { boolean deleteResult = mediaServerService.deleteRecordDirectory(mediaServer, cloudRecordItem.getApp(), cloudRecordItem.getStream(), date, cloudRecordItem.getFileName()); if (deleteResult) { - log.warn("[录像文件定时清理] 删除磁盘文件成功: {}", cloudRecordItem.getFilePath()); + log.warn("[录像文件] 删除磁盘文件成功: {}", cloudRecordItem.getFilePath()); cloudRecordItemIdListForDelete.add(cloudRecordItem); } }catch (ControllerException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java index b9485c095..291f7f9bd 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java @@ -318,10 +318,13 @@ public class CloudRecordController { @RequestParam(required = true) String mediaServerId, @RequestParam(required = true) String app, @RequestParam(required = true) String stream, - @RequestParam(required = true) Double seek + @RequestParam(required = true) Double seek, + @RequestParam(required = false) String schema ) { - - cloudRecordService.seekRecord(mediaServerId, app, stream, seek); + if (schema == null) { + schema = "ts"; + } + cloudRecordService.seekRecord(mediaServerId, app, stream, seek, schema); } @ResponseBody @@ -334,10 +337,14 @@ public class CloudRecordController { @RequestParam(required = true) String mediaServerId, @RequestParam(required = true) String app, @RequestParam(required = true) String stream, - @RequestParam(required = true) Integer speed - ) { + @RequestParam(required = true) Integer speed, + @RequestParam(required = false) String schema + ) { + if (schema == null) { + schema = "ts"; + } - cloudRecordService.setRecordSpeed(mediaServerId, app, stream, speed); + cloudRecordService.setRecordSpeed(mediaServerId, app, stream, speed, schema); } @ResponseBody @@ -410,7 +417,7 @@ public class CloudRecordController { try { ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()); for (CloudRecordItem cloudRecordItem : cloudRecordItemList) { - zos.putNextEntry(new ZipEntry(DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss(cloudRecordItem.getStartTime()) + ".mp4")); + zos.putNextEntry(new ZipEntry(DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss((long)cloudRecordItem.getStartTime()) + ".mp4")); File file = new File(cloudRecordItem.getFilePath()); if (!file.exists() || file.isDirectory()) { continue; @@ -519,7 +526,7 @@ public class CloudRecordController { for (CloudRecordItem cloudRecordItem : cloudRecordItemList) { CloudRecordUrl cloudRecordUrl = new CloudRecordUrl(); cloudRecordUrl.setId(cloudRecordItem.getId()); - cloudRecordUrl.setDownloadUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath() + "&save_name=" + cloudRecordItem.getStream() + "_" + cloudRecordItem.getCallId() + "_" + DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss(cloudRecordItem.getStartTime())); + cloudRecordUrl.setDownloadUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath() + "&save_name=" + cloudRecordItem.getStream() + "_" + cloudRecordItem.getCallId() + "_" + DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss((long)cloudRecordItem.getStartTime())); cloudRecordUrl.setPlayUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath()); cloudRecordUrlList.add(cloudRecordUrl); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserApiKeyController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserApiKeyController.java index 0de8496c9..1f4566bc9 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserApiKeyController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserApiKeyController.java @@ -63,9 +63,9 @@ public class UserApiKeyController { Long expirationTime = null; if (expiresAt != null) { - long timestamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestampMs(expiresAt); - expirationTime = (timestamp - System.currentTimeMillis()) / (60 * 1000); - if (expirationTime < 0) { + expirationTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestampMs(expiresAt); + long difference = (expirationTime - System.currentTimeMillis()) / (60 * 1000); + if (difference < 0) { throw new ControllerException(ErrorCode.ERROR400.getCode(), "过期时间不能早于当前时间"); } } diff --git a/src/main/resources/配置详情.yml b/src/main/resources/配置详情.yml index dd76aa9e6..b6b6ea19e 100644 --- a/src/main/resources/配置详情.yml +++ b/src/main/resources/配置详情.yml @@ -5,6 +5,10 @@ spring: + cache: + type: redis + thymeleaf: + cache: false # 设置接口超时时间 mvc: async: diff --git a/zlm.md b/zlm.md new file mode 100644 index 000000000..f6fa4617a --- /dev/null +++ b/zlm.md @@ -0,0 +1,16 @@ +1. 增加接口:用来返回hook调用耗时。 + 参数: sn, + 返回值: hook耗时 + 功能: zlm收到调用后立即调用心跳hook,hook中携带sn信息, zlm收到hook返回后计算此次hook的耗时,然后返回耗时 + 用途: 1. 可以用来检测hook配置是否正常 + 2. 检测wvp与zlm连接的健康程度 +2. 增加接口:查询loadMP4File的录像播放位置 + 参数: app, steam, + 返回: 当前播放的hook位置 + 功能: zlm收到请求后查询流的seek位置并返回 + 用途: 1. 获取当前播放位置,可以在页面同步显示时间 + 2. 用来时快进五秒 快退五秒类似的操作 +3. loadMP4File扩展, 增加默认seek值和默认倍速,开始时直接从这个位置开始,并使用指定的倍速 +4. 支持下载指定取件的mp4文件,这个区间可能包括多个文件和文件的一部分。 +5. 希望seek接口和倍速接口可以去除schema的必选,作为可选项,不传则默认全部 +6. 可选: seek值如果可以换算为日期,会有更好的体验, 比如2025-4-15 12:32:11