From 2c89fae49a7655105b4e9e0138155485e6ba83b2 Mon Sep 17 00:00:00 2001
From: 648540858 <648540858@qq.com>
Date: 星期四, 23 五月 2024 17:32:15 +0800
Subject: [PATCH] Merge branch 'refs/heads/2.7.1'

---
 src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java                                         |   45 +
 src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java                                       |    7 
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java                                               |    6 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java                                     |    4 
 src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java                                       |    5 
 src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java                                             |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java                               |    1 
 src/main/java/com/genersoft/iot/vmp/service/IMobilePositionService.java                                              |   13 
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                                         |    2 
 src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java                                                        |    2 
 src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java                                                            |   10 
 src/main/resources/application-dev.yml                                                                               |    3 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java                                     |   10 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java                                               |   11 
 src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java                                                |    1 
 src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java                                              |   17 
 数据库/2.7.1/更新-mysql-2.7.1.sql                                                                                         |    2 
 src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java                                                 |    9 
 src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java                                                              |    8 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java |   41 -
 src/main/resources/all-application.yml                                                                               |    2 
 数据库/2.7.1/更新-postgresql-kingbase-2.7.1.sql                                                                           |    2 
 src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java                                  |  229 +++++++++
 数据库/2.7.1/初始化-postgresql-kingbase-2.7.1.sql                                                                          |  325 ++++++++++++++
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                                               |   46 +
 src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java                                              |    4 
 src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java                                                      |   12 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java                           |    4 
 src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java                                                |    7 
 src/main/java/com/genersoft/iot/vmp/service/impl/MobilePositionServiceImpl.java                                      |   95 ++++
 src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/bean/CloudRecordUrl.java                                    |   32 +
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java                                        |    4 
 src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java                                         |    4 
 src/main/java/com/genersoft/iot/vmp/utils/MediaServerUtils.java                                                      |   26 +
 数据库/2.7.1/初始化-mysql-2.7.1.sql                                                                                        |  325 ++++++++++++++
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java                                            |   37 
 36 files changed, 1,256 insertions(+), 97 deletions(-)

diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
index 0a472f8..45f9a2f 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
@@ -7,6 +7,7 @@
 import io.swagger.v3.oas.models.info.Info;
 import io.swagger.v3.oas.models.info.License;
 import io.swagger.v3.oas.models.security.SecurityScheme;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.core.annotation.Order;
 import org.springdoc.core.GroupedOpenApi;
 import org.springframework.beans.factory.annotation.Value;
@@ -18,6 +19,7 @@
  */
 @Configuration
 @Order(1)
+@ConditionalOnProperty(value = "user-settings.doc-enable", havingValue = "true", matchIfMissing = true)
 public class SpringDocConfig {
 
     @Value("${doc.enabled: true}")
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
index a9b17ae..96253d6 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -54,6 +54,8 @@
     private Boolean deviceStatusNotify = Boolean.TRUE;
     private Boolean useCustomSsrcForParentInvite = Boolean.TRUE;
 
+    private Boolean docEnable = Boolean.TRUE;
+
     private String serverId = "000000";
 
     private String thirdPartyGBIdReg = "[\\s\\S]*";
@@ -315,4 +317,12 @@
     public void setRegisterKeepIntDialog(boolean registerKeepIntDialog) {
         this.registerKeepIntDialog = registerKeepIntDialog;
     }
+
+    public Boolean getDocEnable() {
+        return docEnable;
+    }
+
+    public void setDocEnable(Boolean docEnable) {
+        this.docEnable = docEnable;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java
index df3345e..2dc66b3 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java
@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.conf.redis;
 
 import com.alibaba.fastjson2.support.spring.data.redis.GenericFastJsonRedisSerializer;
+import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -25,4 +26,20 @@
         redisTemplate.setConnectionFactory(redisConnectionFactory);
         return redisTemplate;
     }
+
+    @Bean
+    public RedisTemplate<String, MobilePosition> getRedisTemplateForMobilePosition(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<String, MobilePosition> redisTemplate = new RedisTemplate<>();
+        // 浣跨敤fastJson搴忓垪鍖�
+        GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
+        // value鍊肩殑搴忓垪鍖栭噰鐢╢astJsonRedisSerializer
+        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
+        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
+
+        // key鐨勫簭鍒楀寲閲囩敤StringRedisSerializer
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+        return redisTemplate;
+    }
 }
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 274a19f..ebeea98 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
@@ -35,10 +35,15 @@
 
         // 蹇界暐鐧诲綍璇锋眰鐨則oken楠岃瘉
         String requestURI = request.getRequestURI();
