Merge branch 'refs/heads/2.7.1'
# Conflicts: # pom.xml # src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java # src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java # src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java # src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java # src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java # src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
This commit is contained in:
@@ -17,7 +17,12 @@ public interface ICloudRecordService {
|
||||
/**
|
||||
* 分页回去云端录像列表
|
||||
*/
|
||||
PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServer> mediaServerItems);
|
||||
PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServer> mediaServerItems, String callId);
|
||||
|
||||
/**
|
||||
* 根据hook消息增加一条记录
|
||||
*/
|
||||
void addRecord(OnRecordMp4HookParam param);
|
||||
|
||||
/**
|
||||
* 获取所有的日期
|
||||
@@ -50,4 +55,6 @@ public interface ICloudRecordService {
|
||||
* 获取播放地址
|
||||
*/
|
||||
DownloadFileInfo getPlayUrlPath(Integer recordId);
|
||||
|
||||
List<CloudRecordItem> getAllList(String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems, String callId, List<Integer> ids);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IMobilePositionService {
|
||||
|
||||
void add(List<MobilePosition> mobilePositionList);
|
||||
|
||||
void add(MobilePosition mobilePosition);
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.service.bean;
|
||||
|
||||
import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||
import com.genersoft.iot.vmp.utils.MediaServerUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 云端录像数据
|
||||
@@ -89,6 +92,10 @@ public class CloudRecordItem {
|
||||
cloudRecordItem.setMediaServerId(param.getMediaServer().getId());
|
||||
cloudRecordItem.setTimeLen((long) param.getRecordInfo().getTimeLen() * 1000);
|
||||
cloudRecordItem.setEndTime((param.getRecordInfo().getStartTime() + (long)param.getRecordInfo().getTimeLen()) * 1000);
|
||||
Map<String, String> paramsMap = MediaServerUtils.urlParamToMap(param.getParams());
|
||||
if (paramsMap.get("callId") != null) {
|
||||
cloudRecordItem.setCallId(paramsMap.get("callId"));
|
||||
}
|
||||
return cloudRecordItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event;
|
||||
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
|
||||
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.ICloudRecordService;
|
||||
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||
@@ -28,8 +30,12 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
@DS("share")
|
||||
@@ -53,7 +59,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
||||
private VideoStreamSessionManager streamSession;
|
||||
|
||||
@Override
|
||||
public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServer> mediaServerItems) {
|
||||
public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems, String callId) {
|
||||
// 开始时间和结束时间在数据库中都是以秒为单位的
|
||||
Long startTimeStamp = null;
|
||||
Long endTimeStamp = null;
|
||||
@@ -73,7 +79,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
||||
}
|
||||
PageHelper.startPage(page, count);
|
||||
List<CloudRecordItem> all = cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp,
|
||||
null, mediaServerItems);
|
||||
callId, mediaServerItems, null);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
@@ -89,7 +95,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
||||
long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond() * 1000;
|
||||
long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond() * 1000;
|
||||
List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp,
|
||||
endTimeStamp, null, mediaServerItems);
|
||||
endTimeStamp, null, mediaServerItems, null);
|
||||
if (cloudRecordItemList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
@@ -105,10 +111,6 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
||||
@EventListener
|
||||
public void onApplicationEvent(MediaRecordMp4Event event) {
|
||||
CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(event);
|
||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(event.getApp(), event.getStream());
|
||||
if (streamAuthorityInfo != null) {
|
||||
cloudRecordItem.setCallId(streamAuthorityInfo.getCallId());
|
||||
}
|
||||
logger.info("[添加录像记录] {}/{} 内容:{}", event.getApp(), event.getStream(), event.getRecordInfo());
|
||||
cloudRecordServiceMapper.add(cloudRecordItem);
|
||||
}
|
||||
@@ -199,7 +201,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
||||
}
|
||||
|
||||
List<CloudRecordItem> all = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, endTimeStamp,
|
||||
callId, mediaServerItems);
|
||||
callId, mediaServerItems, null);
|
||||
if (all.isEmpty()) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到待收藏的视频");
|
||||
}
|
||||
@@ -235,4 +237,27 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
||||
MediaServer mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId());
|
||||
return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CloudRecordItem> getAllList(String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems, String callId, List<Integer> ids) {
|
||||
// 开始时间和结束时间在数据库中都是以秒为单位的
|
||||
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_ssToTimestampMs(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_ssToTimestampMs(endTime);
|
||||
|
||||
}
|
||||
return cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp,
|
||||
callId, mediaServerItems, ids);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,12 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
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.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.service.*;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
|
||||
import com.genersoft.iot.vmp.service.IMobilePositionService;
|
||||
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
|
||||
import com.genersoft.iot.vmp.storager.dao.DeviceMobilePositionMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Service
|
||||
public class MobilePositionServiceImpl implements IMobilePositionService {
|
||||
|
||||
@Autowired
|
||||
private DeviceChannelMapper channelMapper;
|
||||
|
||||
@Autowired
|
||||
private DeviceMobilePositionMapper mobilePositionMapper;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, MobilePosition> redisTemplate;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(MobilePositionServiceImpl.class);
|
||||
|
||||
private final String REDIS_MOBILE_POSITION_LIST = "redis_mobile_position_list";
|
||||
|
||||
@Override
|
||||
public void add(MobilePosition mobilePosition) {
|
||||
List<MobilePosition> list = new ArrayList<>();
|
||||
list.add(mobilePosition);
|
||||
add(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(List<MobilePosition> mobilePositionList) {
|
||||
redisTemplate.opsForList().leftPushAll(REDIS_MOBILE_POSITION_LIST, mobilePositionList);
|
||||
}
|
||||
|
||||
private List<MobilePosition> get(int length) {
|
||||
Long size = redisTemplate.opsForList().size(REDIS_MOBILE_POSITION_LIST);
|
||||
if (size == null || size == 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<MobilePosition> mobilePositions;
|
||||
if (size > length) {
|
||||
mobilePositions = redisTemplate.opsForList().rightPop(REDIS_MOBILE_POSITION_LIST, length);
|
||||
}else {
|
||||
mobilePositions = redisTemplate.opsForList().rightPop(REDIS_MOBILE_POSITION_LIST, size);
|
||||
}
|
||||
return mobilePositions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Scheduled(fixedRate = 1000)
|
||||
@Transactional
|
||||
public void executeTaskQueue() {
|
||||
int countLimit = 3000;
|
||||
List<MobilePosition> mobilePositions = get(countLimit);
|
||||
if (mobilePositions == null || mobilePositions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (userSetting.getSavePositionHistory()) {
|
||||
mobilePositionMapper.batchadd(mobilePositions);
|
||||
}
|
||||
logger.info("[移动位置订阅]更新通道位置: {}", mobilePositions.size());
|
||||
Map<String, DeviceChannel> updateChannelMap = new HashMap<>();
|
||||
for (MobilePosition mobilePosition : mobilePositions) {
|
||||
DeviceChannel deviceChannel = new DeviceChannel();
|
||||
deviceChannel.setDeviceId(mobilePosition.getDeviceId());
|
||||
deviceChannel.setLongitude(mobilePosition.getLongitude());
|
||||
deviceChannel.setLatitude(mobilePosition.getLatitude());
|
||||
deviceChannel.setGpsTime(mobilePosition.getTime());
|
||||
updateChannelMap.put(mobilePosition.getDeviceId() + mobilePosition.getChannelId(), deviceChannel);
|
||||
}
|
||||
List<DeviceChannel> channels = new ArrayList<>(updateChannelMap.values());
|
||||
channelMapper.batchUpdatePosition(channels);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -349,6 +349,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
}
|
||||
String msgResult;
|
||||
if ("ffmpeg".equalsIgnoreCase(param.getType())){
|
||||
if (param.getTimeoutMs() == 0) {
|
||||
param.setTimeoutMs(15);
|
||||
}
|
||||
result = mediaServerService.addFFmpegSource(mediaServer, param.getSrcUrl().trim(), param.getDstUrl(),
|
||||
param.getTimeoutMs(), param.isEnableAudio(), param.isEnableMp4(),
|
||||
param.getFfmpegCmdKey());
|
||||
@@ -406,6 +409,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
gbStreamMapper.del(app, stream);
|
||||
videoManagerStorager.deleteStreamProxy(app, stream);
|
||||
redisCatchStorage.removeStream(streamProxyItem.getMediaServerId(), "PULL", app, stream);
|
||||
redisCatchStorage.removeStream(streamProxyItem.getMediaServerId(), "PUSH", app, stream);
|
||||
Boolean result = removeStreamProxyFromZlm(streamProxyItem);
|
||||
if (result != null && result) {
|
||||
logger.info("[移除代理]: 代理: {}/{}, 从zlm移除成功", app, stream);
|
||||
|
||||
Reference in New Issue
Block a user