| | |
| | | add stream_key varying(255) |
| | | |
| | | create table wvp_cloud_record ( |
| | | id serial primary key, |
| | | app character varying(255), |
| | | stream character varying(255), |
| | | call_id character varying(255), |
| | | start_time integer, |
| | | end_time integer, |
| | | media_server_id character varying(50), |
| | | file_name character varying(50), |
| | | folder character varying(50), |
| | | file_path character varying(255), |
| | | file_size integer, |
| | | time_len integer, |
| | | constraint uk_stream_push_app_stream_path unique (app, stream, file_path) |
| | | id serial primary key, |
| | | app character varying(255), |
| | | stream character varying(255), |
| | | call_id character varying(255), |
| | | start_time integer, |
| | | end_time integer, |
| | | media_server_id character varying(50), |
| | | file_name character varying(255), |
| | | folder character varying(255), |
| | | file_path character varying(255), |
| | | collect_type character varying(255), |
| | | file_size integer, |
| | | time_len integer, |
| | | constraint uk_stream_push_app_stream_path unique (app, stream, file_path) |
| | | ); |
| | |
| | | constraint uk_stream_push_app_stream unique (app, stream) |
| | | ); |
| | | create table wvp_cloud_record ( |
| | | id serial primary key, |
| | | app character varying(255), |
| | | stream character varying(255), |
| | | call_id character varying(255), |
| | | start_time integer, |
| | | end_time integer, |
| | | mediaServerId character varying(50), |
| | | file_name character varying(50), |
| | | folder character varying(50), |
| | | file_path character varying(255), |
| | | file_size integer, |
| | | time_len integer, |
| | | constraint uk_stream_push_app_stream_path unique (app, stream, file_path) |
| | | id serial primary key, |
| | | app character varying(255), |
| | | stream character varying(255), |
| | | call_id character varying(255), |
| | | start_time integer, |
| | | end_time integer, |
| | | media_server_id character varying(50), |
| | | file_name character varying(255), |
| | | folder character varying(255), |
| | | file_path character varying(255), |
| | | collect_type character varying(255), |
| | | file_size integer, |
| | | time_len integer, |
| | | constraint uk_stream_push_app_stream_path unique (app, stream, file_path) |
| | | ); |
| | | |
| | | create table wvp_user ( |
| | |
| | | private IUserService userService; |
| | | |
| | | @Autowired |
| | | private ICloudRecordService cloudRecordService; |
| | | |
| | | @Autowired |
| | | private VideoStreamSessionManager sessionManager; |
| | | |
| | | @Autowired |
| | |
| | | logger.info("[ZLM HOOK] å½å宿äºä»¶ï¼{}->{}", param.getMediaServerId(), param.getFile_path()); |
| | | |
| | | taskExecutor.execute(() -> { |
| | | |
| | | cloudRecordService.addRecord(param); |
| | | }); |
| | | |
| | | return HookResult.SUCCESS(); |
| | |
| | | private String stream; |
| | | private String file_name; |
| | | private String file_path; |
| | | private String file_size; |
| | | private long file_size; |
| | | private String folder; |
| | | private String url; |
| | | private String vhost; |
| | |
| | | this.file_path = file_path; |
| | | } |
| | | |
| | | public String getFile_size() { |
| | | public long getFile_size() { |
| | | return file_size; |
| | | } |
| | | |
| | | public void setFile_size(String file_size) { |
| | | public void setFile_size(long file_size) { |
| | | this.file_size = file_size; |
| | | } |
| | | |
| | |
| | | package com.genersoft.iot.vmp.service; |
| | | |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; |
| | | import com.genersoft.iot.vmp.service.bean.CloudRecordItem; |
| | | import com.github.pagehelper.PageInfo; |
| | | |
| | |
| | | /** |
| | | * å页åå»äºç«¯å½åå表 |
| | | */ |
| | | PageInfo<CloudRecordItem> getList(int page, int count, String startTime, String endTime); |
| | | PageInfo<CloudRecordItem> getList(int page, int count, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); |
| | | |
| | | /** |
| | | * æ ¹æ®hookæ¶æ¯å¢å 䏿¡è®°å½ |
| | | */ |
| | | void addRecord(OnRecordMp4HookParam param); |
| | | |
| | | /** |
| | | * è·åææçæ¥æ |
| | | */ |
| | | List<String> getDateList(Integer year, Integer month, String app, String stream); |
| | | |
| | | |
| | | |
| | | List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); |
| | | |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.service.bean; |
| | | |
| | | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; |
| | | |
| | | /** |
| | | * äºç«¯å½åæ°æ® |
| | | */ |
| | |
| | | */ |
| | | private long timeLen; |
| | | |
| | | public static CloudRecordItem getInstance(OnRecordMp4HookParam param) { |
| | | CloudRecordItem cloudRecordItem = new CloudRecordItem(); |
| | | cloudRecordItem.setApp(param.getApp()); |
| | | cloudRecordItem.setStream(param.getStream()); |
| | | cloudRecordItem.setStartTime(param.getStart_time()); |
| | | cloudRecordItem.setFileName(param.getFile_name()); |
| | | cloudRecordItem.setFolder(param.getFolder()); |
| | | cloudRecordItem.setFileSize(param.getFile_size()); |
| | | cloudRecordItem.setFilePath(param.getFile_path()); |
| | | cloudRecordItem.setMediaServerId(param.getMediaServerId()); |
| | | cloudRecordItem.setTimeLen(param.getTime_len()); |
| | | cloudRecordItem.setEndTime(param.getStart_time() + param.getTime_len()); |
| | | return cloudRecordItem; |
| | | } |
| | | |
| | | public int getId() { |
| | | return id; |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.service.impl; |
| | | |
| | | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| | | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; |
| | | import com.genersoft.iot.vmp.service.ICloudRecordService; |
| | | import com.genersoft.iot.vmp.service.bean.CloudRecordItem; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| | | import com.github.pagehelper.PageHelper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.unit.DataUnit; |
| | | |
| | | import java.time.*; |
| | | import java.time.temporal.TemporalAccessor; |
| | | import java.util.*; |
| | | |
| | | @Service |
| | | public class CloudRecordServiceImpl implements ICloudRecordService { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(CloudRecordServiceImpl.class); |
| | | |
| | | @Autowired |
| | | private CloudRecordServiceMapper cloudRecordServiceMapper; |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Override |
| | | public PageInfo<CloudRecordItem> getList(int page, int count, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { |
| | | // å¼å§æ¶é´åç»ææ¶é´å¨æ°æ®åºä¸é½æ¯ä»¥ç§ä¸ºåä½ç |
| | | Long startTimeStamp = null; |
| | | Long endTimeStamp = null; |
| | | if (startTime != null ) { |
| | | if (!DateUtil.verification(startTime, DateUtil.formatter)) { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "å¼å§æ¶é´æ ¼å¼éè¯¯ï¼æ£ç¡®æ ¼å¼ä¸ºï¼ " + DateUtil.formatter); |
| | | } |
| | | startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); |
| | | |
| | | } |
| | | if (endTime != null ) { |
| | | if (!DateUtil.verification(endTime, DateUtil.formatter)) { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "ç»ææ¶é´æ ¼å¼éè¯¯ï¼æ£ç¡®æ ¼å¼ä¸ºï¼ " + DateUtil.formatter); |
| | | } |
| | | endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); |
| | | |
| | | } |
| | | PageHelper.startPage(page, count); |
| | | List<CloudRecordItem> all = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, mediaServerItems); |
| | | return new PageInfo<>(all); |
| | | } |
| | | |
| | | @Override |
| | | public List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) { |
| | | LocalDate startDate = LocalDate.of(year, month, 1); |
| | | LocalDate endDate; |
| | | if (month == 12) { |
| | | endDate = LocalDate.of(year + 1, 1, 1); |
| | | }else { |
| | | endDate = LocalDate.of(year, month + 1, 1); |
| | | } |
| | | long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); |
| | | long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); |
| | | List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, mediaServerItems); |
| | | if (cloudRecordItemList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | | Set<String> resultSet = new HashSet<>(); |
| | | cloudRecordItemList.stream().forEach(cloudRecordItem -> { |
| | | String date = DateUtil.timestampTo_yyyy_MM_dd(cloudRecordItem.getStartTime()); |
| | | resultSet.add(date); |
| | | }); |
| | | return new ArrayList<>(resultSet); |
| | | } |
| | | |
| | | @Override |
| | | public void addRecord(OnRecordMp4HookParam param) { |
| | | CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param); |
| | | StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); |
| | | if (streamAuthorityInfo != null) { |
| | | cloudRecordItem.setCallId(streamAuthorityInfo.getCallId()); |
| | | } |
| | | logger.info("[æ·»å å½åè®°å½] {}/{} æä»¶å¤§å°ï¼{}", param.getApp(), param.getStream(), param.getFile_size()); |
| | | cloudRecordServiceMapper.add(cloudRecordItem); |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.storager.dao; |
| | | |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.service.bean.CloudRecordItem; |
| | | import org.apache.ibatis.annotations.Insert; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.apache.ibatis.annotations.Select; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface CloudRecordServiceMapper { |
| | | |
| | | @Insert(" <script>" + |
| | | "INSERT INTO wvp_cloud_record (" + |
| | | " app," + |
| | | " stream," + |
| | | "<if test=\"callId != null\"> call_id,</if>" + |
| | | " start_time," + |
| | | " end_time," + |
| | | " media_server_id," + |
| | | " file_name," + |
| | | " folder," + |
| | | " file_path," + |
| | | " file_size," + |
| | | " time_len ) " + |
| | | "VALUES (" + |
| | | " #{app}," + |
| | | " #{stream}," + |
| | | " <if test=\"callId != null\"> #{callId},</if>" + |
| | | " #{startTime}," + |
| | | " #{endTime}," + |
| | | " #{mediaServerId}," + |
| | | " #{fileName}," + |
| | | " #{folder}," + |
| | | " #{filePath}," + |
| | | " #{fileSize}," + |
| | | " #{timeLen})" + |
| | | " </script>") |
| | | int add(CloudRecordItem cloudRecordItem); |
| | | |
| | | @Select(" <script>" + |
| | | "select * " + |
| | | "from wvp_cloud_record " + |
| | | "where 0 = 0" + |
| | | " <if test= 'app != null '> and app=#{app}</if>" + |
| | | " <if test= 'stream != null '> and stream=#{stream}</if>" + |
| | | " <if test= 'startTimeStamp != null '> and start_time >= #{startTimeStamp}</if>" + |
| | | " <if test= 'endTimeStamp != null '> and end_time <= #{endTimeStamp}</if>" + |
| | | " <if test= 'mediaServerItemList != null ' > and media_server_id in " + |
| | | " <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + |
| | | " </if>" + |
| | | " </script>") |
| | | List<CloudRecordItem> getList(@Param("app") String app, @Param("stream") String stream, |
| | | @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, |
| | | List<MediaServerItem> mediaServerItemList); |
| | | } |
| | |
| | | */ |
| | | public static final String URL_PATTERN = "yyyyMMddHHmmss"; |
| | | |
| | | /** |
| | | * æ¥ææ ¼å¼ |
| | | */ |
| | | public static final String date_PATTERN = "yyyy-MM-dd"; |
| | | |
| | | public static final String zoneStr = "Asia/Shanghai"; |
| | | |
| | | public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| | | public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| | | public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| | | public static final DateTimeFormatter DateFormatter = DateTimeFormatter.ofPattern(date_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| | | public static final DateTimeFormatter urlFormatter = DateTimeFormatter.ofPattern(URL_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| | | |
| | | public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * æ¶é´æ³ 转 yyyy_MM_dd_HH_mm_ss |
| | | */ |
| | | public static String timestampTo_yyyy_MM_dd_HH_mm_ss(long timestamp) { |
| | | Instant instant = Instant.ofEpochSecond(timestamp); |
| | | return formatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr))); |
| | | } |
| | | |
| | | /** |
| | | * æ¶é´æ³ 转 yyyy_MM_dd |
| | | */ |
| | | public static String timestampTo_yyyy_MM_dd(long timestamp) { |
| | | Instant instant = Instant.ofEpochSecond(timestamp); |
| | | return DateFormatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr))); |
| | | } |
| | | |
| | | /** |
| | | * è·åå½åæ¶é´ |
| | | * @return |
| | | */ |
| | |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.service.ICloudRecordService; |
| | | import com.genersoft.iot.vmp.service.IMediaServerService; |
| | | import com.genersoft.iot.vmp.service.bean.CloudRecordItem; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| | | import com.genersoft.iot.vmp.vmanager.bean.PageInfo; |
| | | import com.genersoft.iot.vmp.vmanager.bean.RecordFile; |
| | | import com.github.pagehelper.PageInfo; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | |
| | | private final static Logger logger = LoggerFactory.getLogger(CloudRecordController.class); |
| | | |
| | | @Autowired |
| | | private ZlmHttpHookSubscribe hookSubscribe; |
| | | private ICloudRecordService cloudRecordService; |
| | | |
| | | @Autowired |
| | | private IMediaServerService mediaServerService; |
| | |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | return mediaServerService.getRecordDates(app, stream, year, month, mediaServerItems); |
| | | return cloudRecordService.getDateList(app, stream, year, month, mediaServerItems); |
| | | } |
| | | |
| | | @ResponseBody |
| | |
| | | @Parameter(name = "startTime", description = "å¼å§æ¶é´(yyyy-MM-dd HH:mm:ss)", required = true) |
| | | @Parameter(name = "endTime", description = "ç»ææ¶é´(yyyy-MM-dd HH:mm:ss)", required = true) |
| | | @Parameter(name = "mediaServerId", description = "æµåªä½IDï¼ç½®ç©ºåæ¥è¯¢å
¨é¨æµåªä½", required = false) |
| | | public PageInfo<RecordFile> openRtpServer( |
| | | public PageInfo<CloudRecordItem> openRtpServer( |
| | | @RequestParam String app, |
| | | @RequestParam String stream, |
| | | @RequestParam int page, |
| | |
| | | mediaServerItems = mediaServerService.getAll(); |
| | | } |
| | | if (mediaServerItems.isEmpty()) { |
| | | return new PageInfo<>(); |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "å½åæ æµåªä½"); |
| | | } |
| | | List<RecordFile> records = mediaServerService.getRecords(app, stream, startTime, endTime, mediaServerItems); |
| | | PageInfo<RecordFile> pageInfo = new PageInfo<>(records); |
| | | pageInfo.startPage(page, count); |
| | | return pageInfo; |
| | | return cloudRecordService.getList(page, count, app, stream, startTime, endTime, mediaServerItems); |
| | | } |
| | | |
| | | |
| | |
| | | <li v-for="(item,index) in detailFiles" :key="index" class="infinite-list-item record-list-item" > |
| | | <el-tag v-if="choosedFile !== item.filename" @click="chooseFile(item)"> |
| | | <i class="el-icon-video-camera" ></i> |
| | | {{ getFileShowName(item.fileName) }} |
| | | {{ getFileShowName(item) }} |
| | | </el-tag> |
| | | <el-tag type="danger" v-if="choosedFile === item.filename"> |
| | | <i class="el-icon-video-camera" ></i> |
| | | {{ getFileShowName(item.fileName) }} |
| | | {{ getFileShowName(item) }} |
| | | </el-tag> |
| | | <a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" |
| | | :href="`${getFileBasePath(item)}/download.html?url=download/${app}/${stream}/${chooseDate}/${item.fileName}`" |
| | |
| | | this.choosedFile = ""; |
| | | }else { |
| | | this.choosedFile = file.fileName; |
| | | this.videoUrl = `${this.getFileBasePath(file)}/download/${this.app}/${this.stream}/${this.chooseDate}/${this.choosedFile}` |
| | | this.videoUrl = `${this.getFileBasePath(file)}/download/${this.app}/${this.stream}/${this.chooseDate}/${file.fileName}` |
| | | console.log(this.videoUrl) |
| | | } |
| | | |
| | |
| | | backToList() { |
| | | this.$router.back() |
| | | }, |
| | | getFileShowName(name) { |
| | | return name.substring(0, 2) + ":" + name.substring(2, 4) + ":" + name.substring(4, 6) + "-" + |
| | | name.substring(7, 9) + ":" + name.substring(9, 11) + ":" + name.substring(11, 13) |
| | | getFileShowName(item) { |
| | | return moment.unix(item.startTime).format('HH:mm:ss') + "-" + moment.unix(item.endTime).format('HH:mm:ss') |
| | | }, |
| | | chooseMediaChange() { |
| | | |
| | |
| | | }, |
| | | getTimeForFile(file){ |
| | | console.log(file) |
| | | let timeStr = file.fileName.substring(0, 17); |
| | | if(timeStr.indexOf("~") > 0){ |
| | | timeStr = timeStr.replaceAll("-",":") |
| | | } |
| | | let timeArr = timeStr.split("-"); |
| | | let starTime = new Date(this.chooseDate + " " + timeArr[0]); |
| | | let endTime = new Date(this.chooseDate + " " + timeArr[1]); |
| | | let starTime = new Date(file.startTime * 1000); |
| | | let endTime = new Date(file.endTime * 1000); |
| | | if(this.checkIsOver24h(starTime,endTime)){ |
| | | endTime = new Date(this.chooseDate + " " + "23:59:59"); |
| | | } |