+        if ((requestURI.startsWith("/doc.html") || requestURI.startsWith("/swagger-ui") ) && !userSetting.getDocEnable()) {
+            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
         if (requestURI.equalsIgnoreCase("/api/user/login")) {
             chain.doFilter(request, response);
             return;
         }
+
         if (!userSetting.isInterfaceAuthentication()) {
             UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() );
             SecurityContextHolder.getContext().setAuthentication(token);
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
index b035fcb..ee45e4d 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -117,7 +117,7 @@
                 .authorizeRequests()
                 .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                 .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
-                .antMatchers("/api/user/login", "/index/hook/**","/index/hook/abl/**", "/swagger-ui/**", "/doc.html").permitAll()
+                .antMatchers("/api/user/login", "/index/hook/**","/index/hook/abl/**", "/swagger-ui/**", "/doc.html#/**").permitAll()
                 .anyRequest().authenticated()
                 // 寮傚父澶勭悊鍣�
                 .and()
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
index 3a9f5fb..dd30fea 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -168,6 +168,7 @@
 		// via
 		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
 		ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
+//		viaHeader.setRPort();
 		viaHeaders.add(viaHeader);
 		//from
 		SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
index 9fb1d4d..6a6bfcf 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -515,9 +515,7 @@
         if (parentPlatform == null) {
             return;
         }
-        if (logger.isDebugEnabled()) {
-            logger.debug("[鍙戦�� 绉诲姩浣嶇疆璁㈤槄] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat());
-        }
+        logger.info("[鍙戦�� 绉诲姩浣嶇疆璁㈤槄] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat());
 
         String characterSet = parentPlatform.getCharacterSet();
         StringBuffer deviceStatusXml = new StringBuffer(600);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java
index a8c4af8..52fc7a3 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java
@@ -11,6 +11,7 @@
 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.service.IDeviceChannelService;
+import com.genersoft.iot.vmp.service.IMobilePositionService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import org.dom4j.DocumentException;
@@ -20,15 +21,11 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ObjectUtils;
 
 import javax.sip.RequestEvent;
 import javax.sip.header.FromHeader;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
@@ -54,6 +51,9 @@
 	@Autowired
 	private IDeviceChannelService deviceChannelService;
 
+	@Autowired
+	private IMobilePositionService mobilePositionService;
+
 	public void process(RequestEvent evt) {
 
 		if (taskQueue.size() >= userSetting.getMaxNotifyCountQueue()) {
@@ -64,13 +64,10 @@
 	}
 
 	@Scheduled(fixedRate = 200) //姣�200姣鎵ц涓�娆�
-	@Transactional
 	public void executeTaskQueue() {
 		if (taskQueue.isEmpty()) {
 			return;
 		}
-		Map<String, DeviceChannel> updateChannelMap = new ConcurrentHashMap<>();
-		List<MobilePosition> addMobilePositionList = new ArrayList<>();
 		for (HandlerCatchData take : taskQueue) {
 			if (take == null) {
 				continue;
@@ -146,20 +143,11 @@
 					}
 				}
 
-//			logger.info("[鏀跺埌绉诲姩浣嶇疆璁㈤槄閫氱煡]锛歿}/{}->{}.{}, 鏃堕棿锛� {}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
-//					mobilePosition.getLongitude(), mobilePosition.getLatitude(), System.currentTimeMillis() - startTime);
+			logger.debug("[鏀跺埌绉诲姩浣嶇疆璁㈤槄閫氱煡]锛歿}/{}->{}.{}, 鏃堕棿锛� {}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
+					mobilePosition.getLongitude(), mobilePosition.getLatitude(), System.currentTimeMillis() - startTime);
 				mobilePosition.setReportSource("Mobile Position");
 
-				// 鏇存柊device channel 鐨勭粡绾害
-				DeviceChannel deviceChannel = new DeviceChannel();
-				deviceChannel.setDeviceId(device.getDeviceId());
-				deviceChannel.setLongitude(mobilePosition.getLongitude());
-				deviceChannel.setLatitude(mobilePosition.getLatitude());
-				deviceChannel.setGpsTime(mobilePosition.getTime());
-				updateChannelMap.put(deviceId + mobilePosition.getChannelId(), deviceChannel);
-				addMobilePositionList.add(mobilePosition);
-
-
+				mobilePositionService.add(mobilePosition);
 				// 鍚戝叧鑱斾簡璇ラ�氶亾骞朵笖寮�鍚Щ鍔ㄤ綅缃闃呯殑涓婄骇骞冲彴鍙戦�佺Щ鍔ㄤ綅缃闃呮秷鎭�
 				try {
 					eventPublisher.mobilePositionEventPublish(mobilePosition);
@@ -199,21 +187,6 @@
 			}
 		}
 		taskQueue.clear();
-		if(!updateChannelMap.isEmpty()) {
-			List<DeviceChannel>  channels = new ArrayList<>(updateChannelMap.values());
-			logger.info("[绉诲姩浣嶇疆璁㈤槄]鏇存柊閫氶亾浣嶇疆锛� {}", channels.size());
-			deviceChannelService.batchUpdateChannel(channels);
-			updateChannelMap.clear();
-		}
-		if (userSetting.isSavePositionHistory() && !addMobilePositionList.isEmpty()) {
-			try {
-				logger.info("[绉诲姩浣嶇疆璁㈤槄] 娣诲姞閫氶亾杞ㄨ抗鐐逛綅锛� {}", addMobilePositionList.size());
-				deviceChannelService.batchAddMobilePosition(addMobilePositionList);
-			}catch (Exception e) {
-				logger.info("[绉诲姩浣嶇疆璁㈤槄] b娣诲姞閫氶亾杞ㄨ抗鐐逛綅淇濆瓨澶辫触锛� {}", addMobilePositionList.size());
-			}
-			addMobilePositionList.clear();
-		}
 	}
 	@Scheduled(fixedRate = 10000)
 	public void execute(){
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 decbd4e..c951e41 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
@@ -100,6 +100,9 @@
     @Schema(description = "绫诲瀷锛� zlm/abl")
     private String type;
 
+    @Schema(description = "杞爜鐨勫墠缂�")
+    private String transcodeSuffix;
+
     public MediaServer() {
     }
 
@@ -126,6 +129,7 @@
         rtpEnable = false; // 榛樿浣跨敤鍗曠鍙�;鐩村埌鐢ㄦ埛鑷繁璁剧疆寮�鍚绔彛
         rtpPortRange = zlmServerConfig.getPortRange().replace("_",","); // 榛樿浣跨敤30000,30500浣滀负绾ц仈鏃跺彂閫佹祦鐨勭鍙e彿
         recordAssistPort = 0; // 榛樿鍏抽棴
+        transcodeSuffix = zlmServerConfig.getTranscodeSuffix();
 
     }
 
@@ -376,4 +380,12 @@
     public void setWsFlvSSLPort(int wsFlvSSLPort) {
         this.wsFlvSSLPort = wsFlvSSLPort;
     }
+
+    public String getTranscodeSuffix() {
+        return transcodeSuffix;
+    }
+
+    public void setTranscodeSuffix(String transcodeSuffix) {
+        this.transcodeSuffix = transcodeSuffix;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
index 7fffc10..f799a93 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
@@ -104,7 +104,6 @@
                 return port;
             }
         }
-
     }
 
     interface CheckPortCallback{
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
index bfe54a2..8b8389e 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -24,6 +24,12 @@
 import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import com.genersoft.iot.vmp.utils.DateUtil;
+import com.genersoft.iot.vmp.utils.MediaServerUtils;
+import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
+import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -36,6 +42,10 @@
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.HashMap;
+import javax.sip.InvalidArgumentException;
+import javax.sip.SipException;
+import java.text.ParseException;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -202,6 +212,11 @@
         if (mediaServer == null) {
             return HookResult.SUCCESS();
         }
+        if (!ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix())
+                && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())
+                && param.getStream().endsWith(mediaServer.getTranscodeSuffix())  ) {
+            return;
+        }
         if (param.getSchema().equalsIgnoreCase("rtsp")) {
             if (param.isRegist()) {
                 logger.info("[ZLM HOOK] 娴佹敞鍐�, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
@@ -226,6 +241,19 @@
 
         logger.info("[ZLM HOOK]娴佹棤浜鸿鐪嬶細{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
                 param.getApp(), param.getStream());
+
+        MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
+        if (mediaInfo == null) {
+            JSONObject ret = new JSONObject();
+            ret.put("code", 0);
+            return ret;
+        }
+        if (!ObjectUtils.isEmpty(mediaInfo.getTranscodeSuffix())
+                && !"null".equalsIgnoreCase(mediaInfo.getTranscodeSuffix())
+                && param.getStream().endsWith(mediaInfo.getTranscodeSuffix())  ) {
+            param.setStream(param.getStream().substring(0, param.getStream().lastIndexOf(mediaInfo.getTranscodeSuffix()) -1 ));
+        }
+
         JSONObject ret = new JSONObject();
         boolean close = mediaService.closeStreamOnNoneReader(param.getMediaServerId(), param.getApp(), param.getStream(), param.getSchema());
         ret.put("code", 0);
@@ -347,23 +375,5 @@
         }
 
         return HookResult.SUCCESS();
-    }
-
-    private Map<String, String> urlParamToMap(String params) {
-        HashMap<String, String> map = new HashMap<>();
-        if (ObjectUtils.isEmpty(params)) {
-            return map;
-        }
-        String[] paramsArray = params.split("&");
-        if (paramsArray.length == 0) {
-            return map;
-        }
-        for (String param : paramsArray) {
-            String[] paramArray = param.split("=");
-            if (paramArray.length == 2) {
-                map.put(paramArray[0], paramArray[1]);
-            }
-        }
-        return map;
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java
index 8f77b63..05fc57d 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java
@@ -331,6 +331,9 @@
     @JSONField(name = "shell.shell")
     private String shellPhell;
 
+    @JSONField(name = "transcode.suffix")
+    private String transcodeSuffix;
+
 
     public String getHookIp() {
         return hookIp;
@@ -1211,4 +1214,12 @@
     public void setHookOnRtpServerTimeout(String hookOnRtpServerTimeout) {
         this.hookOnRtpServerTimeout = hookOnRtpServerTimeout;
     }
+
+    public String getTranscodeSuffix() {
+        return transcodeSuffix;
+    }
+
+    public void setTranscodeSuffix(String transcodeSuffix) {
+        this.transcodeSuffix = transcodeSuffix;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
index d52165e..deeeff4 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
@@ -15,6 +15,7 @@
     private String vhost;
     private long start_time;
     private double time_len;
+    private String params;
 
     public String getApp() {
         return app;
@@ -96,6 +97,14 @@
         this.time_len = time_len;
     }
 
+    public String getParams() {
+        return params;
+    }
+
+    public void setParams(String params) {
+        this.params = params;
+    }
+
     @Override
     public String toString() {
         return "OnRecordMp4HookParam{" +
@@ -109,6 +118,7 @@
                 ", vhost='" + vhost + '\'' +
                 ", start_time=" + start_time +
                 ", time_len=" + time_len +
+                ", params=" + params +
                 '}';
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
index 875140f..df7024f 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
@@ -17,7 +17,12 @@
     /**
      * 鍒嗛〉鍥炲幓浜戠褰曞儚鍒楄〃
      */
-    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 @@
      * 鑾峰彇鎾斁鍦板潃
      */
     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);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMobilePositionService.java b/src/main/java/com/genersoft/iot/vmp/service/IMobilePositionService.java
new file mode 100644
index 0000000..9af6415
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/service/IMobilePositionService.java
@@ -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);
+}
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 c9a54bc..4a6c2c3 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
@@ -2,6 +2,9 @@
 
 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 @@
         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;
     }
 
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 9461f06..9299429 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
@@ -9,6 +9,8 @@
 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.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 @@
     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 @@
         }
         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 @@
         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 @@
     @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 @@
         }
 
         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 @@
         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(), "寮�濮嬫椂闂存牸寮忛敊璇紝姝g‘鏍煎紡涓猴細 " + 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);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
