diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java index 3246097a3..9a5701e2b 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java @@ -97,7 +97,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { // return; default: } - // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录 User user = new User(); user.setId(jwtUser.getUserId()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/ICloudRecordService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/ICloudRecordService.java index 8f9e9ef8b..5738a8202 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/ICloudRecordService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/ICloudRecordService.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONArray; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.service.bean.CloudRecordItem; import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.github.pagehelper.PageInfo; import java.util.List; @@ -17,7 +18,7 @@ public interface ICloudRecordService { /** * 分页回去云端录像列表 */ - PageInfo getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List mediaServerItems, String callId); + PageInfo getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List mediaServerItems, String callId, Boolean ascOrder); /** * 获取所有的日期 @@ -52,4 +53,9 @@ public interface ICloudRecordService { DownloadFileInfo getPlayUrlPath(Integer recordId); List getAllList(String query, String app, String stream, String startTime, String endTime, List mediaServerItems, String callId, List ids); + + /** + * 加载录像文件,形成录像流 + */ + StreamContent loadRecord(String app, String stream, String date); } 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 5523bd3c0..82840b479 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 @@ -18,6 +18,7 @@ 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.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; @@ -59,7 +60,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService { @Override public PageInfo getList(int page, int count, String query, String app, String stream, String startTime, - String endTime, List mediaServerItems, String callId) { + String endTime, List mediaServerItems, String callId, Boolean ascOrder) { // 开始时间和结束时间在数据库中都是以秒为单位的 Long startTimeStamp = null; Long endTimeStamp = null; @@ -84,7 +85,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService { .replaceAll("_", "/_"); } List all = cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp, - callId, mediaServerItems, null); + callId, mediaServerItems, null, ascOrder); return new PageInfo<>(all); } @@ -100,7 +101,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService { long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); List cloudRecordItemList = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, - endTimeStamp, null, mediaServerItems, null); + endTimeStamp, null, mediaServerItems, null, null); if (cloudRecordItemList.isEmpty()) { return new ArrayList<>(); } @@ -213,7 +214,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService { } List all = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, endTimeStamp, - callId, mediaServerItems, null); + callId, mediaServerItems, null, null); if (all.isEmpty()) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到待收藏的视频"); } @@ -273,6 +274,22 @@ public class CloudRecordServiceImpl implements ICloudRecordService { } return cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp, - callId, mediaServerItems, ids); + callId, mediaServerItems, ids, null); + } + + @Override + public StreamContent loadRecord(String app, String stream, String date) { + long startTimestamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestampMs(date + " 00:00:00"); + long endTimestamp = startTimestamp + 24 * 60 * 60 * 1000; + + List mediaServerIds = cloudRecordServiceMapper.queryMediaServerInRecord(app, stream, startTimestamp, endTimestamp); + if (mediaServerIds.isEmpty()) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "此时间无录像"); + } + if (mediaServerIds.size() > 1) { + log.info("[云端录像] loadMP4File时发现录像文件分布在不通的zlm上,默认使用第一个zlm开启录像,"); + } + mediaServerService.loadMP4File() + return null; } } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java index f41c2e10c..49dab7fbd 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java @@ -55,12 +55,13 @@ public interface CloudRecordServiceMapper { " and id in " + " #{item}" + " " + - " order by start_time desc" + + " order by start_time asc" + + " order by start_time desc" + " ") List getList(@Param("query") String query, @Param("app") String app, @Param("stream") String stream, @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, @Param("callId")String callId, List mediaServerItemList, - List ids); + List ids, @Param("ascOrder") Boolean ascOrder); @Select(" ") CloudRecordItem queryOne(@Param("id") Integer id); + + @Select(" ") + int queryCount(@Param("app") String app, @Param("stream") String stream, + @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp,); } 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 c3080051e..6011c512e 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 @@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.service.bean.CloudRecordItem; import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.genersoft.iot.vmp.vmanager.cloudRecord.bean.CloudRecordUrl; import com.github.pagehelper.PageInfo; import io.swagger.v3.oas.annotations.Operation; @@ -101,6 +102,7 @@ public class CloudRecordController { @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = false) @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false) @Parameter(name = "callId", description = "每次录像的唯一标识,置空则查询全部流媒体", required = false) + @Parameter(name = "ascOrder", description = "是否升序排序, 升序: true, 降序: false", required = false) public PageInfo openRtpServer(@RequestParam(required = false) String query, @RequestParam(required = false) String app, @RequestParam(required = false) String stream, @@ -109,7 +111,8 @@ public class CloudRecordController { @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String mediaServerId, - @RequestParam(required = false) String callId + @RequestParam(required = false) String callId, + @RequestParam(required = false) Boolean ascOrder ) { log.info("[云端录像] 查询 app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}, callId->{}", app, stream, mediaServerId, page, count, startTime, endTime, callId); @@ -143,7 +146,7 @@ public class CloudRecordController { if (callId != null && ObjectUtils.isEmpty(callId.trim())) { callId = null; } - return cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServers, callId); + return cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServers, callId, ascOrder); } @ResponseBody @@ -233,6 +236,20 @@ public class CloudRecordController { return cloudRecordService.getPlayUrlPath(recordId); } + @ResponseBody + @GetMapping("/loadRecord") + @Operation(summary = "加载录像文件形成播放地址") + @Parameter(name = "app", description = "应用名", required = true) + @Parameter(name = "stream", description = "流ID", required = true) + @Parameter(name = "date", description = "日期, 例如 2025-04-10", required = true) + public StreamContent loadRecord( + @RequestParam(required = true) String app, + @RequestParam(required = true) String stream, + @RequestParam(required = true) String date + ) { + return cloudRecordService.loadRecord(app, stream, date); + } + /************************* 以下这些接口只适合wvp和zlm部署在同一台服务器的情况,且wvp只有一个zlm节点的情况 ***************************************/ /** @@ -379,7 +396,7 @@ public class CloudRecordController { if (remoteHost == null) { remoteHost = request.getScheme() + "://" + request.getLocalAddr() + ":" + (request.getScheme().equals("https") ? mediaServer.getHttpSSlPort() : mediaServer.getHttpPort()); } - PageInfo cloudRecordItemPageInfo = cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServers, callId); + PageInfo cloudRecordItemPageInfo = cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServers, callId, null); PageInfo cloudRecordUrlPageInfo = new PageInfo<>(); if (!ObjectUtils.isEmpty(cloudRecordItemPageInfo)) { cloudRecordUrlPageInfo.setPageNum(cloudRecordItemPageInfo.getPageNum());