Commit e4d37864d1c9fa525807ceecf131a556549672b4

Authored by 648540858
1 parent 298a9f42

开始重构云端录像继续

Too many changes to show.

To preserve performance only 10 of 12 files are displayed.

sql/2.6.9更新.sql
... ... @@ -8,17 +8,18 @@ alter table wvp_stream_proxy
8 8 add stream_key varying(255)
9 9  
10 10 create table wvp_cloud_record (
11   - id serial primary key,
12   - app character varying(255),
13   - stream character varying(255),
14   - call_id character varying(255),
15   - start_time integer,
16   - end_time integer,
17   - media_server_id character varying(50),
18   - file_name character varying(50),
19   - folder character varying(50),
20   - file_path character varying(255),
21   - file_size integer,
22   - time_len integer,
23   - constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
  11 + id serial primary key,
  12 + app character varying(255),
  13 + stream character varying(255),
  14 + call_id character varying(255),
  15 + start_time integer,
  16 + end_time integer,
  17 + media_server_id character varying(50),
  18 + file_name character varying(255),
  19 + folder character varying(255),
  20 + file_path character varying(255),
  21 + collect_type character varying(255),
  22 + file_size integer,
  23 + time_len integer,
  24 + constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
24 25 );
... ...
sql/初始化.sql
... ... @@ -267,19 +267,20 @@ create table wvp_stream_push (
267 267 constraint uk_stream_push_app_stream unique (app, stream)
268 268 );
269 269 create table wvp_cloud_record (
270   - id serial primary key,
271   - app character varying(255),
272   - stream character varying(255),
273   - call_id character varying(255),
274   - start_time integer,
275   - end_time integer,
276   - mediaServerId character varying(50),
277   - file_name character varying(50),
278   - folder character varying(50),
279   - file_path character varying(255),
280   - file_size integer,
281   - time_len integer,
282   - constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
  270 + id serial primary key,
  271 + app character varying(255),
  272 + stream character varying(255),
  273 + call_id character varying(255),
  274 + start_time integer,
  275 + end_time integer,
  276 + media_server_id character varying(50),
  277 + file_name character varying(255),
  278 + folder character varying(255),
  279 + file_path character varying(255),
  280 + collect_type character varying(255),
  281 + file_size integer,
  282 + time_len integer,
  283 + constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
283 284 );
284 285  
285 286 create table wvp_user (
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -111,6 +111,9 @@ public class ZLMHttpHookListener {
111 111 private IUserService userService;
112 112  
113 113 @Autowired
  114 + private ICloudRecordService cloudRecordService;
  115 +
  116 + @Autowired
114 117 private VideoStreamSessionManager sessionManager;
115 118  
116 119 @Autowired
... ... @@ -775,7 +778,7 @@ public class ZLMHttpHookListener {
775 778 logger.info("[ZLM HOOK] 录像完成事件:{}->{}", param.getMediaServerId(), param.getFile_path());
776 779  
777 780 taskExecutor.execute(() -> {
778   -
  781 + cloudRecordService.addRecord(param);
779 782 });
780 783  
781 784 return HookResult.SUCCESS();
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
... ... @@ -9,7 +9,7 @@ public class OnRecordMp4HookParam extends HookParam{
9 9 private String stream;
10 10 private String file_name;
11 11 private String file_path;
12   - private String file_size;
  12 + private long file_size;
13 13 private String folder;
14 14 private String url;
15 15 private String vhost;
... ... @@ -48,11 +48,11 @@ public class OnRecordMp4HookParam extends HookParam{
48 48 this.file_path = file_path;
49 49 }
50 50  
51   - public String getFile_size() {
  51 + public long getFile_size() {
52 52 return file_size;
53 53 }
54 54  
55   - public void setFile_size(String file_size) {
  55 + public void setFile_size(long file_size) {
56 56 this.file_size = file_size;
57 57 }
58 58  
... ...
src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
1 1 package com.genersoft.iot.vmp.service;
2 2  
  3 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
3 5 import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
4 6 import com.github.pagehelper.PageInfo;
5 7  
... ... @@ -14,14 +16,16 @@ public interface ICloudRecordService {
14 16 /**
15 17 * 分页回去云端录像列表
16 18 */
17   - PageInfo<CloudRecordItem> getList(int page, int count, String startTime, String endTime);
  19 + PageInfo<CloudRecordItem> getList(int page, int count, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems);
18 20  
19 21 /**
20   - * 获取所有的日期
  22 + * 根据hook消息增加一条记录
21 23 */
22   - List<String> getDateList(Integer year, Integer month, String app, String stream);
23   -
24   -
  24 + void addRecord(OnRecordMp4HookParam param);
25 25  
  26 + /**
  27 + * 获取所有的日期
  28 + */
  29 + List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems);
26 30  
27 31 }
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java
1 1 package com.genersoft.iot.vmp.service.bean;
2 2  
  3 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
  4 +
3 5 /**
4 6 * 云端录像数据
5 7 */
... ... @@ -69,6 +71,21 @@ public class CloudRecordItem {
69 71 */
70 72 private long timeLen;
71 73  
  74 + public static CloudRecordItem getInstance(OnRecordMp4HookParam param) {
  75 + CloudRecordItem cloudRecordItem = new CloudRecordItem();
  76 + cloudRecordItem.setApp(param.getApp());
  77 + cloudRecordItem.setStream(param.getStream());
  78 + cloudRecordItem.setStartTime(param.getStart_time());
  79 + cloudRecordItem.setFileName(param.getFile_name());
  80 + cloudRecordItem.setFolder(param.getFolder());
  81 + cloudRecordItem.setFileSize(param.getFile_size());
  82 + cloudRecordItem.setFilePath(param.getFile_path());
  83 + cloudRecordItem.setMediaServerId(param.getMediaServerId());
  84 + cloudRecordItem.setTimeLen(param.getTime_len());
  85 + cloudRecordItem.setEndTime(param.getStart_time() + param.getTime_len());
  86 + return cloudRecordItem;
  87 + }
  88 +
72 89 public int getId() {
73 90 return id;
74 91 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.impl;
  2 +
  3 +import com.genersoft.iot.vmp.conf.exception.ControllerException;
  4 +import com.genersoft.iot.vmp.gb28181.bean.GbStream;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  6 +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
  8 +import com.genersoft.iot.vmp.service.ICloudRecordService;
  9 +import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
  10 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  11 +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
  12 +import com.genersoft.iot.vmp.utils.DateUtil;
  13 +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  14 +import com.github.pagehelper.PageHelper;
  15 +import com.github.pagehelper.PageInfo;
  16 +import org.slf4j.Logger;
  17 +import org.slf4j.LoggerFactory;
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Service;
  20 +import org.springframework.util.unit.DataUnit;
  21 +
  22 +import java.time.*;
  23 +import java.time.temporal.TemporalAccessor;
  24 +import java.util.*;
  25 +
  26 +@Service
  27 +public class CloudRecordServiceImpl implements ICloudRecordService {
  28 +
  29 + private final static Logger logger = LoggerFactory.getLogger(CloudRecordServiceImpl.class);
  30 +
  31 + @Autowired
  32 + private CloudRecordServiceMapper cloudRecordServiceMapper;
  33 +
  34 + @Autowired
  35 + private IRedisCatchStorage redisCatchStorage;
  36 +
  37 + @Override
  38 + public PageInfo<CloudRecordItem> getList(int page, int count, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) {
  39 + // 开始时间和结束时间在数据库中都是以秒为单位的
  40 + Long startTimeStamp = null;
  41 + Long endTimeStamp = null;
  42 + if (startTime != null ) {
  43 + if (!DateUtil.verification(startTime, DateUtil.formatter)) {
  44 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间格式错误,正确格式为: " + DateUtil.formatter);
  45 + }
  46 + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
  47 +
  48 + }
  49 + if (endTime != null ) {
  50 + if (!DateUtil.verification(endTime, DateUtil.formatter)) {
  51 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "结束时间格式错误,正确格式为: " + DateUtil.formatter);
  52 + }
  53 + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
  54 +
  55 + }
  56 + PageHelper.startPage(page, count);
  57 + List<CloudRecordItem> all = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, mediaServerItems);
  58 + return new PageInfo<>(all);
  59 + }
  60 +
  61 + @Override
  62 + public List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) {
  63 + LocalDate startDate = LocalDate.of(year, month, 1);
  64 + LocalDate endDate;
  65 + if (month == 12) {
  66 + endDate = LocalDate.of(year + 1, 1, 1);
  67 + }else {
  68 + endDate = LocalDate.of(year, month + 1, 1);
  69 + }
  70 + long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond();
  71 + long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond();
  72 + List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, mediaServerItems);
  73 + if (cloudRecordItemList.isEmpty()) {
  74 + return new ArrayList<>();
  75 + }
  76 + Set<String> resultSet = new HashSet<>();
  77 + cloudRecordItemList.stream().forEach(cloudRecordItem -> {
  78 + String date = DateUtil.timestampTo_yyyy_MM_dd(cloudRecordItem.getStartTime());
  79 + resultSet.add(date);
  80 + });
  81 + return new ArrayList<>(resultSet);
  82 + }
  83 +
  84 + @Override
  85 + public void addRecord(OnRecordMp4HookParam param) {
  86 + CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param);
  87 + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
  88 + if (streamAuthorityInfo != null) {
  89 + cloudRecordItem.setCallId(streamAuthorityInfo.getCallId());
  90 + }
  91 + logger.info("[添加录像记录] {}/{} 文件大小:{}", param.getApp(), param.getStream(), param.getFile_size());
  92 + cloudRecordServiceMapper.add(cloudRecordItem);
  93 + }
  94 +}
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java 0 → 100644
  1 +package com.genersoft.iot.vmp.storager.dao;
  2 +
  3 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  4 +import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
  5 +import org.apache.ibatis.annotations.Insert;
  6 +import org.apache.ibatis.annotations.Mapper;
  7 +import org.apache.ibatis.annotations.Param;
  8 +import org.apache.ibatis.annotations.Select;
  9 +
  10 +import java.util.List;
  11 +
  12 +@Mapper
  13 +public interface CloudRecordServiceMapper {
  14 +
  15 + @Insert(" <script>" +
  16 + "INSERT INTO wvp_cloud_record (" +
  17 + " app," +
  18 + " stream," +
  19 + "<if test=\"callId != null\"> call_id,</if>" +
  20 + " start_time," +
  21 + " end_time," +
  22 + " media_server_id," +
  23 + " file_name," +
  24 + " folder," +
  25 + " file_path," +
  26 + " file_size," +
  27 + " time_len ) " +
  28 + "VALUES (" +
  29 + " #{app}," +
  30 + " #{stream}," +
  31 + " <if test=\"callId != null\"> #{callId},</if>" +
  32 + " #{startTime}," +
  33 + " #{endTime}," +
  34 + " #{mediaServerId}," +
  35 + " #{fileName}," +
  36 + " #{folder}," +
  37 + " #{filePath}," +
  38 + " #{fileSize}," +
  39 + " #{timeLen})" +
  40 + " </script>")
  41 + int add(CloudRecordItem cloudRecordItem);
  42 +
  43 + @Select(" <script>" +
  44 + "select * " +
  45 + "from wvp_cloud_record " +
  46 + "where 0 = 0" +
  47 + " <if test= 'app != null '> and app=#{app}</if>" +
  48 + " <if test= 'stream != null '> and stream=#{stream}</if>" +
  49 + " <if test= 'startTimeStamp != null '> and start_time &gt;= #{startTimeStamp}</if>" +
  50 + " <if test= 'endTimeStamp != null '> and end_time &lt;= #{endTimeStamp}</if>" +
  51 + " <if test= 'mediaServerItemList != null ' > and media_server_id in " +
  52 + " <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
  53 + " </if>" +
  54 + " </script>")
  55 + List<CloudRecordItem> getList(@Param("app") String app, @Param("stream") String stream,
  56 + @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp,
  57 + List<MediaServerItem> mediaServerItemList);
  58 +}
... ...
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
... ... @@ -40,11 +40,17 @@ public class DateUtil {
40 40 */
41 41 public static final String URL_PATTERN = "yyyyMMddHHmmss";
42 42  
  43 + /**
  44 + * 日期格式
  45 + */
  46 + public static final String date_PATTERN = "yyyy-MM-dd";
  47 +
43 48 public static final String zoneStr = "Asia/Shanghai";
44 49  
45 50 public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
46 51 public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
47 52 public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
  53 + public static final DateTimeFormatter DateFormatter = DateTimeFormatter.ofPattern(date_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
48 54 public static final DateTimeFormatter urlFormatter = DateTimeFormatter.ofPattern(URL_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
49 55  
50 56 public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) {
... ... @@ -72,6 +78,22 @@ public class DateUtil {
72 78 }
73 79  
74 80 /**
  81 + * 时间戳 转 yyyy_MM_dd_HH_mm_ss
  82 + */
  83 + public static String timestampTo_yyyy_MM_dd_HH_mm_ss(long timestamp) {
  84 + Instant instant = Instant.ofEpochSecond(timestamp);
  85 + return formatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr)));
  86 + }
  87 +
  88 + /**
  89 + * 时间戳 转 yyyy_MM_dd
  90 + */
  91 + public static String timestampTo_yyyy_MM_dd(long timestamp) {
  92 + Instant instant = Instant.ofEpochSecond(timestamp);
  93 + return DateFormatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr)));
  94 + }
  95 +
  96 + /**
75 97 * 获取当前时间
76 98 * @return
77 99 */
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java
... ... @@ -7,10 +7,12 @@ import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
7 7 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
8 8 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
9 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  10 +import com.genersoft.iot.vmp.service.ICloudRecordService;
10 11 import com.genersoft.iot.vmp.service.IMediaServerService;
  12 +import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