index 5f96dbe..7070632 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -12,6 +12,12 @@
 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.*;
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MobilePositionServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MobilePositionServiceImpl.java
new file mode 100644
index 0000000..277493a
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MobilePositionServiceImpl.java
@@ -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);
+    }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
index 8ddf4f8..d3f69d6 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -349,6 +349,9 @@
         }
         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 @@
             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("[绉婚櫎浠g悊]锛� 浠g悊锛� {}/{}, 浠巣lm绉婚櫎鎴愬姛", app, stream);
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 22f2ce0..a654ea0 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
@@ -50,12 +50,15 @@
             " <if test= 'mediaServerItemList != null  ' > and media_server_id in " +
             " <foreach collection='mediaServerItemList'  item='item'  open='(' separator=',' close=')' > #{item.id}</foreach>" +
             " </if>" +
+            " <if test= 'ids != null  ' > and id in " +
+            " <foreach collection='ids'  item='item'  open='(' separator=',' close=')' > #{item}</foreach>" +
+            " </if>" +
             " order by start_time DESC" +
-
             " </script>")
     List<CloudRecordItem> 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<MediaServer> mediaServerItemList);
+                                  @Param("callId")String callId, List<MediaServer> mediaServerItemList,
+                                  List<Integer> ids);
 
 
     @Select(" <script>" +
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
index 4f12746..5cd50b9 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -402,23 +402,6 @@
             " </script>"})
     int updatePosition(DeviceChannel deviceChannel);
 
-    @Update({"<script>" +
-            "<foreach collection='deviceChannelList' item='item' separator=';'>" +
-            " UPDATE" +
-            " wvp_device_channel" +
-            " SET gps_time=#{item.gpsTime}" +
-            "<if test='item.longitude != null'>, longitude=#{item.longitude}</if>" +
-            "<if test='item.latitude != null'>, latitude=#{item.latitude}</if>" +
-            "<if test='item.longitudeGcj02 != null'>, longitude_gcj02=#{item.longitudeGcj02}</if>" +
-            "<if test='item.latitudeGcj02 != null'>, latitude_gcj02=#{item.latitudeGcj02}</if>" +
-            "<if test='item.longitudeWgs84 != null'>, longitude_wgs84=#{item.longitudeWgs84}</if>" +
-            "<if test='item.latitudeWgs84 != null'>, latitude_wgs84=#{item.latitudeWgs84}</if>" +
-            "WHERE device_id=#{item.deviceId} " +
-            " <if test='item.channelId != null' > AND channel_id=#{item.channelId}</if>" +
-            "</foreach>" +
-            "</script>"})
-    int batchUpdatePosition(List<DeviceChannel> deviceChannelList);
-
     @Select("SELECT * FROM wvp_device_channel WHERE length(trim(stream_id)) > 0")
     List<DeviceChannel> getAllChannelInPlay();
 
@@ -572,4 +555,24 @@
             " <if test='channelId != null'> and channel_id = #{channelId} </if>" +
             "</script>")
     void updateChannelStreamIdentification(DeviceChannel channel);
+
+
+    @Update({"<script>" +
+            "<foreach collection='channelList' item='item' separator=';'>" +
+            " UPDATE" +
+            " wvp_device_channel" +
+            " SET update_time=#{item.updateTime}" +
+            "<if test='item.longitude != null'>, longitude=#{item.longitude}</if>" +
+            "<if test='item.latitude != null'>, latitude=#{item.latitude}</if>" +
+            "<if test='item.longitudeGcj02 != null'>, longitude_gcj02=#{item.longitudeGcj02}</if>" +
+            "<if test='item.latitudeGcj02 != null'>, latitude_gcj02=#{item.latitudeGcj02}</if>" +
+            "<if test='item.longitudeWgs84 != null'>, longitude_wgs84=#{item.longitudeWgs84}</if>" +
+            "<if test='item.latitudeWgs84 != null'>, latitude_wgs84=#{item.latitudeWgs84}</if>" +
+            "<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" +
+            "<if test='item.id > 0'>WHERE id=#{item.id}</if>" +
+            "<if test='item.id == 0'>WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}</if>" +
+            "</foreach>" +
+            "</script>"})
+    void batchUpdatePosition(List<DeviceChannel> channelList);
+
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
index c28b16e..5124310 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
@@ -49,7 +49,7 @@
     void batchadd2(List<MobilePosition> mobilePositions);
 
     @Insert("<script> " +
-            "<foreach collection='mobilePositions' index='index' item='item' separator=','> " +
+            "<foreach collection='mobilePositions' index='index' item='item' separator=';'> " +
             "insert into wvp_device_mobile_position " +
             "(device_id,channel_id, device_name,time,longitude,latitude,altitude,speed,direction,report_source," +
             "longitude_gcj02,latitude_gcj02,longitude_wgs84,latitude_wgs84,create_time)"+
@@ -57,7 +57,7 @@
             "(#{item.deviceId}, #{item.channelId}, #{item.deviceName}, #{item.time}, #{item.longitude}, " +
             "#{item.latitude}, #{item.altitude}, #{item.speed},#{item.direction}," +
             "#{item.reportSource}, #{item.longitudeGcj02}, #{item.latitudeGcj02}, #{item.longitudeWgs84}, #{item.latitudeWgs84}, " +
-            "#{item.createTime}); " +
+            "#{item.createTime}) " +
             "</foreach> " +
             "</script>")
     void batchadd(List<MobilePosition> mobilePositions);
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
index d34657f..2f2bfb6 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
@@ -41,6 +41,7 @@
             "type,"+
             "create_time,"+
             "update_time,"+
+            "transcode_suffix,"+
             "hook_alive_interval"+
             ") VALUES " +
             "(" +
@@ -72,6 +73,7 @@
             "#{type}, " +
             "#{createTime}, " +
             "#{updateTime}, " +
+            "#{transcodeSuffix}, " +
             "#{hookAliveInterval})")
     int add(MediaServer mediaServerItem);
 
@@ -102,6 +104,7 @@
             "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
             "<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" +
             "<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" +
+            "<if test=\"transcodeSuffix != null\">, transcode_suffix=#{transcodeSuffix}</if>" +
             "<if test=\"type != null\">, type=#{type}</if>" +
             "WHERE id=#{id}"+
             " </script>"})
@@ -133,6 +136,7 @@
             "<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" +
             "<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" +
             "<if test=\"type != null\">, type=#{type}</if>" +
