From fb9ff677015584d0d9a1c60460e4005bb95e59bf Mon Sep 17 00:00:00 2001 From: lin <648540858@qq.com> Date: Wed, 17 Sep 2025 18:19:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81ABL=E5=BD=95=E5=83=8F?= =?UTF-8?q?=E5=9B=9E=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/conf/MediaConfig.java | 16 ++++ .../gb28181/service/impl/PlayServiceImpl.java | 35 +++----- .../media/abl/ABLMediaNodeServerService.java | 90 +++++++++++++++---- .../iot/vmp/media/abl/ABLRESTfulUtils.java | 15 ++++ .../iot/vmp/media/abl/bean/ABLResult.java | 2 +- .../bean/hook/OnRecordMp4ABLHookParam.java | 16 ++-- .../iot/vmp/media/bean/MediaServer.java | 6 ++ .../iot/vmp/media/bean/RecordInfo.java | 33 ++++++- .../service/IMediaNodeServerService.java | 7 +- .../media/service/IMediaServerService.java | 8 +- .../service/impl/MediaServerServiceImpl.java | 20 +++-- .../media/zlm/ZLMMediaNodeServerService.java | 64 ++++++++++++- .../iot/vmp/media/zlm/ZLMRESTfulUtils.java | 15 ++++ .../iot/vmp/service/bean/CloudRecordItem.java | 6 +- .../service/impl/CloudRecordServiceImpl.java | 46 ++++------ .../iot/vmp/utils/CloudRecordUtils.java | 46 ---------- 数据库/2.7.4/初始化-mysql-2.7.4.sql | 2 + .../2.7.4/初始化-postgresql-kingbase-2.7.4.sql | 2 + 数据库/2.7.4/更新-mysql-2.7.4.sql | 24 +++++ .../2.7.4/更新-postgresql-kingbase-2.7.4.sql | 2 + 20 files changed, 314 insertions(+), 141 deletions(-) delete mode 100644 src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java diff --git a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java index d82b883ba..ab75494c5 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java @@ -47,6 +47,9 @@ public class MediaConfig{ @Value("${media.flv-port:0}") private Integer flvPort = 0; + @Value("${media.mp4-port:0}") + private Integer mp4Port = 0; + @Value("${media.ws-flv-port:0}") private Integer wsFlvPort = 0; @@ -56,6 +59,9 @@ public class MediaConfig{ @Value("${media.flv-ssl-port:0}") private Integer flvSSlPort = 0; + @Value("${media.mp4-ssl-port:0}") + private Integer mp4SSlPort = 0; + @Value("${media.ws-flv-ssl-port:0}") private Integer wsFlvSSlPort = 0; @@ -164,6 +170,11 @@ public class MediaConfig{ }else { mediaServer.setFlvPort(flvPort); } + if (mp4Port == 0) { + mediaServer.setMp4Port(httpPort); + }else { + mediaServer.setMp4Port(mp4Port); + } if (wsFlvPort == 0) { mediaServer.setWsFlvPort(httpPort); }else { @@ -174,6 +185,11 @@ public class MediaConfig{ }else { mediaServer.setFlvSSLPort(flvSSlPort); } + if (mp4SSlPort == 0) { + mediaServer.setMp4SSLPort(httpSSlPort); + }else { + mediaServer.setMp4SSLPort(mp4SSlPort); + } if (wsFlvSSlPort == 0) { mediaServer.setWsFlvSSLPort(httpSSlPort); }else { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java index 0003580a6..def8b5f93 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java @@ -1,6 +1,5 @@ package com.genersoft.iot.vmp.gb28181.service.impl; -import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; @@ -34,7 +33,6 @@ import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.bean.*; import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.utils.CloudRecordUtils; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; @@ -981,8 +979,8 @@ public class PlayServiceImpl implements IPlayService { } - private void download(MediaServer mediaServerItem, Device device, DeviceChannel channel, String startTime, String endTime, int downloadSpeed, ErrorCallback callback) { - if (mediaServerItem == null ) { + private void download(MediaServer mediaServer, Device device, DeviceChannel channel, String startTime, String endTime, int downloadSpeed, ErrorCallback callback) { + if (mediaServer == null ) { callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(), null); @@ -992,7 +990,7 @@ public class PlayServiceImpl implements IPlayService { int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); // 录像下载不使用固定流地址,固定流地址会导致如果开始时间与结束时间一致时文件错误的叠加在一起 RTPServerParam rtpServerParam = new RTPServerParam(); - rtpServerParam.setMediaServerItem(mediaServerItem); + rtpServerParam.setMediaServerItem(mediaServer); rtpServerParam.setSsrcCheck(device.isSsrcCheck()); rtpServerParam.setPlayback(true); rtpServerParam.setPort(0); @@ -1002,7 +1000,7 @@ public class PlayServiceImpl implements IPlayService { SSRCInfo ssrcInfo = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { // hook响应 - StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItem, result.getHookData().getMediaInfo(), device, channel, startTime, endTime); + StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime); if (streamInfo == null) { log.warn("[录像下载] 获取流地址信息失败"); callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), @@ -1048,24 +1046,24 @@ public class PlayServiceImpl implements IPlayService { device.isSsrcCheck()); // 初始化redis中的invite消息状态 - InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), - mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(), + mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, InviteSessionStatus.ready, true); inviteInfo.setStartTime(startTime); inviteInfo.setEndTime(endTime); inviteStreamService.updateInviteInfo(inviteInfo); try { - cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channel, startTime, endTime, downloadSpeed, + cmder.downloadStreamCmd(mediaServer, ssrcInfo, device, channel, startTime, endTime, downloadSpeed, eventResult -> { // 对方返回错误 callback.run(InviteErrorCode.FAIL.getCode(), String.format("录像下载失败, 错误码: %s, %s", eventResult.statusCode, eventResult.msg), null); - receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); + receiveRtpServerService.closeRTPServer(mediaServer, ssrcInfo); sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); inviteStreamService.removeInviteInfo(inviteInfo); }, eventResult ->{ // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 - InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel, + InviteOKHandler(eventResult, ssrcInfo, mediaServer, device, channel, callback, inviteInfo, InviteSessionType.DOWNLOAD); // 注册录像回调事件,录像下载结束后写入下载地址 @@ -1074,8 +1072,7 @@ public class PlayServiceImpl implements IPlayService { inviteInfo.getDeviceId(), inviteInfo.getChannelId(), ssrcInfo.getStream()); log.info("[录像下载] 收到录像写入磁盘消息内容: " + hookData); RecordInfo recordInfo = hookData.getRecordInfo(); - String filePath = recordInfo.getFilePath(); - DownloadFileInfo downloadFileInfo = CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath); + DownloadFileInfo downloadFileInfo = mediaServerService.getDownloadFilePath(mediaServer, recordInfo); InviteInfo inviteInfoForNew = inviteStreamService.getInviteInfo(inviteInfo.getType() , inviteInfo.getChannelId(), inviteInfo.getStream()); if (inviteInfoForNew != null && inviteInfoForNew.getStreamInfo() != null) { @@ -1084,7 +1081,7 @@ public class PlayServiceImpl implements IPlayService { inviteStreamService.updateInviteInfo(inviteInfoForNew, 60*15L); } }; - Hook hook = Hook.getInstance(HookType.on_record_mp4, "rtp", ssrcInfo.getStream(), mediaServerItem.getId()); + Hook hook = Hook.getInstance(HookType.on_record_mp4, "rtp", ssrcInfo.getStream(), mediaServer.getId()); // 设置过期时间,下载失败时自动处理订阅数据 hook.setExpireTime(System.currentTimeMillis() + 24 * 60 * 60 * 1000); subscribe.addSubscribe(hook, hookEventForRecord); @@ -1092,7 +1089,7 @@ public class PlayServiceImpl implements IPlayService { } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 录像下载: {}", e.getMessage()); callback.run(InviteErrorCode.FAIL.getCode(),e.getMessage(), null); - receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); + receiveRtpServerService.closeRTPServer(mediaServer, ssrcInfo); sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); inviteStreamService.removeInviteInfo(inviteInfo); } @@ -1112,11 +1109,7 @@ public class PlayServiceImpl implements IPlayService { log.warn("[获取下载进度] 未查询到录像下载的信息 {}/{}-{}", device.getDeviceId(), channel.getDeviceId(), stream); return null; } - String filePath = allList.get(0).getFilePath(); - if (filePath == null) { - log.warn("[获取下载进度] 未查询到录像下载的文件路径 {}/{}-{}", device.getDeviceId(), channel.getDeviceId(), stream); - return null; - } + String mediaServerId = allList.get(0).getMediaServerId(); MediaServer mediaServer = mediaServerService.getOne(mediaServerId); if (mediaServer == null) { @@ -1124,7 +1117,7 @@ public class PlayServiceImpl implements IPlayService { return null; } log.warn("[获取下载进度] 发现下载已经结束,直接从数据库获取到文件 {}/{}-{}", device.getDeviceId(), channel.getDeviceId(), stream); - DownloadFileInfo downloadFileInfo = CloudRecordUtils.getDownloadFilePath(mediaServer, filePath); + DownloadFileInfo downloadFileInfo = mediaServerService.getDownloadFilePath(mediaServer, RecordInfo.getInstance(allList.get(0))); StreamInfo streamInfo = new StreamInfo(); streamInfo.setDownLoadFilePath(downloadFileInfo); streamInfo.setApp(app); diff --git a/src/main/java/com/genersoft/iot/vmp/media/abl/ABLMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/abl/ABLMediaNodeServerService.java index 4d63cae6c..403833f3d 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/abl/ABLMediaNodeServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/media/abl/ABLMediaNodeServerService.java @@ -15,11 +15,12 @@ import com.genersoft.iot.vmp.media.abl.bean.ABLResult; import com.genersoft.iot.vmp.media.abl.bean.AblServerConfig; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.bean.RecordInfo; import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event; -import com.genersoft.iot.vmp.media.event.media.MediaRecordProcessEvent; import com.genersoft.iot.vmp.media.service.IMediaNodeServerService; import com.genersoft.iot.vmp.service.bean.CloudRecordItem; import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.utils.DateUtil; @@ -32,6 +33,8 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -192,8 +195,10 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService { streamInfoResult.setTs(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam); streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay); - streamInfoResult.setMediaInfo(mediaInfo); - streamInfoResult.setOriginType(mediaInfo.getOriginType()); + if (mediaInfo != null) { + streamInfoResult.setMediaInfo(mediaInfo); + streamInfoResult.setOriginType(mediaInfo.getOriginType()); + } return streamInfoResult; } @@ -255,18 +260,18 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService { } // 接受进度通知 - @EventListener - public void onApplicationEvent(MediaRecordProcessEvent event) { - CloudRecordItem cloudRecordItem = cloudRecordServiceMapper.getListByFileName(event.getApp(), event.getStream(), event.getFileName()); - if (cloudRecordItem == null) { - cloudRecordItem = CloudRecordItem.getInstance(event); - cloudRecordItem.setStartTime(event.getStartTime()); - cloudRecordItem.setEndTime(event.getEndTime()); - cloudRecordServiceMapper.add(cloudRecordItem); - }else { - cloudRecordServiceMapper.updateTimeLen(cloudRecordItem.getId(), (long)event.getCurrentFileDuration() * 1000, System.currentTimeMillis()); - } - } +// @EventListener +// public void onApplicationEvent(MediaRecordProcessEvent event) { +// CloudRecordItem cloudRecordItem = cloudRecordServiceMapper.getListByFileName(event.getApp(), event.getStream(), event.getFileName()); +// if (cloudRecordItem == null) { +// cloudRecordItem = CloudRecordItem.getInstance(event); +// cloudRecordItem.setStartTime(event.getStartTime()); +// cloudRecordItem.setEndTime(event.getEndTime()); +// cloudRecordServiceMapper.add(cloudRecordItem); +// }else { +// cloudRecordServiceMapper.updateTimeLen(cloudRecordItem.getId(), (long)event.getCurrentFileDuration() * 1000, System.currentTimeMillis()); +// } +// } @EventListener public void onApplicationEvent(MediaRecordMp4Event event) { InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, null, event.getStream()); @@ -401,8 +406,24 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService { } @Override - public void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath) { - logger.warn("[abl-loadMP4File] 未实现"); + public void loadMP4File(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback callback) { + // 解析为 LocalDate + LocalDate localDate = LocalDate.parse(date, DateUtil.DateFormatter); + LocalDateTime startOfDay = localDate.atStartOfDay(); + LocalDateTime endOfDay = localDate.atTime(23, 59,59, 999); + String startTime = DateUtil.urlFormatter.format(startOfDay); + String endTime = DateUtil.urlFormatter.format(endOfDay); + + ABLResult ablResult = ablresTfulUtils.queryRecordList(mediaServer, app, stream, startTime, endTime); + if (ablResult.getCode() != 0) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), ablResult.getMemo()); + } + String resultApp = ablResult.getApp(); + String resultStream = ablResult.getStream(); + StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, resultApp, resultStream, null, null, true); + if (callback != null) { + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); + } } @Override @@ -414,4 +435,39 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService { public void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed, String schema) { logger.warn("[abl-setRecordSpeed] 未实现"); } + + @Override + public DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo) { + // 将filePath作为独立参数传入,避免%符号解析问题 + String pathTemplate = "%s://%s:%s/%s/%s__ReplayFMP4RecordFile__%s?download_speed=6"; + + DownloadFileInfo info = new DownloadFileInfo(); + + info.setHttpPath( + String.format( + pathTemplate, + "http", + mediaServer.getStreamIp(), + mediaServer.getHttpPort(), + recordInfo.getApp(), + recordInfo.getStream(), + recordInfo.getFileName() + ) + ); + + if (mediaServer.getHttpSSlPort() > 0) { + info.setHttpsPath( + String.format( + pathTemplate, + "https", + mediaServer.getStreamIp(), + mediaServer.getHttpSSlPort(), + recordInfo.getApp(), + recordInfo.getStream(), + recordInfo.getFileName() + ) + ); + } + return info; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/abl/ABLRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/abl/ABLRESTfulUtils.java index b019eef68..d3c85b8bd 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/abl/ABLRESTfulUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/media/abl/ABLRESTfulUtils.java @@ -1,8 +1,10 @@ package com.genersoft.iot.vmp.media.abl; import com.alibaba.fastjson2.JSON; +import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.media.abl.bean.ABLResult; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import okhttp3.*; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -12,8 +14,10 @@ import org.springframework.stereotype.Component; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.SocketTimeoutException; +import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -426,6 +430,12 @@ public class ABLRESTfulUtils { } public ABLResult addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean disableAudio, boolean enableMp4, String rtpType, Integer timeout) { + try { + url = URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(),"url编码失败"); + } + Map param = new HashMap<>(); param.put("app", app); param.put("stream", stream); @@ -443,6 +453,11 @@ public class ABLRESTfulUtils { } public ABLResult addFFmpegProxy(MediaServer mediaServer, String app, String stream, String url, boolean disableAudio, boolean enableMp4, String rtpType, Integer timeout) { + try { + url = URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(),"url编码失败"); + } Map param = new HashMap<>(); param.put("app", app); param.put("stream", stream); diff --git a/src/main/java/com/genersoft/iot/vmp/media/abl/bean/ABLResult.java b/src/main/java/com/genersoft/iot/vmp/media/abl/bean/ABLResult.java index d76d916cf..d10965550 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/abl/bean/ABLResult.java +++ b/src/main/java/com/genersoft/iot/vmp/media/abl/bean/ABLResult.java @@ -21,7 +21,7 @@ public class ABLResult { private String starttime; private String endtime; private ABLUrls url; - private ABLRecordFile recordFileList; + private List recordFileList; public static ABLResult getFailForMediaServer() { ABLResult zlmResult = new ABLResult(); diff --git a/src/main/java/com/genersoft/iot/vmp/media/abl/bean/hook/OnRecordMp4ABLHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/abl/bean/hook/OnRecordMp4ABLHookParam.java index 0fb819fae..6aaddfed2 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/abl/bean/hook/OnRecordMp4ABLHookParam.java +++ b/src/main/java/com/genersoft/iot/vmp/media/abl/bean/hook/OnRecordMp4ABLHookParam.java @@ -1,13 +1,13 @@ package com.genersoft.iot.vmp.media.abl.bean.hook; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter public class OnRecordMp4ABLHookParam extends ABLHookParam{ private String fileName; - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } + private String startTime; + private String endTime; + private long fileSize; } diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java index ad0c14ed0..7a6f65fa7 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java +++ b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java @@ -41,6 +41,12 @@ public class MediaServer { @Schema(description = "https-flv端口") private int flvSSLPort; + @Schema(description = "mp4端口") + private int mp4Port; + + @Schema(description = "https-mp4端口") + private int mp4SSLPort; + @Schema(description = "ws-flv端口") private int wsFlvPort; 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 562ea75f5..b90305854 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 @@ -2,34 +2,63 @@ package com.genersoft.iot.vmp.media.bean; import com.genersoft.iot.vmp.media.abl.bean.hook.OnRecordMp4ABLHookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; +import com.genersoft.iot.vmp.utils.DateUtil; import lombok.Data; @Data public class RecordInfo { + private String app; + private String stream; private String fileName; private String filePath; private long fileSize; private String folder; private String url; + /** + * 单位毫秒 + */ private long startTime; + /** + * 单位毫秒 + */ private double timeLen; private String params; public static RecordInfo getInstance(OnRecordMp4HookParam hookParam) { RecordInfo recordInfo = new RecordInfo(); + recordInfo.setApp(hookParam.getApp()); + recordInfo.setStream(hookParam.getStream()); recordInfo.setFileName(hookParam.getFile_name()); recordInfo.setUrl(hookParam.getUrl()); recordInfo.setFolder(hookParam.getFolder()); recordInfo.setFilePath(hookParam.getFile_path()); recordInfo.setFileSize(hookParam.getFile_size()); - recordInfo.setStartTime(hookParam.getStart_time()); - recordInfo.setTimeLen(hookParam.getTime_len()); + recordInfo.setStartTime(hookParam.getStart_time() * 1000); + recordInfo.setTimeLen(hookParam.getTime_len() * 1000); return recordInfo; } public static RecordInfo getInstance(OnRecordMp4ABLHookParam hookParam) { RecordInfo recordInfo = new RecordInfo(); + recordInfo.setApp(hookParam.getApp()); + recordInfo.setStream(hookParam.getStream()); recordInfo.setFileName(hookParam.getFileName()); + recordInfo.setStartTime(DateUtil.urlToTimestampMs(hookParam.getStartTime())); + recordInfo.setTimeLen(DateUtil.urlToTimestampMs(hookParam.getEndTime()) - recordInfo.getStartTime()); + recordInfo.setFileSize(hookParam.getFileSize()); + return recordInfo; + } + + public static RecordInfo getInstance(CloudRecordItem cloudRecordItem) { + RecordInfo recordInfo = new RecordInfo(); + recordInfo.setApp(cloudRecordItem.getApp()); + recordInfo.setStream(cloudRecordItem.getStream()); + recordInfo.setFileName(cloudRecordItem.getFileName()); + recordInfo.setStartTime(cloudRecordItem.getStartTime()); + recordInfo.setTimeLen(cloudRecordItem.getTimeLen()); + recordInfo.setFileSize(cloudRecordItem.getFileSize()); + recordInfo.setFilePath(cloudRecordItem.getFilePath()); 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 f6a773f83..ca10adae3 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 @@ -5,6 +5,9 @@ import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.bean.RecordInfo; +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; @@ -74,9 +77,11 @@ public interface IMediaNodeServerService { List listRtpServer(MediaServer mediaServer); - void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath); + void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath, String dateDir, ErrorCallback callback); void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp, String schema); void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed, String schema); + + DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo); } 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 a89c90812..f5ff1a8bd 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 @@ -5,8 +5,8 @@ import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; -import com.genersoft.iot.vmp.service.bean.MediaServerLoad; -import com.genersoft.iot.vmp.service.bean.SSRCInfo; +import com.genersoft.iot.vmp.media.bean.RecordInfo; +import com.genersoft.iot.vmp.service.bean.*; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; @@ -164,9 +164,11 @@ public interface IMediaServerService { List listRtpServer(MediaServer mediaServer); - StreamInfo loadMP4File(MediaServer mediaServer, String app, String stream, String datePath); + void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath, String dateDir, ErrorCallback callback); void seekRecordStamp(MediaServer mediaServer, String app, String stream, Double stamp, String schema); void setRecordSpeed(MediaServer mediaServer, String app, String stream, Integer speed, String schema); + + DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo); } 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 4ee147eb8..bcc206d12 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 @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.bean.RecordInfo; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerDeleteEvent; @@ -20,8 +21,7 @@ import com.genersoft.iot.vmp.media.service.IMediaNodeServerService; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType; -import com.genersoft.iot.vmp.service.bean.MediaServerLoad; -import com.genersoft.iot.vmp.service.bean.SSRCInfo; +import com.genersoft.iot.vmp.service.bean.*; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.dao.MediaServerMapper; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; @@ -1008,14 +1008,14 @@ public class MediaServerServiceImpl implements IMediaServerService { } @Override - public StreamInfo loadMP4File(MediaServer mediaServer, String app, String stream, String datePath) { + public void loadMP4File(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback callback) { IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType()); if (mediaNodeServerService == null) { log.info("[loadMP4File] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType()); throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类"); } - mediaNodeServerService.loadMP4File(mediaServer, app, stream, datePath); - return getStreamInfoByAppAndStream(mediaServer, app, stream, null, null); + mediaNodeServerService.loadMP4File(mediaServer, app, stream, date, dateDir, callback); + } @Override @@ -1037,4 +1037,14 @@ public class MediaServerServiceImpl implements IMediaServerService { } mediaNodeServerService.setRecordSpeed(mediaServer, app, stream, speed, schema); } + + @Override + public DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo) { + IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType()); + if (mediaNodeServerService == null) { + log.info("[setRecordSpeed] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类"); + } + return mediaNodeServerService.getDownloadFilePath(mediaServer, recordInfo); + } } 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 3c0c12082..cc0dc4ebb 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 @@ -10,8 +10,14 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.bean.RecordInfo; +import com.genersoft.iot.vmp.media.event.hook.Hook; +import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; +import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.service.IMediaNodeServerService; import com.genersoft.iot.vmp.media.zlm.dto.*; +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; @@ -20,7 +26,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @Slf4j @Service("zlm") @@ -36,6 +45,9 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { @Autowired private UserSetting userSetting; + @Autowired + private HookSubscribe subscribe; + @Override public int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) { return zlmServerFactory.createRTPServer(mediaServer, "rtp", streamId, ssrc, port, onlyAuto, disableAudio, reUsePort, tcpMode); @@ -552,8 +564,28 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { } @Override - public void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath) { - ZLMResult zlmResult = zlmresTfulUtils.loadMP4File(mediaServer, app, stream, datePath); + public void loadMP4File(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback callback) { + String buildApp = "mp4_record"; + String buildStream = app + "_" + stream + "_" + date; + MediaInfo mediaInfo = getMediaInfo(mediaServer, buildApp, buildStream); + if (mediaInfo != null) { + if (callback != null) { + StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, buildApp, buildStream, mediaInfo, null, true); + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); + } + return; + } + + Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServer.getServerId()); + subscribe.addSubscribe(hook, (hookData) -> { + StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, buildApp, buildStream, hookData.getMediaInfo(), null, true); + if (callback != null) { + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); + } + }); + + ZLMResult zlmResult = zlmresTfulUtils.loadMP4File(mediaServer, buildApp, buildStream, dateDir); + if (zlmResult == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "请求失败"); } @@ -583,4 +615,30 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { throw new ControllerException(zlmResult.getCode(), zlmResult.getMsg()); } } + + @Override + public DownloadFileInfo getDownloadFilePath(MediaServer mediaServerItem, RecordInfo recordInfo) { + + // 将filePath作为独立参数传入,避免%符号解析问题 + String pathTemplate = "%s://%s:%s/index/api/downloadFile?file_path=%s"; + + DownloadFileInfo info = new DownloadFileInfo(); + + // filePath作为第4个参数 + info.setHttpPath(String.format(pathTemplate, + "http", + mediaServerItem.getStreamIp(), + mediaServerItem.getHttpPort(), + recordInfo.getFilePath())); + + // 同样作为第4个参数 + if (mediaServerItem.getHttpSSlPort() > 0) { + info.setHttpsPath(String.format(pathTemplate, + "https", + mediaServerItem.getStreamIp(), + mediaServerItem.getHttpSSlPort(), + recordInfo.getFilePath())); + } + return info; + } } 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 a90e5732f..3414eacc7 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 @@ -4,8 +4,10 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.TypeReference; +import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.zlm.dto.*; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import okhttp3.logging.HttpLoggingInterceptor; @@ -15,9 +17,11 @@ import org.springframework.stereotype.Component; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.net.ConnectException; import java.net.SocketTimeoutException; +import java.net.URLEncoder; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -327,6 +331,12 @@ public class ZLMRESTfulUtils { public ZLMResult addFFmpegSource(MediaServer mediaServer, String src_url, String dst_url, Integer timeout_sec, boolean enable_audio, boolean enable_mp4, String ffmpeg_cmd_key){ + try { + src_url = URLEncoder.encode(src_url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(),"url编码失败"); + } + Map param = new HashMap<>(); param.put("src_url", src_url); param.put("dst_url", dst_url); @@ -573,6 +583,11 @@ public class ZLMRESTfulUtils { } public ZLMResult addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enable_audio, boolean enable_mp4, String rtp_type, Integer timeOut) { + try { + url = URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new ControllerException(ErrorCode.ERROR100.getCode(),"url编码失败"); + } Map param = new HashMap<>(); param.put("vhost", "__defaultVhost__"); param.put("app", app); diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java b/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java index 0caea9481..01e452a54 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java +++ b/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java @@ -91,14 +91,14 @@ public class CloudRecordItem { CloudRecordItem cloudRecordItem = new CloudRecordItem(); cloudRecordItem.setApp(param.getApp()); cloudRecordItem.setStream(param.getStream()); - cloudRecordItem.setStartTime(param.getRecordInfo().getStartTime()*1000); + cloudRecordItem.setStartTime(param.getRecordInfo().getStartTime()); cloudRecordItem.setFileName(param.getRecordInfo().getFileName()); cloudRecordItem.setFolder(param.getRecordInfo().getFolder()); cloudRecordItem.setFileSize(param.getRecordInfo().getFileSize()); cloudRecordItem.setFilePath(param.getRecordInfo().getFilePath()); cloudRecordItem.setMediaServerId(param.getMediaServer().getId()); - cloudRecordItem.setTimeLen(param.getRecordInfo().getTimeLen() * 1000); - cloudRecordItem.setEndTime((param.getRecordInfo().getStartTime() + (long)param.getRecordInfo().getTimeLen()) * 1000); + cloudRecordItem.setTimeLen(param.getRecordInfo().getTimeLen()); + cloudRecordItem.setEndTime((param.getRecordInfo().getStartTime() + (long)param.getRecordInfo().getTimeLen())); Map paramsMap = MediaServerUtils.urlParamToMap(param.getRecordInfo().getParams()); if (paramsMap.get("callId") != null) { cloudRecordItem.setCallId(paramsMap.get("callId")); 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 150a8a33e..6a8588027 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 @@ -5,11 +5,8 @@ import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; -import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; -import com.genersoft.iot.vmp.media.event.hook.Hook; -import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; -import com.genersoft.iot.vmp.media.event.hook.HookType; +import com.genersoft.iot.vmp.media.bean.RecordInfo; import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; @@ -21,7 +18,6 @@ import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; -import com.genersoft.iot.vmp.utils.CloudRecordUtils; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.github.pagehelper.PageHelper; @@ -37,7 +33,10 @@ import org.springframework.util.Assert; import java.io.File; import java.time.LocalDate; import java.time.ZoneOffset; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; @Slf4j @Service @@ -61,9 +60,6 @@ public class CloudRecordServiceImpl implements ICloudRecordService { @Autowired private IRedisRpcPlayService redisRpcPlayService; - @Autowired - private HookSubscribe subscribe; - @Override public PageInfo getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List mediaServerItems, String callId, Boolean ascOrder) { @@ -255,9 +251,10 @@ public class CloudRecordServiceImpl implements ICloudRecordService { if (!userSetting.getServerId().equals(recordItem.getServerId())) { return redisRpcPlayService.getRecordPlayUrl(recordItem.getServerId(), recordId); } - String filePath = recordItem.getFilePath(); - MediaServer mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId()); - return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath); + + MediaServer mediaServer = mediaServerService.getOne(recordItem.getMediaServerId()); + + return mediaServerService.getDownloadFilePath(mediaServer, RecordInfo.getInstance(recordItem)); } @Override @@ -297,26 +294,13 @@ public class CloudRecordServiceImpl implements ICloudRecordService { if (mediaServer == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "媒体节点不存在: " + mediaServerId); } - 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, buildApp, buildStream, mediaInfo, null); - callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); - } - return; - } + String dateDir = null; + String filePath = recordItemList.get(0).getFilePath(); + if (filePath != null) { + dateDir = filePath.substring(0, filePath.lastIndexOf("/")); + } + mediaServerService.loadMP4File(mediaServer, app, stream, date, dateDir, callback); - Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServerId); - subscribe.addSubscribe(hook, (hookData) -> { - 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, buildApp, buildStream, dateDir); } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java deleted file mode 100644 index 6fcf53b3f..000000000 --- a/src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.genersoft.iot.vmp.utils; - -import com.genersoft.iot.vmp.media.bean.MediaServer; -import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; -import lombok.experimental.UtilityClass; - -/** - * 云录像工具类 - * - * @author 648540858 - */ -@UtilityClass -public class CloudRecordUtils { - - - /** - * 修复原始工具类中的格式化问题 - * - * @param mediaServerItem 媒体服务器配置 - * @param filePath 文件路径(可能包含%等特殊字符) - * @return 修复后的下载信息 - */ - public static DownloadFileInfo getDownloadFilePath(MediaServer mediaServerItem, String filePath) { - // 将filePath作为独立参数传入,避免%符号解析问题 - String pathTemplate = "%s://%s:%s/index/api/downloadFile?file_path=%s"; - - DownloadFileInfo info = new DownloadFileInfo(); - - // filePath作为第4个参数 - info.setHttpPath(String.format(pathTemplate, - "http", - mediaServerItem.getStreamIp(), - mediaServerItem.getHttpPort(), - filePath)); - - // 同样作为第4个参数 - if (mediaServerItem.getHttpSSlPort() > 0) { - info.setHttpsPath(String.format(pathTemplate, - "https", - mediaServerItem.getStreamIp(), - mediaServerItem.getHttpSSlPort(), - filePath)); - } - return info; - } -} diff --git a/数据库/2.7.4/初始化-mysql-2.7.4.sql b/数据库/2.7.4/初始化-mysql-2.7.4.sql index fa1ffbbc3..d35c952d4 100644 --- a/数据库/2.7.4/初始化-mysql-2.7.4.sql +++ b/数据库/2.7.4/初始化-mysql-2.7.4.sql @@ -181,6 +181,8 @@ create table IF NOT EXISTS wvp_media_server rtsp_ssl_port integer, flv_port integer, flv_ssl_port integer, + mp4_port integer, + mp4_ssl_port integer, ws_flv_port integer, ws_flv_ssl_port integer, jtt_proxy_port integer, diff --git a/数据库/2.7.4/初始化-postgresql-kingbase-2.7.4.sql b/数据库/2.7.4/初始化-postgresql-kingbase-2.7.4.sql index 8b9f8ec8b..ff8d72eab 100644 --- a/数据库/2.7.4/初始化-postgresql-kingbase-2.7.4.sql +++ b/数据库/2.7.4/初始化-postgresql-kingbase-2.7.4.sql @@ -182,6 +182,8 @@ create table IF NOT EXISTS wvp_media_server rtsp_ssl_port integer, flv_port integer, flv_ssl_port integer, + mp4_port integer, + mp4_ssl_port integer, ws_flv_port integer, ws_flv_ssl_port integer, jtt_proxy_port integer, diff --git a/数据库/2.7.4/更新-mysql-2.7.4.sql b/数据库/2.7.4/更新-mysql-2.7.4.sql index a1d17c343..d09a6daed 100644 --- a/数据库/2.7.4/更新-mysql-2.7.4.sql +++ b/数据库/2.7.4/更新-mysql-2.7.4.sql @@ -51,4 +51,28 @@ call wvp_20250708(); DROP PROCEDURE wvp_20250708; DELIMITER ; +/* +* 20250917 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250917`() +BEGIN + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'mp4_port') + THEN + ALTER TABLE wvp_media_server ADD mp4_port integer; + END IF; + + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'mp4_ssl_port') + THEN + ALTER TABLE wvp_media_server ADD mp4_ssl_port integer; + END IF; +END; // +call wvp_20250917(); +DROP PROCEDURE wvp_20250917; +DELIMITER ; + + + diff --git a/数据库/2.7.4/更新-postgresql-kingbase-2.7.4.sql b/数据库/2.7.4/更新-postgresql-kingbase-2.7.4.sql index 3daac089b..6a87a736d 100644 --- a/数据库/2.7.4/更新-postgresql-kingbase-2.7.4.sql +++ b/数据库/2.7.4/更新-postgresql-kingbase-2.7.4.sql @@ -35,3 +35,5 @@ create table IF NOT EXISTS wvp_jt_channel ( ); ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS jtt_proxy_port integer; +ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS mp4_port integer; +ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS mp4_ssl_port integer;