11 13 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
12   -import com.genersoft.iot.vmp.vmanager.bean.PageInfo;
13 14 import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
  15 +import com.github.pagehelper.PageInfo;
14 16 import io.swagger.v3.oas.annotations.Operation;
15 17 import io.swagger.v3.oas.annotations.Parameter;
16 18 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -41,7 +43,7 @@ public class CloudRecordController {
41 43 private final static Logger logger = LoggerFactory.getLogger(CloudRecordController.class);
42 44  
43 45 @Autowired
44   - private ZlmHttpHookSubscribe hookSubscribe;
  46 + private ICloudRecordService cloudRecordService;
45 47  
46 48 @Autowired
47 49 private IMediaServerService mediaServerService;
... ... @@ -95,7 +97,7 @@ public class CloudRecordController {
95 97 return new ArrayList<>();
96 98 }
97 99  
98   - return mediaServerService.getRecordDates(app, stream, year, month, mediaServerItems);
  100 + return cloudRecordService.getDateList(app, stream, year, month, mediaServerItems);
99 101 }
100 102  
101 103 @ResponseBody
... ... @@ -108,7 +110,7 @@ public class CloudRecordController {
108 110 @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)
109 111 @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)
110 112 @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false)
111   - public PageInfo<RecordFile> openRtpServer(
  113 + public PageInfo<CloudRecordItem> openRtpServer(
112 114 @RequestParam String app,
113 115 @RequestParam String stream,
114 116 @RequestParam int page,
... ... @@ -133,12 +135,9 @@ public class CloudRecordController {
133 135 mediaServerItems = mediaServerService.getAll();
134 136 }
135 137 if (mediaServerItems.isEmpty()) {
136   - return new PageInfo<>();
  138 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "当前无流媒体");
137 139 }
138   - List<RecordFile> records = mediaServerService.getRecords(app, stream, startTime, endTime, mediaServerItems);
139   - PageInfo<RecordFile> pageInfo = new PageInfo<>(records);
140   - pageInfo.startPage(page, count);
141   - return pageInfo;
  140 + return cloudRecordService.getList(page, count, app, stream, startTime, endTime, mediaServerItems);
142 141 }
143 142  
144 143  
... ...