+            "<if test=\"transcodeSuffix != null\">, transcode_suffix=#{transcodeSuffix}</if>" +
             "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
             "WHERE ip=#{ip} and http_port=#{httpPort}"+
             " </script>"})
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
index e219360..0a45552 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -576,7 +576,7 @@
     @Override
     public void sendMobilePositionMsg(JSONObject jsonObject) {
         String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_MOBILE_POSITION;
-//        logger.info("[redis鍙戦�侀�氱煡] 鍙戦�� 绉诲姩浣嶇疆 {}: {}", key, jsonObject.toString());
+        logger.debug("[redis鍙戦�侀�氱煡] 鍙戦�� 绉诲姩浣嶇疆 {}: {}", key, jsonObject.toString());
         redisTemplate.convertAndSend(key, jsonObject);
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
index ddcbb21..f6f60d7 100755
--- a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
+++ b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
@@ -107,6 +107,14 @@
 	}
 
     /**
+     * 鏃堕棿鎴� 杞� yyyy_MM_dd_HH_mm_ss
+     */
+	public static String timestampMsToUrlToyyyy_MM_dd_HH_mm_ss(long timestamp) {
+        Instant instant = Instant.ofEpochMilli(timestamp);
+        return urlFormatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr)));
+	}
+
+    /**
      * yyyy_MM_dd_HH_mm_ss 杞椂闂存埑锛堟绉掞級
      *
      * @param formatTime
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/MediaServerUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/MediaServerUtils.java
new file mode 100644
index 0000000..bb57547
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/MediaServerUtils.java
@@ -0,0 +1,26 @@
+package com.genersoft.iot.vmp.utils;
+
+import org.springframework.util.ObjectUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MediaServerUtils {
+    public static Map<String, String> urlParamToMap(String params) {
+        HashMap<String, String> map = new HashMap<>();
+        if (ObjectUtils.isEmpty(params)) {
+            return map;
+        }
+        String[] paramsArray = params.split("&");
+        if (paramsArray.length == 0) {
+            return map;
+        }
+        for (String param : paramsArray) {
+            String[] paramArray = param.split("=");
+            if (paramArray.length == 2) {
+                map.put(paramArray[0], paramArray[1]);
+            }
+        }
+        return map;
+    }
+}
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 da8bbc8..e55534d 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
@@ -8,7 +8,9 @@
 import com.genersoft.iot.vmp.media.service.IMediaServerService;
 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.cloudRecord.bean.CloudRecordUrl;
 import com.github.pagehelper.PageInfo;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -21,9 +23,15 @@
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 @SuppressWarnings("rawtypes")
 @Tag(name = "浜戠褰曞儚鎺ュ彛")
@@ -96,6 +104,7 @@
     @Parameter(name = "startTime", description = "寮�濮嬫椂闂�(yyyy-MM-dd HH:mm:ss)", required = false)
     @Parameter(name = "endTime", description = "缁撴潫鏃堕棿(yyyy-MM-dd HH:mm:ss)", required = false)
     @Parameter(name = "mediaServerId", description = "娴佸獟浣揑D锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�", required = false)
+    @Parameter(name = "callId", description = "姣忔褰曞儚鐨勫敮涓�鏍囪瘑锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�", required = false)
     public PageInfo<CloudRecordItem> openRtpServer(
             @RequestParam(required = false)  String query,
             @RequestParam(required = false)  String app,
@@ -104,11 +113,12 @@
             @RequestParam int count,
             @RequestParam(required = false)  String startTime,
             @RequestParam(required = false)  String endTime,
-            @RequestParam(required = false) String mediaServerId
+            @RequestParam(required = false) String mediaServerId,
+            @RequestParam(required = false) String callId
 
     ) {
-        logger.info("[浜戠褰曞儚] 鏌ヨ app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}",
-                app, stream, mediaServerId, page, count, startTime, endTime);
+        logger.info("[浜戠褰曞儚] 鏌ヨ app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}, callId->{}",
+                app, stream, mediaServerId, page, count, startTime, endTime, callId);
 
         List<MediaServer> mediaServerItems;
         if (!ObjectUtils.isEmpty(mediaServerId)) {
@@ -139,7 +149,10 @@
         if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) {
             endTime = null;
         }
-        return cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServerItems);
+        if (callId != null && ObjectUtils.isEmpty(callId.trim())) {
+            callId = null;
+        }
+        return cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServerItems, callId);
     }
 
     @ResponseBody
@@ -265,4 +278,212 @@
     ){
         return cloudRecordService.getPlayUrlPath(recordId);
     }
+
+    /************************* 浠ヤ笅杩欎簺鎺ュ彛鍙�傚悎wvp鍜寊lm閮ㄧ讲鍦ㄥ悓涓�鍙版湇鍔″櫒鐨勬儏鍐碉紝涓攚vp鍙湁涓�涓獄lm鑺傜偣鐨勬儏鍐� ***************************************/
+
+    /**
+     * 涓嬭浇鎸囧畾褰曞儚鏂囦欢鐨勫帇缂╁寘
+     * @param query 妫�绱㈠唴瀹�
+     * @param app 搴旂敤鍚�
+     * @param stream 娴両D
+     * @param startTime 寮�濮嬫椂闂�(yyyy-MM-dd HH:mm:ss)
+     * @param endTime 缁撴潫鏃堕棿(yyyy-MM-dd HH:mm:ss)
+     * @param mediaServerId 娴佸獟浣揑D锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�
+     * @param callId 姣忔褰曞儚鐨勫敮涓�鏍囪瘑锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�
+     * @param ids 鎸囧畾鐨処d
+     */
+    @ResponseBody
+    @GetMapping("/zip")
+    public void downloadZipFile(
+            HttpServletResponse response,
+            @RequestParam(required = false) String query,
+            @RequestParam(required = false) String app,
+            @RequestParam(required = false) String stream,
+            @RequestParam(required = false) String startTime,
+            @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) String mediaServerId,
+            @RequestParam(required = false) String callId,
+            @RequestParam(required = false) List<Integer> ids
+
+    ) {
+        logger.info("[涓嬭浇鎸囧畾褰曞儚鏂囦欢鐨勫帇缂╁寘] 鏌ヨ app->{}, stream->{}, mediaServerId->{}, startTime->{}, endTime->{}, callId->{}",
+                app, stream, mediaServerId, startTime, endTime, callId);
+
+        List<MediaServerItem> mediaServerItems;
+        if (!ObjectUtils.isEmpty(mediaServerId)) {
+            mediaServerItems = new ArrayList<>();
+            MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+            if (mediaServerItem == null) {
+                throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒版祦濯掍綋: " + mediaServerId);
+            }
+            mediaServerItems.add(mediaServerItem);
+        } else {
+            mediaServerItems = mediaServerService.getAll();
+        }
+        if (mediaServerItems.isEmpty()) {
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "褰撳墠鏃犳祦濯掍綋");
+        }
+        if (query != null && ObjectUtils.isEmpty(query.trim())) {
+            query = null;
+        }
+        if (app != null && ObjectUtils.isEmpty(app.trim())) {
+            app = null;
+        }
+        if (stream != null && ObjectUtils.isEmpty(stream.trim())) {
+            stream = null;
+        }
+        if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) {
+            startTime = null;
+        }
+        if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) {
+            endTime = null;
+        }
+        if (callId != null && ObjectUtils.isEmpty(callId.trim())) {
+            callId = null;
+        }
+        if (stream != null && callId != null) {
+            response.addHeader( "Content-Disposition", "attachment;filename=" + stream + "_" + callId + ".zip" );
+        }
+        List<CloudRecordItem> cloudRecordItemList = cloudRecordService.getAllList(query, app, stream, startTime, endTime, mediaServerItems, callId, ids);
+        if (ObjectUtils.isEmpty(cloudRecordItemList)) {
+            return;
+        }
+        try {
+            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
+            for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
+                zos.putNextEntry(new ZipEntry(DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss(cloudRecordItem.getStartTime()) + ".mp4"));
+                File file = new File(cloudRecordItem.getFilePath());
+                if (!file.exists() || file.isDirectory()) {
+                    continue;
+                }
+                FileInputStream fis = new FileInputStream(cloudRecordItem.getFilePath());
+                byte[] buf = new byte[2*1024];
+                int len;
+                while ((len = fis.read(buf)) != -1){
+                    zos.write(buf, 0, len);
+                }
+                zos.closeEntry();
+                fis.close();
+            }
+            zos.close();
+        } catch (IOException e) {
+            logger.error("[涓嬭浇鎸囧畾褰曞儚鏂囦欢鐨勫帇缂╁寘] 澶辫触锛� 鏌ヨ app->{}, stream->{}, mediaServerId->{}, startTime->{}, endTime->{}, callId->{}",
+                    app, stream, mediaServerId, startTime, endTime, callId, e);
+        }
+    }
+
+    /**
+     *
+     * @param query 妫�绱㈠唴瀹�
+     * @param app 搴旂敤鍚�
+     * @param stream 娴両D
+     * @param startTime 寮�濮嬫椂闂�(yyyy-MM-dd HH:mm:ss)
+     * @param endTime 缁撴潫鏃堕棿(yyyy-MM-dd HH:mm:ss)
+     * @param mediaServerId 娴佸獟浣揑D锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�
+     * @param callId 姣忔褰曞儚鐨勫敮涓�鏍囪瘑锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�
+     * @param remoteHost 鎷兼帴鎾斁鍦板潃鏃朵娇鐢ㄧ殑杩滅▼鍦板潃
+     */
+    @ResponseBody
+    @GetMapping("/list-url")
+    @Operation(summary = "鍒嗛〉鏌ヨ浜戠褰曞儚", security = @SecurityRequirement(name = JwtUtils.HEADER))
+    @Parameter(name = "query", description = "妫�绱㈠唴瀹�", required = false)
+    @Parameter(name = "app", description = "搴旂敤鍚�", required = false)
+    @Parameter(name = "stream", description = "娴両D", required = false)
+    @Parameter(name = "page", description = "褰撳墠椤�", required = true)
+    @Parameter(name = "count", description = "姣忛〉鏌ヨ鏁伴噺", required = true)
+    @Parameter(name = "startTime", description = "寮�濮嬫椂闂�(yyyy-MM-dd HH:mm:ss)", required = false)
+    @Parameter(name = "endTime", description = "缁撴潫鏃堕棿(yyyy-MM-dd HH:mm:ss)", required = false)
+    @Parameter(name = "mediaServerId", description = "娴佸獟浣揑D锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�", required = false)
+    @Parameter(name = "callId", description = "姣忔褰曞儚鐨勫敮涓�鏍囪瘑锛岀疆绌哄垯鏌ヨ鍏ㄩ儴娴佸獟浣�", required = false)
+    public PageInfo<CloudRecordUrl> getListWithUrl(
+            HttpServletRequest request,
+            @RequestParam(required = false)  String query,
+            @RequestParam(required = false)  String app,
+            @RequestParam(required = false)  String stream,
+            @RequestParam int page,
+            @RequestParam int count,
+            @RequestParam(required = false)  String startTime,
+            @RequestParam(required = false)  String endTime,
+            @RequestParam(required = false) String mediaServerId,
+            @RequestParam(required = false) String callId,
+            @RequestParam(required = false) String remoteHost
+
+    ) {
+        logger.info("[浜戠褰曞儚] 鏌ヨURL app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}, callId->{}",
+                app, stream, mediaServerId, page, count, startTime, endTime, callId);
+
+        List<MediaServerItem> mediaServerItems;
+        if (!ObjectUtils.isEmpty(mediaServerId)) {
+            mediaServerItems = new ArrayList<>();
+            MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+            if (mediaServerItem == null) {
+                throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒版祦濯掍綋: " + mediaServerId);
+            }
+            mediaServerItems.add(mediaServerItem);
+        } else {
+            mediaServerItems = mediaServerService.getAll();
+        }
+        if (mediaServerItems.isEmpty()) {
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "褰撳墠鏃犳祦濯掍綋");
+        }
+        if (query != null && ObjectUtils.isEmpty(query.trim())) {
+            query = null;
+        }
+        if (app != null && ObjectUtils.isEmpty(app.trim())) {
+            app = null;
+        }
+        if (stream != null && ObjectUtils.isEmpty(stream.trim())) {
+            stream = null;
+        }
+        if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) {
+            startTime = null;
+        }
+        if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) {
+            endTime = null;
+        }
+        if (callId != null && ObjectUtils.isEmpty(callId.trim())) {
+            callId = null;
+        }
+        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        if (mediaServerItem == null) {
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒版祦濯掍綋鑺傜偣");
+        }
+        if (remoteHost == null) {
+            remoteHost = request.getScheme() + "://" + request.getLocalAddr() + ":" +
+                    (request.getScheme().equals("https")? mediaServerItem.getHttpSSlPort() : mediaServerItem.getHttpPort());
+        }
+        PageInfo<CloudRecordItem> cloudRecordItemPageInfo = cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServerItems, callId);
+        PageInfo<CloudRecordUrl> cloudRecordUrlPageInfo = new PageInfo<>();
+        if (!ObjectUtils.isEmpty(cloudRecordItemPageInfo)) {
+            cloudRecordUrlPageInfo.setPageNum(cloudRecordItemPageInfo.getPageNum());
+            cloudRecordUrlPageInfo.setPageSize(cloudRecordItemPageInfo.getPageSize());
+            cloudRecordUrlPageInfo.setSize(cloudRecordItemPageInfo.getSize());
+            cloudRecordUrlPageInfo.setEndRow(cloudRecordItemPageInfo.getEndRow());
+            cloudRecordUrlPageInfo.setStartRow(cloudRecordItemPageInfo.getStartRow());
+            cloudRecordUrlPageInfo.setPages(cloudRecordItemPageInfo.getPages());
+            cloudRecordUrlPageInfo.setPrePage(cloudRecordItemPageInfo.getPrePage());
+            cloudRecordUrlPageInfo.setNextPage(cloudRecordItemPageInfo.getNextPage());
+            cloudRecordUrlPageInfo.setIsFirstPage(cloudRecordItemPageInfo.isIsFirstPage());
+            cloudRecordUrlPageInfo.setIsLastPage(cloudRecordItemPageInfo.isIsLastPage());
+            cloudRecordUrlPageInfo.setHasPreviousPage(cloudRecordItemPageInfo.isHasPreviousPage());
+            cloudRecordUrlPageInfo.setHasNextPage(cloudRecordItemPageInfo.isHasNextPage());
+            cloudRecordUrlPageInfo.setNavigatePages(cloudRecordItemPageInfo.getNavigatePages());
+            cloudRecordUrlPageInfo.setNavigateFirstPage(cloudRecordItemPageInfo.getNavigateFirstPage());
+            cloudRecordUrlPageInfo.setNavigateLastPage(cloudRecordItemPageInfo.getNavigateLastPage());
+            cloudRecordUrlPageInfo.setNavigatepageNums(cloudRecordItemPageInfo.getNavigatepageNums());
+            cloudRecordUrlPageInfo.setTotal(cloudRecordItemPageInfo.getTotal());
+            List<CloudRecordUrl> cloudRecordUrlList = new ArrayList<>(cloudRecordItemPageInfo.getList().size());
+            List<CloudRecordItem> cloudRecordItemList = cloudRecordItemPageInfo.getList();
+            for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
+                CloudRecordUrl cloudRecordUrl = new CloudRecordUrl();
+                cloudRecordUrl.setId(cloudRecordItem.getId());
+                cloudRecordUrl.setDownloadUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath()
+                        + "&save_name=" + cloudRecordItem.getStream() + "_" + cloudRecordItem.getCallId() + "_" + DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss(cloudRecordItem.getStartTime()) );
+                cloudRecordUrl.setPlayUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath());
+                cloudRecordUrlList.add(cloudRecordUrl);
+            }
+            cloudRecordUrlPageInfo.setList(cloudRecordUrlList);
+        }
+        return cloudRecordUrlPageInfo;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/bean/CloudRecordUrl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/bean/CloudRecordUrl.java
new file mode 100644
index 0000000..20aa12b
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/bean/CloudRecordUrl.java
@@ -0,0 +1,32 @@
+package com.genersoft.iot.vmp.vmanager.cloudRecord.bean;
+
+public class CloudRecordUrl {
+
+    private String playUrl;
+    private String downloadUrl;
+    private int id;
+
+    public String getPlayUrl() {
+        return playUrl;
+    }
+
+    public void setPlayUrl(String playUrl) {
+        this.playUrl = playUrl;
+    }
+
+    public String getDownloadUrl() {
+        return downloadUrl;
+    }
+
+    public void setDownloadUrl(String downloadUrl) {
+        this.downloadUrl = downloadUrl;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
index 1ed3197..780f536 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -31,6 +31,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
@@ -129,6 +130,9 @@
 						}
 						streamInfo.channgeStreamIp(host);
 					}
+					if (!ObjectUtils.isEmpty(newMediaServerItem.getTranscodeSuffix()) && !"null".equalsIgnoreCase(newMediaServerItem.getTranscodeSuffix())) {
+						streamInfo.setStream(streamInfo.getStream() + "_" + newMediaServerItem.getTranscodeSuffix());
+					}
 					wvpResult.setData(new StreamContent(streamInfo));
 				}else {
 					wvpResult.setCode(code);
diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml
index e616187..f2fd504 100644
--- a/src/main/resources/all-application.yml
+++ b/src/main/resources/all-application.yml
@@ -241,6 +241,8 @@
     register-again-after-time: 60
     # 鍥芥爣缁鏂瑰紡锛宼rue涓虹画璁紝姣忔娉ㄥ唽鍦ㄥ悓涓�涓細璇濋噷锛宖alse涓洪噸鏂版敞鍐岋紝姣忔浣跨敤鏂扮殑浼氳瘽
     register-keep-int-dialog: false
+    # 寮�鍚帴鍙f枃妗i〉闈€�� 榛樿寮�鍚紝鐢熶骇鐜寤鸿鍏抽棴锛岄亣鍒皊wagger鐩稿叧鐨勬紡娲炴椂涔熷彲浠ュ叧闂�
+    doc-enable: true
     # 璺ㄥ煙閰嶇疆锛屼笉閰嶇疆姝ら」鍒欏厑璁告墍鏈夎法鍩熻姹傦紝閰嶇疆鍚庡垯鍙厑璁搁厤缃殑椤甸潰鐨勫湴鍧�璇锋眰锛� 鍙互閰嶇疆澶氫釜
     allowed-origins:
         - http://localhost:8008
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index ddbf237..e61ac0b 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -112,7 +112,4 @@
   auto-apply-play: true
   # 璁惧/閫氶亾鐘舵�佸彉鍖栨椂鍙戦�佹秷鎭�
   device-status-notify: true
-# [鍙�塢 鏃ュ織閰嶇疆, 涓�鑸笉闇�瑕佹敼
-logging:
-  config: classpath:logback-spring.xml
 
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-mysql-2.7.1.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-mysql-2.7.1.sql"
new file mode 100644
index 0000000..ee828f4
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-mysql-2.7.1.sql"
@@ -0,0 +1,325 @@
+/*寤鸿〃*/
+create table wvp_device (
+                            id serial primary key ,
+                            device_id character varying(50) not null ,
+                            name character varying(255),
+                            manufacturer character varying(255),
+                            model character varying(255),
+                            firmware character varying(255),
+                            transport character varying(50),
+                            stream_mode character varying(50),
+                            on_line bool default false,
+                            register_time character varying(50),
+                            keepalive_time character varying(50),
+                            ip character varying(50),
+                            create_time character varying(50),
+                            update_time character varying(50),
+                            port integer,
+                            expires integer,
+                            subscribe_cycle_for_catalog integer DEFAULT 0,
+                            subscribe_cycle_for_mobile_position integer DEFAULT 0,
+                            mobile_position_submission_interval integer DEFAULT 5,
+                            subscribe_cycle_for_alarm integer DEFAULT 0,
+                            host_address character varying(50),
+                            charset character varying(50),
+                            ssrc_check bool default false,
+                            geo_coord_sys character varying(50),
+                            media_server_id character varying(50),
+                            custom_name character varying(255),
+                            sdp_ip character varying(50),
+                            local_ip character varying(50),
+                            password character varying(255),
+                            as_message_channel bool default false,
+                            keepalive_interval_time integer,
+                            broadcast_push_after_ack bool default false,
+                            constraint uk_device_device unique (device_id)
+);
+
+create table wvp_device_alarm (
+                                  id serial primary key ,
+                                  device_id character varying(50) not null,
+                                  channel_id character varying(50) not null,
+                                  alarm_priority character varying(50),
+                                  alarm_method character varying(50),
+                                  alarm_time character varying(50),
+                                  alarm_description character varying(255),
+                                  longitude double precision,
+                                  latitude double precision,
+                                  alarm_type character varying(50),
+                                  create_time character varying(50) not null
+);
+
+create table wvp_device_channel (
+                                    id serial primary key ,
+                                    channel_id character varying(50) not null,
+                                    name character varying(255),
+                                    custom_name character varying(255),
+                                    manufacture character varying(50),
+                                    model character varying(50),
+                                    owner character varying(50),
+                                    civil_code character varying(50),
+                                    block character varying(50),
+                                    address character varying(50),
+                                    parent_id character varying(50),
+                                    safety_way integer,
+                                    register_way integer,
+                                    cert_num character varying(50),
+                                    certifiable integer,
+                                    err_code integer,
+                                    end_time character varying(50),
+                                    secrecy character varying(50),
+                                    ip_address character varying(50),
+                                    port integer,
+                                    password character varying(255),
+                                    ptz_type integer,
+                                    custom_ptz_type integer,
+                                    status bool default false,
+                                    longitude double precision,
+                                    custom_longitude double precision,
+                                    latitude double precision,
+                                    custom_latitude double precision,
+                                    stream_id character varying(255),
+                                    device_id character varying(50) not null,
+                                    parental character varying(50),
+                                    has_audio bool default false,
+                                    create_time character varying(50) not null,
+                                    update_time character varying(50) not null,
+                                    sub_count integer,
+                                    longitude_gcj02 double precision,
+                                    latitude_gcj02 double precision,
+                                    longitude_wgs84 double precision,
+                                    latitude_wgs84 double precision,
+                                    business_group_id character varying(50),
+                                    gps_time character varying(50),
+                                    stream_identification character varying(50),
+                                    constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id)
+);
+
+create table wvp_device_mobile_position (
+                                            id serial primary key,
+                                            device_id character varying(50) not null,
+                                            channel_id character varying(50) not null,
+                                            device_name character varying(255),
+                                            time character varying(50),
+                                            longitude double precision,
+                                            latitude double precision,
+                                            altitude double precision,
+                                            speed double precision,
+                                            direction double precision,
+                                            report_source character varying(50),
+                                            longitude_gcj02 double precision,
+                                            latitude_gcj02 double precision,
+                                            longitude_wgs84 double precision,
+                                            latitude_wgs84 double precision,
+                                            create_time character varying(50)
+);
+
+create table wvp_gb_stream (
+                               gb_stream_id serial primary key,
+                               app character varying(255) not null,
+                               stream character varying(255) not null,
+                               gb_id character varying(50) not null,
+                               name character varying(255),
+                               longitude double precision,
+                               latitude double precision,
+                               stream_type character varying(50),
+                               media_server_id character varying(50),
+                               create_time character varying(50),
+                               constraint uk_gb_stream_unique_gb_id unique (gb_id),
+                               constraint uk_gb_stream_unique_app_stream unique (app, stream)
+);
+
+create table wvp_log (
+                         id serial primary key ,
+                         name character varying(50),
+                         type character varying(50),
+                         uri character varying(200),
+                         address character varying(50),
+                         result character varying(50),
+                         timing bigint,
+                         username character varying(50),
+                         create_time character varying(50)
+);
+
+create table wvp_media_server (
+                                  id character varying(255) primary key ,
+                                  ip character varying(50),
+                                  hook_ip character varying(50),
+                                  sdp_ip character varying(50),
+                                  stream_ip character varying(50),
+                                  http_port integer,
+                                  http_ssl_port integer,
+                                  rtmp_port integer,
+                                  rtmp_ssl_port integer,
+                                  rtp_proxy_port integer,
+                                  rtsp_port integer,
+                                  rtsp_ssl_port integer,
+                                  auto_config bool default false,
+                                  secret character varying(50),
+                                  rtp_enable bool default false,
+                                  rtp_port_range character varying(50),
+                                  send_rtp_port_range character varying(50),
+                                  record_assist_port integer,
+                                  default_server bool default false,
+                                  create_time character varying(50),
+                                  update_time character varying(50),
+                                  hook_alive_interval integer,
+                                  record_path character varying(255),
+                                  record_day integer default 7,
+                                  transcode_suffix character varying(255),
+                                  constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
+);
+
+create table wvp_platform (
+                              id serial primary key ,
+                              enable bool default false,
+                              name character varying(255),
+                              server_gb_id character varying(50),
+                              server_gb_domain character varying(50),
+                              server_ip character varying(50),
+                              server_port integer,
+                              device_gb_id character varying(50),
+                              device_ip character varying(50),
+                              device_port character varying(50),
+                              username character varying(255),
+                              password character varying(50),
+                              expires character varying(50),
+                              keep_timeout character varying(50),
+                              transport character varying(50),
+                              character_set character varying(50),
+                              catalog_id character varying(50),
+                              ptz bool default false,
+                              rtcp bool default false,
+                              status bool default false,
+                              start_offline_push bool default false,
+                              administrative_division character varying(50),
+                              catalog_group integer,
+                              create_time character varying(50),
+                              update_time character varying(50),
+                              as_message_channel bool default false,
+                              auto_push_channel bool default false,
+                              send_stream_ip character varying(50),
+                              constraint uk_platform_unique_server_gb_id unique (server_gb_id)
+);
+
+create table wvp_platform_catalog (
+                                      id character varying(50),
+                                      platform_id character varying(50),
+                                      name character varying(255),
+                                      parent_id character varying(50),
+                                      civil_code character varying(50),
+                                      business_group_id character varying(50),
+                                      constraint uk_platform_catalog_id_platform_id unique (id, platform_id)
+);
+
+create table wvp_platform_gb_channel (
+                                         id serial primary key ,
+                                         platform_id character varying(50),
+                                         catalog_id character varying(50),
+                                         device_channel_id integer,
+                                         constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id)
+);
+
+create table wvp_platform_gb_stream (
+                                        id serial primary key,
+                                        platform_id character varying(50),
+                                        catalog_id character varying(50),
+                                        gb_stream_id integer,
+                                        constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id)
+);
+
+create table wvp_stream_proxy (
+                                  id serial primary key,
+                                  type character varying(50),
+                                  app character varying(255),
+                                  stream character varying(255),
+                                  url character varying(255),
+                                  src_url character varying(255),
+                                  dst_url character varying(255),
+                                  timeout_ms integer,
+                                  ffmpeg_cmd_key character varying(255),
+                                  rtp_type character varying(50),
+                                  media_server_id character varying(50),
+                                  enable_audio bool default false,
+                                  enable_mp4 bool default false,
+                                  enable bool default false,
+                                  status boolean,
+                                  enable_remove_none_reader bool default false,
+                                  create_time character varying(50),
+                                  name character varying(255),
+                                  update_time character varying(50),
+                                  stream_key character varying(255),
+                                  enable_disable_none_reader bool default false,
+                                  constraint uk_stream_proxy_app_stream unique (app, stream)
+);
+
+create table wvp_stream_push (
+                                 id serial primary key,
+                                 app character varying(255),
+                                 stream character varying(255),
+                                 total_reader_count character varying(50),
+                                 origin_type integer,
+                                 origin_type_str character varying(50),
+                                 create_time character varying(50),
+                                 alive_second integer,
+                                 media_server_id character varying(50),
+                                 server_id character varying(50),
+                                 push_time character varying(50),
+                                 status bool default false,
+                                 update_time character varying(50),
+                                 push_ing bool default false,
+                                 self bool default false,
+                                 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 bigint,
+                                  end_time bigint,
+                                  media_server_id character varying(50),
+                                  file_name character varying(255),
+                                  folder character varying(255),
+                                  file_path character varying(255),
+                                  collect bool default false,
+                                  file_size bigint,
+                                  time_len bigint,
+                                  constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
+);
+
+create table wvp_user (
+                          id serial primary key,
+                          username character varying(255),
+                          password character varying(255),
+                          role_id integer,
+                          create_time character varying(50),
+                          update_time character varying(50),
+                          push_key character varying(50),
+                          constraint uk_user_username unique (username)
+);
+
+create table wvp_user_role (
+                               id serial primary key,
+                               name character varying(50),
+                               authority character varying(50),
+                               create_time character varying(50),
+                               update_time character varying(50)
+);
+create table wvp_resources_tree (
+                                    id serial primary key ,
+                                    is_catalog bool default true,
+                                    device_channel_id integer ,
+                                    gb_stream_id integer,
+                                    name character varying(255),
+                                    parentId integer,
+                                    path character varying(255)
+);
+
+
+/*鍒濆鏁版嵁*/
+INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
+INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
+
+
+
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.1.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.1.sql"
new file mode 100644
index 0000000..86a63d9
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.1.sql"
@@ -0,0 +1,325 @@
+/*寤鸿〃*/
+create table wvp_device (
+                            id serial primary key ,
+                            device_id character varying(50) not null ,
+                            name character varying(255),
+                            manufacturer character varying(255),
+                            model character varying(255),
+                            firmware character varying(255),
+                            transport character varying(50),
+                            stream_mode character varying(50),
+                            on_line bool default false,
+                            register_time character varying(50),
+                            keepalive_time character varying(50),
+                            ip character varying(50),
+                            create_time character varying(50),
+                            update_time character varying(50),
+                            port integer,
+                            expires integer,
+                            subscribe_cycle_for_catalog integer DEFAULT 0,
+                            subscribe_cycle_for_mobile_position integer DEFAULT 0,
+                            mobile_position_submission_interval integer DEFAULT 5,
+                            subscribe_cycle_for_alarm integer DEFAULT 0,
+                            host_address character varying(50),
+                            charset character varying(50),
+                            ssrc_check bool default false,
+                            geo_coord_sys character varying(50),
+                            media_server_id character varying(50),
+                            custom_name character varying(255),
+                            sdp_ip character varying(50),
+                            local_ip character varying(50),
+                            password character varying(255),
+                            as_message_channel bool default false,
+                            keepalive_interval_time integer,
+                            broadcast_push_after_ack bool default false,
+                            constraint uk_device_device unique (device_id)
+);
+
+create table wvp_device_alarm (
+                                  id serial primary key ,
+                                  device_id character varying(50) not null,
+                                  channel_id character varying(50) not null,
+                                  alarm_priority character varying(50),
+                                  alarm_method character varying(50),
+                                  alarm_time character varying(50),
+                                  alarm_description character varying(255),
+                                  longitude double precision,
+                                  latitude double precision,
+                                  alarm_type character varying(50),
+                                  create_time character varying(50) not null
+);
+
+create table wvp_device_channel (
+                                    id serial primary key ,
+                                    channel_id character varying(50) not null,
+                                    name character varying(255),
+                                    custom_name character varying(255),
+                                    manufacture character varying(50),
+                                    model character varying(50),
+                                    owner character varying(50),
+                                    civil_code character varying(50),
+                                    block character varying(50),
+                                    address character varying(50),
+                                    parent_id character varying(50),
+                                    safety_way integer,
+                                    register_way integer,
+                                    cert_num character varying(50),
+                                    certifiable integer,
+                                    err_code integer,
+                                    end_time character varying(50),
+                                    secrecy character varying(50),
+                                    ip_address character varying(50),
+                                    port integer,
+                                    password character varying(255),
+                                    ptz_type integer,
+                                    custom_ptz_type integer,
+                                    status bool default false,
+                                    longitude double precision,
+                                    custom_longitude double precision,
+                                    latitude double precision,
+                                    custom_latitude double precision,
+                                    stream_id character varying(255),
+                                    device_id character varying(50) not null,
+                                    parental character varying(50),
+                                    has_audio bool default false,
+                                    create_time character varying(50) not null,
+                                    update_time character varying(50) not null,
+                                    sub_count integer,
+                                    longitude_gcj02 double precision,
+                                    latitude_gcj02 double precision,
+                                    longitude_wgs84 double precision,
+                                    latitude_wgs84 double precision,
+                                    business_group_id character varying(50),
+                                    gps_time character varying(50),
+                                    stream_identification character varying(50),
+                                    constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id)
+);
+
+create table wvp_device_mobile_position (
+                                            id serial primary key,
+                                            device_id character varying(50) not null,
+                                            channel_id character varying(50) not null,
+                                            device_name character varying(255),
+                                            time character varying(50),
+                                            longitude double precision,
+                                            latitude double precision,
+                                            altitude double precision,
+                                            speed double precision,
+                                            direction double precision,
+                                            report_source character varying(50),
+                                            longitude_gcj02 double precision,
+                                            latitude_gcj02 double precision,
+                                            longitude_wgs84 double precision,
+                                            latitude_wgs84 double precision,
+                                            create_time character varying(50)
+);
+
+create table wvp_gb_stream (
+                               gb_stream_id serial primary key,
+                               app character varying(255) not null,
+                               stream character varying(255) not null,
+                               gb_id character varying(50) not null,
+                               name character varying(255),
+                               longitude double precision,
+                               latitude double precision,
+                               stream_type character varying(50),
+                               media_server_id character varying(50),
+                               create_time character varying(50),
+                               constraint uk_gb_stream_unique_gb_id unique (gb_id),
+                               constraint uk_gb_stream_unique_app_stream unique (app, stream)
+);
+
+create table wvp_log (
+                         id serial primary key ,
+                         name character varying(50),
+                         type character varying(50),
+                         uri character varying(200),
+                         address character varying(50),
+                         result character varying(50),
+                         timing bigint,
+                         username character varying(50),
+                         create_time character varying(50)
+);
+
+create table wvp_media_server (
+                                  id character varying(255) primary key ,
+                                  ip character varying(50),
+                                  hook_ip character varying(50),
+                                  sdp_ip character varying(50),
+                                  stream_ip character varying(50),
+                                  http_port integer,
+                                  http_ssl_port integer,
+                                  rtmp_port integer,
+                                  rtmp_ssl_port integer,
+                                  rtp_proxy_port integer,
+                                  rtsp_port integer,
+                                  rtsp_ssl_port integer,
+                                  auto_config bool default false,
+                                  secret character varying(50),
+                                  rtp_enable bool default false,
+                                  rtp_port_range character varying(50),
+                                  send_rtp_port_range character varying(50),
+                                  record_assist_port integer,
+                                  default_server bool default false,
+                                  create_time character varying(50),
+                                  update_time character varying(50),
+                                  hook_alive_interval integer,
+                                  record_path character varying(255),
+                                  record_day integer default 7,
+                                  transcode_suffix character varying(255),
+                                  constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
+);
+
+create table wvp_platform (
+                              id serial primary key ,
+                              enable bool default false,
+                              name character varying(255),
+                              server_gb_id character varying(50),
+                              server_gb_domain character varying(50),
+                              server_ip character varying(50),
+                              server_port integer,
+                              device_gb_id character varying(50),
+                              device_ip character varying(50),
+                              device_port character varying(50),
+                              username character varying(255),
+                              password character varying(50),
+                              expires character varying(50),
+                              keep_timeout character varying(50),
+                              transport character varying(50),
+                              character_set character varying(50),
+                              catalog_id character varying(50),
+                              ptz bool default false,
+                              rtcp bool default false,
+                              status bool default false,
+                              start_offline_push bool default false,
+                              administrative_division character varying(50),
+                              catalog_group integer,
+                              create_time character varying(50),
+                              update_time character varying(50),
+                              as_message_channel bool default false,
+                              auto_push_channel bool default false,
+                              send_stream_ip character varying(50),
+                              constraint uk_platform_unique_server_gb_id unique (server_gb_id)
+);
+
+create table wvp_platform_catalog (
+                                      id character varying(50),
+                                      platform_id character varying(50),
+                                      name character varying(255),
+                                      parent_id character varying(50),
+                                      civil_code character varying(50),
+                                      business_group_id character varying(50),
+                                      constraint uk_platform_catalog_id_platform_id unique (id, platform_id)
+);
+
+create table wvp_platform_gb_channel (
+                                         id serial primary key ,
+                                         platform_id character varying(50),
+                                         catalog_id character varying(50),
+                                         device_channel_id integer,
+                                         constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id)
+);
+
+create table wvp_platform_gb_stream (
+                                        id serial primary key,
+                                        platform_id character varying(50),
+                                        catalog_id character varying(50),
+                                        gb_stream_id integer,
+                                        constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id)
+);
+
+create table wvp_stream_proxy (
+                                  id serial primary key,
+                                  type character varying(50),
+                                  app character varying(255),
+                                  stream character varying(255),
+                                  url character varying(255),
+                                  src_url character varying(255),
+                                  dst_url character varying(255),
+                                  timeout_ms integer,
+                                  ffmpeg_cmd_key character varying(255),
+                                  rtp_type character varying(50),
+                                  media_server_id character varying(50),
+                                  enable_audio bool default false,
+                                  enable_mp4 bool default false,
+                                  enable bool default false,
+                                  status boolean,
+                                  enable_remove_none_reader bool default false,
+                                  create_time character varying(50),
+                                  name character varying(255),
+                                  update_time character varying(50),
+                                  stream_key character varying(255),
+                                  enable_disable_none_reader bool default false,
+                                  constraint uk_stream_proxy_app_stream unique (app, stream)
+);
+
+create table wvp_stream_push (
+                                 id serial primary key,
+                                 app character varying(255),
+                                 stream character varying(255),
+                                 total_reader_count character varying(50),
+                                 origin_type integer,
+                                 origin_type_str character varying(50),
+                                 create_time character varying(50),
+                                 alive_second integer,
+                                 media_server_id character varying(50),
+                                 server_id character varying(50),
+                                 push_time character varying(50),
+                                 status bool default false,
+                                 update_time character varying(50),
+                                 push_ing bool default false,
+                                 self bool default false,
+                                 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 int8,
+                                  end_time int8,
+                                  media_server_id character varying(50),
+                                  file_name character varying(255),
+                                  folder character varying(255),
+                                  file_path character varying(255),
+                                  collect bool default false,
+                                  file_size int8,
+                                  time_len int8,
+                                  constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
+);
+
+create table wvp_user (
+                          id serial primary key,
+                          username character varying(255),
+                          password character varying(255),
+                          role_id integer,
+                          create_time character varying(50),
+                          update_time character varying(50),
+                          push_key character varying(50),
+                          constraint uk_user_username unique (username)
+);
+
+create table wvp_user_role (
+                               id serial primary key,
+                               name character varying(50),
+                               authority character varying(50),
+                               create_time character varying(50),
+                               update_time character varying(50)
+);
+create table wvp_resources_tree (
+                                    id serial primary key ,
+                                    is_catalog bool default true,
+                                    device_channel_id integer ,
+                                    gb_stream_id integer,
+                                    name character varying(255),
+                                    parentId integer,
+                                    path character varying(255)
+);
+
+
+/*鍒濆鏁版嵁*/
+INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
+INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
+
+
+
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-mysql-2.7.1.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-mysql-2.7.1.sql"
new file mode 100644
index 0000000..86e8d0d
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-mysql-2.7.1.sql"
@@ -0,0 +1,2 @@
+alter table wvp_media_server
+    add transcode_suffix character varying(255);
\ No newline at end of file
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-postgresql-kingbase-2.7.1.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-postgresql-kingbase-2.7.1.sql"
new file mode 100644
index 0000000..86e8d0d
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-postgresql-kingbase-2.7.1.sql"
@@ -0,0 +1,2 @@
+alter table wvp_media_server
+    add transcode_suffix character varying(255);
\ No newline at end of file

--
Gitblit v1.8.0