Commit 5b0b17d7410785aef2bedb22447bd458a3713300

Authored by 648540858
1 parent 52656bb8

添加第三方服务参与的推流直接转发到国标功能

Showing 23 changed files with 321 additions and 74 deletions
sql/mysql.sql
... ... @@ -173,6 +173,7 @@ create table parent_platform
173 173 ptz int null,
174 174 rtcp int null,
175 175 status bit null,
  176 + shareAllLiveStream int null,
176 177 primary key (id, serverGBId)
177 178 );
178 179  
... ...
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
... ... @@ -55,5 +55,8 @@ public class VideoManagerConstants {
55 55 public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_";
56 56  
57 57 //************************** redis 消息*********************************
58   - public static final String WVP_MSG_STREAM_CHANGE__PREFIX = "WVP_MSG_STREAM_CHANGE_";
  58 + public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";
  59 +
  60 + //************************** 第三方 ****************************************
  61 + public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
59 62 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/UserSetup.java
... ... @@ -29,6 +29,8 @@ public class UserSetup {
29 29  
30 30 private String serverId = "000000";
31 31  
  32 + private String thirdPartyGBIdReg = "[\\s\\S]*";
  33 +
32 34 private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
33 35  
34 36 public Boolean getSavePositionHistory() {
... ... @@ -114,4 +116,12 @@ public class UserSetup {
114 116 public void setServerId(String serverId) {
115 117 this.serverId = serverId;
116 118 }
  119 +
  120 + public String getThirdPartyGBIdReg() {
  121 + return thirdPartyGBIdReg;
  122 + }
  123 +
  124 + public void setThirdPartyGBIdReg(String thirdPartyGBIdReg) {
  125 + this.thirdPartyGBIdReg = thirdPartyGBIdReg;
  126 + }
117 127 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
... ... @@ -104,6 +104,11 @@ public class ParentPlatform {
104 104 */
105 105 private int channelCount;
106 106  
  107 + /**
  108 + * 共享所有的直播流
  109 + */
  110 + private boolean shareAllLiveStream;
  111 +
107 112 public Integer getId() {
108 113 return id;
109 114 }
... ... @@ -264,4 +269,12 @@ public class ParentPlatform {
264 269 this.channelCount = channelCount;
265 270 }
266 271  
  272 +
  273 + public boolean isShareAllLiveStream() {
  274 + return shareAllLiveStream;
  275 + }
  276 +
  277 + public void setShareAllLiveStream(boolean shareAllLiveStream) {
  278 + this.shareAllLiveStream = shareAllLiveStream;
  279 + }
267 280 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -31,6 +31,7 @@ import javax.sip.header.FromHeader;
31 31 import javax.sip.message.Request;
32 32 import javax.sip.message.Response;
33 33 import java.text.ParseException;
  34 +import java.util.List;
34 35 import java.util.Vector;
35 36  
36 37 /**
... ... @@ -105,7 +106,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
105 106 if (platform != null) {
106 107 // 查询平台下是否有该通道
107 108 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
108   - GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
  109 + List<GbStream> gbStreams = storager.queryStreamInParentPlatform(requesterId, channelId);
  110 + GbStream gbStream = gbStreams.size() > 0? gbStreams.get(0):null;
109 111 MediaServerItem mediaServerItem = null;
110 112 // 不是通道可能是直播流
111 113 if (channel != null && gbStream == null ) {
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
1 1 package com.genersoft.iot.vmp.media.zlm;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.conf.UserSetup;
  5 +import com.genersoft.iot.vmp.gb28181.bean.GbStream;
4 6 import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
5 7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 8 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
7 9 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
8 10 import com.genersoft.iot.vmp.service.IStreamPushService;
  11 +import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
9 12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 13 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
11 14 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
12 15 import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
  16 +import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
13 17 import org.slf4j.Logger;
14 18 import org.slf4j.LoggerFactory;
15 19 import org.springframework.beans.factory.annotation.Autowired;
16 20 import org.springframework.stereotype.Component;
  21 +import org.springframework.util.StringUtils;
17 22  
18 23 import java.util.*;
  24 +import java.util.regex.Matcher;
  25 +import java.util.regex.Pattern;
19 26  
20 27 @Component
21 28 public class ZLMMediaListManager {
... ... @@ -41,8 +48,14 @@ public class ZLMMediaListManager {
41 48 private IStreamPushService streamPushService;
42 49  
43 50 @Autowired
  51 + private StreamPushMapper streamPushMapper;
  52 +
  53 + @Autowired
44 54 private ZLMHttpHookSubscribe subscribe;
45 55  
  56 + @Autowired
  57 + private UserSetup userSetup;
  58 +
46 59  
47 60 public void updateMediaList(MediaServerItem mediaServerItem) {
48 61 storager.clearMediaList();
... ... @@ -89,7 +102,43 @@ public class ZLMMediaListManager {
89 102 }
90 103  
91 104 public void addMedia(MediaItem mediaItem) {
92   - storager.updateMedia(streamPushService.transform(mediaItem));
  105 + // 查找此直播流是否存在redis预设gbId
  106 + StreamPushItem transform = streamPushService.transform(mediaItem);
  107 + // 从streamId取出查询关键值
  108 + Pattern pattern = Pattern.compile(userSetup.getThirdPartyGBIdReg());
  109 + Matcher matcher = pattern.matcher(mediaItem.getStream());// 指定要匹配的字符串
  110 + String queryKey = null;
  111 + if (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
  112 + queryKey = matcher.group();
  113 + }
  114 + if (queryKey != null) {
  115 + ThirdPartyGB thirdPartyGB = redisCatchStorage.queryMemberNoGBId(queryKey);
  116 + if (thirdPartyGB != null && !StringUtils.isEmpty(thirdPartyGB.getNationalStandardNo())) {
  117 + transform.setGbId(thirdPartyGB.getNationalStandardNo());
  118 + transform.setName(thirdPartyGB.getName());
  119 + }
  120 + }
  121 + storager.updateMedia(transform);
  122 + if (!StringUtils.isEmpty(transform.getGbId())) {
  123 + // 如果这个国标ID已经给了其他推流且流已离线,则移除其他推流
  124 + List<GbStream> gbStreams = gbStreamMapper.selectByGBId(transform.getGbId());
  125 + if (gbStreams.size() > 0) {
  126 + for (GbStream gbStream : gbStreams) {
  127 + // 出现使用相同国标Id的视频流时,使用新流替换旧流,
  128 + gbStreamMapper.del(gbStream.getApp(), gbStream.getStream());
  129 + platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream());
  130 + if (!gbStream.isStatus()) {
  131 + streamPushMapper.del(gbStream.getApp(), gbStream.getStream());
  132 + }
  133 + }
  134 + }
  135 + if (gbStreamMapper.selectOne(transform.getApp(), transform.getStream()) != null) {
  136 + gbStreamMapper.update(transform);
  137 + }else {
  138 + gbStreamMapper.add(transform);
  139 + }
  140 +
  141 + }
93 142 }
94 143  
95 144  
... ...
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
... ... @@ -37,4 +37,13 @@ public interface IStreamPushService {
37 37 StreamPushItem transform(MediaItem item);
38 38  
39 39 StreamPushItem getPush(String app, String streamId);
  40 +
  41 + /**
  42 + * 停止一路推流
  43 + * @param app 应用名
  44 + * @param streamId 流ID
  45 + * @return
  46 + */
  47 + boolean stop(String app, String streamId);
  48 +
40 49 }
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/ThirdPartyGB.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +public class ThirdPartyGB {
  4 +
  5 + private String name;
  6 + private String nationalStandardNo;
  7 +
  8 + public String getName() {
  9 + return name;
  10 + }
  11 +
  12 + public void setName(String name) {
  13 + this.name = name;
  14 + }
  15 +
  16 + public String getNationalStandardNo() {
  17 + return nationalStandardNo;
  18 + }
  19 +
  20 + public void setNationalStandardNo(String nationalStandardNo) {
  21 + this.nationalStandardNo = nationalStandardNo;
  22 + }
  23 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
... ... @@ -79,44 +79,38 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
79 79 StringBuffer result = new StringBuffer();
80 80 boolean streamLive = false;
81 81 param.setMediaServerId(mediaInfo.getId());
  82 + boolean saveResult;
82 83 // 更新
83 84 if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
84   - if (videoManagerStorager.updateStreamProxy(param)) {
85   - result.append("保存成功");
86   - if (param.isEnable()){
87   - JSONObject jsonObject = addStreamProxyToZlm(param);
88   - if (jsonObject == null) {
89   - result.append(", 但是启用失败,请检查流地址是否可用");
90   - param.setEnable(false);
91   - videoManagerStorager.updateStreamProxy(param);
92   - }else {
  85 + saveResult = videoManagerStorager.updateStreamProxy(param);
  86 + }else { // 新增
  87 + saveResult = videoManagerStorager.addStreamProxy(param);
  88 + }
  89 + if (saveResult) {
  90 + result.append("保存成功");
  91 + if (param.isEnable()) {
  92 + JSONObject jsonObject = addStreamProxyToZlm(param);
  93 + if (jsonObject == null) {
  94 + streamLive = false;
  95 + result.append(", 但是启用失败,请检查流地址是否可用");
  96 + param.setEnable(false);
  97 + videoManagerStorager.updateStreamProxy(param);
  98 + }else {
  99 + Integer code = jsonObject.getInteger("code");
  100 + if (code == 0) {
93 101 StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
94 102 mediaInfo, param.getApp(), param.getStream(), null);
95 103 wvpResult.setData(streamInfo);
96   - }
97   - }
98   - }
99   - }else { // 新增
100   - if (videoManagerStorager.addStreamProxy(param)){
101   - result.append("保存成功");
102   - streamLive = true;
103   - if (param.isEnable()) {
104   - JSONObject jsonObject = addStreamProxyToZlm(param);
105   - if (jsonObject == null) {
106   - streamLive = false;
  104 + }else {
107 105 result.append(", 但是启用失败,请检查流地址是否可用");
108 106 param.setEnable(false);
109 107 videoManagerStorager.updateStreamProxy(param);
110   - }else {
111   - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
112   - mediaInfo, param.getApp(), param.getStream(), null);
113   - wvpResult.setData(streamInfo);
114 108 }
  109 +
115 110 }
116   - }else {
117   - result.append("保存失败");
118 111 }
119   -
  112 + }else {
  113 + result.append("保存失败");
120 114 }
121 115 if (param.getPlatformGbId() != null && streamLive) {
122 116 List<GbStream> gbStreams = new ArrayList<>();
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
... ... @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.service.IMediaServerService;
12 12 import com.genersoft.iot.vmp.service.IStreamPushService;
13 13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
14 14 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
  15 +import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
15 16 import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
16 17 import com.github.pagehelper.PageHelper;
17 18 import com.github.pagehelper.PageInfo;
... ... @@ -33,6 +34,9 @@ public class StreamPushServiceImpl implements IStreamPushService {
33 34 private StreamPushMapper streamPushMapper;
34 35  
35 36 @Autowired
  37 + private PlatformGbStreamMapper platformGbStreamMapper;
  38 +
  39 + @Autowired
36 40 private ZLMRESTfulUtils zlmresTfulUtils;
37 41  
38 42 @Autowired
... ... @@ -116,4 +120,18 @@ public class StreamPushServiceImpl implements IStreamPushService {
116 120  
117 121 return streamPushMapper.selectOne(app, streamId);
118 122 }
  123 +
  124 + @Override
  125 + public boolean stop(String app, String streamId) {
  126 + StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId);
  127 + int delStream = streamPushMapper.del(app, streamId);
  128 + gbStreamMapper.del(app, streamId);
  129 + platformGbStreamMapper.delByAppAndStream(app, streamId);
  130 + if (delStream > 0) {
  131 + MediaServerItem mediaServerItem = mediaServerService.getOne(streamPushItem.getMediaServerId());
  132 + zlmresTfulUtils.closeStreams(mediaServerItem,app, streamId);
  133 + }
  134 + return true;
  135 + }
  136 +
119 137 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
... ... @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
6 6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
7 7 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
8 8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  9 +import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
9 10  
10 11 import java.util.List;
11 12 import java.util.Map;
... ... @@ -152,4 +153,11 @@ public interface IRedisCatchStorage {
152 153 boolean startDownload(StreamInfo streamInfo);
153 154  
154 155 StreamInfo queryDownloadByStreamId(String streamId);
  156 +
  157 + /**
  158 + * 查找第三方系统留下的国标预设值
  159 + * @param queryKey
  160 + * @return
  161 + */
  162 + ThirdPartyGB queryMemberNoGBId(String queryKey);
155 163 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
... ... @@ -327,7 +327,7 @@ public interface IVideoManagerStorager {
327 327 * @param channelId
328 328 * @return
329 329 */
330   - GbStream queryStreamInParentPlatform(String platformId, String channelId);
  330 + List<GbStream> queryStreamInParentPlatform(String platformId, String channelId);
331 331  
332 332 /**
333 333 * 获取平台关联的直播流
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
... ... @@ -40,10 +40,13 @@ public interface GbStreamMapper {
40 40 @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
41 41 StreamProxyItem selectOne(String app, String stream);
42 42  
  43 + @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}")
  44 + List<GbStream> selectByGBId(String gbId);
  45 +
43 46 @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " +
44 47 "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
45 48 "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'")
46   - GbStream queryStreamInPlatform(String platformId, String gbId);
  49 + List<GbStream> queryStreamInPlatform(String platformId, String gbId);
47 50  
48 51 @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " +
49 52 "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
... ... @@ -15,10 +15,10 @@ public interface ParentPlatformMapper {
15 15  
16 16 @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " +
17 17 " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " +
18   - " status) " +
  18 + " status, shareAllLiveStream) " +
19 19 " VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
20 20 " '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " +
21   - " ${status})")
  21 + " ${status}, ${shareAllLiveStream})")
22 22 int addParentPlatform(ParentPlatform parentPlatform);
23 23  
24 24 @Update("UPDATE parent_platform " +
... ... @@ -39,7 +39,8 @@ public interface ParentPlatformMapper {
39 39 "characterSet=#{characterSet}, " +
40 40 "ptz=#{ptz}, " +
41 41 "rtcp=#{rtcp}, " +
42   - "status=#{status} " +
  42 + "status=#{status}, " +
  43 + "shareAllLiveStream=#{shareAllLiveStream} " +
43 44 "WHERE id=#{id}")
44 45 int updateParentPlatform(ParentPlatform parentPlatform);
45 46  
... ... @@ -70,4 +71,7 @@ public interface ParentPlatformMapper {
70 71  
71 72 @Update("UPDATE parent_platform SET status=#{online} WHERE serverGBId=#{platformGbID}" )
72 73 int updateParentPlatformStatus(String platformGbID, boolean online);
  74 +
  75 + @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true")
  76 + List<ParentPlatform> selectAllAhareAllLiveStream();
73 77 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
... ... @@ -24,4 +24,7 @@ public interface PlatformGbStreamMapper {
24 24  
25 25 @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}")
26 26 List<StreamProxyItem> selectByAppAndStream(String app, String stream);
  27 +
  28 + @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{serverGBId}")
  29 + StreamProxyItem selectOne(String app, String stream, String serverGBId);
27 30 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
6 6 import com.genersoft.iot.vmp.conf.UserSetup;
7 7 import com.genersoft.iot.vmp.gb28181.bean.*;
8 8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  9 +import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
9 10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 11 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
11 12 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
... ... @@ -13,6 +14,7 @@ import org.slf4j.Logger;
13 14 import org.slf4j.LoggerFactory;
14 15 import org.springframework.beans.factory.annotation.Autowired;
15 16 import org.springframework.stereotype.Component;
  17 +import org.springframework.util.StringUtils;
16 18  
17 19 import java.text.SimpleDateFormat;
18 20 import java.util.*;
... ... @@ -324,7 +326,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
324 326  
325 327 @Override
326 328 public void sendStreamChangeMsg(String type, JSONObject jsonObject) {
327   - String key = VideoManagerConstants.WVP_MSG_STREAM_CHANGE__PREFIX + type;
  329 + String key = VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + type;
328 330 logger.debug("[redis 流变化事件] {}: {}", key, jsonObject.toString());
329 331 redis.convertAndSend(key, jsonObject);
330 332 }
... ... @@ -350,4 +352,11 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
350 352 if (playLeys == null || playLeys.size() == 0) return null;
351 353 return (StreamInfo)redis.get(playLeys.get(0).toString());
352 354 }
  355 +
  356 + @Override
  357 + public ThirdPartyGB queryMemberNoGBId(String queryKey) {
  358 + String key = VideoManagerConstants.WVP_STREAM_GB_ID_PREFIX + queryKey;
  359 + JSONObject jsonObject = (JSONObject)redis.get(key);
  360 + return JSONObject.toJavaObject(jsonObject, ThirdPartyGB.class);
  361 + }
353 362 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
... ... @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
5 5 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 6 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
7 7 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
  8 +import com.genersoft.iot.vmp.service.IGbStreamService;
8 9 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
9 10 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
10 11 import com.genersoft.iot.vmp.storager.dao.*;
... ... @@ -19,6 +20,7 @@ import org.springframework.stereotype.Component;
19 20 import org.springframework.transaction.TransactionDefinition;
20 21 import org.springframework.transaction.TransactionStatus;
21 22 import org.springframework.transaction.annotation.Transactional;
  23 +import org.springframework.util.StringUtils;
22 24  
23 25 import java.text.SimpleDateFormat;
24 26 import java.util.ArrayList;
... ... @@ -69,6 +71,16 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
69 71  
70 72 @Autowired
71 73 private GbStreamMapper gbStreamMapper;
  74 +;
  75 +
  76 + @Autowired
  77 + private PlatformGbStreamMapper platformGbStreamMapper;
  78 +
  79 + @Autowired
  80 + private IGbStreamService gbStreamService;
  81 +
  82 + @Autowired
  83 + private ParentPlatformMapper parentPlatformMapper;
72 84  
73 85 @Autowired
74 86 private VideoStreamSessionManager streamSession;
... ... @@ -356,6 +368,15 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
356 368 // 更新缓存
357 369 parentPlatformCatch.setParentPlatform(parentPlatform);
358 370 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
  371 + // 共享所有视频流,需要将现有视频流添加到此平台
  372 + List<GbStream> gbStreams = gbStreamMapper.selectAll();
  373 + if (gbStreams.size() > 0) {
  374 + if (parentPlatform.isShareAllLiveStream()) {
  375 + gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId());
  376 + }else {
  377 + gbStreamService.delPlatformInfo(gbStreams);
  378 + }
  379 + }
359 380 return result > 0;
360 381 }
361 382  
... ... @@ -561,7 +582,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
561 582 * @return
562 583 */
563 584 @Override
564   - public GbStream queryStreamInParentPlatform(String platformId, String gbId) {
  585 + public List<GbStream> queryStreamInParentPlatform(String platformId, String gbId) {
565 586 return gbStreamMapper.queryStreamInPlatform(platformId, gbId);
566 587 }
567 588  
... ... @@ -602,6 +623,22 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
602 623 streamPushMapper.del(streamPushItem.getApp(), streamPushItem.getStream());
603 624 streamPushMapper.add(streamPushItem);
604 625 gbStreamMapper.setStatus(streamPushItem.getApp(), streamPushItem.getStream(), true);
  626 + if(!StringUtils.isEmpty(streamPushItem.getGbId() )){
  627 + // 查找开启了全部直播流共享的上级平台
  628 + List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
  629 + if (parentPlatforms.size() > 0) {
  630 + for (ParentPlatform parentPlatform : parentPlatforms) {
  631 + streamPushItem.setPlatformId(parentPlatform.getServerGBId());
  632 + String stream = streamPushItem.getStream();
  633 + StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(streamPushItem.getApp(), stream, parentPlatform.getServerGBId());
  634 + if (streamProxyItems == null) {
  635 + platformGbStreamMapper.add(streamPushItem);
  636 + }
  637 +
  638 + }
  639 + }
  640 + }
  641 +
605 642 }
606 643  
607 644 @Override
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
... ... @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.vmanager.streamPush;
3 3 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
4 4 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
5 5 import com.genersoft.iot.vmp.service.IStreamPushService;
  6 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
6 7 import com.github.pagehelper.PageInfo;
7 8 import io.swagger.annotations.Api;
8 9 import io.swagger.annotations.ApiImplicitParam;
... ... @@ -71,4 +72,21 @@ public class StreamPushController {
71 72 return "fail";
72 73 }
73 74 }
  75 +
  76 +
  77 + @ApiOperation("中止一个推流")
  78 + @ApiImplicitParams({
  79 + @ApiImplicitParam(name = "app", value = "应用名", required = true, dataTypeClass = String.class),
  80 + @ApiImplicitParam(name = "streamId", value = "流ID", required = true, dataTypeClass = String.class),
  81 + })
  82 + @PostMapping(value = "/stop")
  83 + @ResponseBody
  84 + public Object removeFormGB(@RequestParam(required = true)String app, @RequestParam(required = true)String streamId){
  85 + if (streamPushService.stop(app, streamId)){
  86 + return "success";
  87 + }else {
  88 + return "fail";
  89 + }
  90 + }
  91 +
74 92 }
... ...
src/main/resources/all-application.yml
... ... @@ -160,6 +160,8 @@ user-settings:
160 160 record-push-live: true
161 161 # 是否将日志存储进数据库
162 162 logInDatebase: true
  163 + # 第三方匹配,用于从stream钟获取有效信息
  164 + thirdPartyGBIdReg: [\s\S]*
163 165  
164 166 # 在线文档: swagger-ui(生产环境建议关闭)
165 167 swagger-ui:
... ...
src/main/resources/wvp.sqlite
No preview for this file type
web_src/src/components/PushVideoList.vue
... ... @@ -36,7 +36,7 @@
36 36 <template slot-scope="scope">
37 37 <el-button-group>
38 38 <el-button size="mini" icon="el-icon-video-play" @click="playPuhsh(scope.row)">播放</el-button>
39   - <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopPuhsh(scope.row)">停止</el-button>
  39 + <el-button size="mini" icon="el-icon-switch-button" type="danger" @click="stopPuhsh(scope.row)">移除</el-button>
40 40 <el-button size="mini" icon="el-icon-position" type="primary" v-if="!!!scope.row.gbId" @click="addToGB(scope.row)">加入国标</el-button>
41 41 <el-button size="mini" icon="el-icon-position" type="primary" v-if="!!scope.row.gbId" @click="removeFromGB(scope.row)">移出国标</el-button>
42 42 </el-button-group>
... ... @@ -151,7 +151,21 @@
151 151 });
152 152 },
153 153 stopPuhsh: function(row){
154   - console.log(row)
  154 + var that = this;
  155 + that.$axios({
  156 + method:"post",
  157 + url:"/api/push/stop",
  158 + params: {
  159 + app: row.app,
  160 + streamId: row.stream
  161 + }
  162 + }).then((res)=>{
  163 + if (res.data == "success") {
  164 + that.initData()
  165 + }
  166 + }).catch(function (error) {
  167 + console.log(error);
  168 + });
155 169 },
156 170 addToGB: function(row){
157 171 this.$refs.addStreamTOGB.openDialog({app: row.app, stream: row.stream, mediaServerId: row.mediaServerId}, this.initData);
... ... @@ -159,16 +173,16 @@
159 173 removeFromGB: function(row){
160 174 var that = this;
161 175 that.$axios({
162   - method:"delete",
163   - url:"/api/push/remove_form_gb",
164   - data:row
165   - }).then((res)=>{
166   - if (res.data == "success") {
  176 + method:"delete",
  177 + url:"/api/push/remove_form_gb",
  178 + data:row
  179 + }).then((res)=>{
  180 + if (res.data == "success") {
167 181 that.initData()
168 182 }
169   - }).catch(function (error) {
170   - console.log(error);
171   - });
  183 + }).catch(function (error) {
  184 + console.log(error);
  185 + });
172 186 },
173 187 dateFormat: function(/** timestamp=0 **/) {
174 188 var ts = arguments[0] || 0;
... ...
web_src/src/components/StreamProxyList.vue
... ... @@ -50,6 +50,7 @@
50 50 </div>
51 51 </template>
52 52 </el-table-column>
  53 + <el-table-column prop="createTime" label="创建时间" align="center" width="150" show-overflow-tooltip/>
53 54 <el-table-column label="转HLS" width="120" align="center">
54 55 <template slot-scope="scope">
55 56 <div slot="reference" class="name-wrapper">
... ...
web_src/src/components/dialog/platformEdit.vue
... ... @@ -17,7 +17,7 @@
17 17 <el-input v-model="platform.name"></el-input>
18 18 </el-form-item>
19 19 <el-form-item label="SIP服务国标编码" prop="serverGBId">
20   - <el-input v-model="platform.serverGBId" clearable></el-input>
  20 + <el-input v-model="platform.serverGBId" clearable @input="serverGBIdChange"></el-input>
21 21 </el-form-item>
22 22 <el-form-item label="SIP服务国标域" prop="serverGBDomain">
23 23 <el-input v-model="platform.serverGBDomain" clearable></el-input>
... ... @@ -29,7 +29,7 @@
29 29 <el-input v-model="platform.serverPort" clearable type="number"></el-input>
30 30 </el-form-item>
31 31 <el-form-item label="设备国标编号" prop="deviceGBId">
32   - <el-input v-model="platform.deviceGBId" clearable></el-input>
  32 + <el-input v-model="platform.deviceGBId" clearable @input="deviceGBIdChange"></el-input>
33 33 </el-form-item>
34 34 <el-form-item label="本地IP" prop="deviceIp">
35 35 <el-input v-model="platform.deviceIp" :disabled="true"></el-input>
... ... @@ -76,7 +76,7 @@
76 76 <el-form-item label="其他选项">
77 77 <el-checkbox label="启用" v-model="platform.enable" @change="checkExpires"></el-checkbox>
78 78 <el-checkbox label="云台控制" v-model="platform.ptz"></el-checkbox>
79   - <el-checkbox label="RTCP保活" v-model="platform.rtcp"></el-checkbox>
  79 + <el-checkbox label="共享所有直播流" v-model="platform.shareAllLiveStream"></el-checkbox>
80 80 </el-form-item>
81 81 <el-form-item>
82 82 <el-button type="primary" @click="onSubmit">{{
... ... @@ -97,28 +97,6 @@ export default {
97 97 name: "platformEdit",
98 98 props: {},
99 99 computed: {},
100   - created() {
101   - this.platform = {
102   - id: null,
103   - enable: true,
104   - ptz: true,
105   - rtcp: false,
106   - name: null,
107   - serverGBId: null,
108   - serverGBDomain: null,
109   - serverIP: null,
110   - serverPort: null,
111   - deviceGBId: null,
112   - deviceIp: null,
113   - devicePort: null,
114   - username: null,
115   - password: null,
116   - expires: 300,
117   - keepTimeout: 60,
118   - transport: "UDP",
119   - characterSet: "GB2312",
120   - }
121   - },
122 100 data() {
123 101 var deviceGBIdRules = async (rule, value, callback) => {
124 102 console.log(value);
... ... @@ -158,6 +136,7 @@ export default {
158 136 keepTimeout: 60,
159 137 transport: "UDP",
160 138 characterSet: "GB2312",
  139 + shareAllLiveStream: false,
161 140 },
162 141 rules: {
163 142 name: [{ required: true, message: "请输入平台名称", trigger: "blur" }],
... ... @@ -198,12 +177,39 @@ export default {
198 177 console.log(error);
199 178 });
200 179 }else {
201   - this.platform = platform;
  180 + this.platform.id = platform.id;
  181 + this.platform.enable = platform.enable;
  182 + this.platform.ptz = platform.ptz;
  183 + this.platform.rtcp = platform.rtcp;
  184 + this.platform.name = platform.name;
  185 + this.platform.serverGBId = platform.serverGBId;
  186 + this.platform.serverGBDomain = platform.serverGBDomain;
  187 + this.platform.serverIP = platform.serverIP;
  188 + this.platform.serverPort = platform.serverPort;
  189 + this.platform.deviceGBId = platform.deviceGBId;
  190 + this.platform.deviceIp = platform.deviceIp;
  191 + this.platform.devicePort = platform.devicePort;
  192 + this.platform.username = platform.username;
  193 + this.platform.password = platform.password;
  194 + this.platform.expires = platform.expires;
  195 + this.platform.keepTimeout = platform.keepTimeout;
  196 + this.platform.transport = platform.transport;
  197 + this.platform.characterSet = platform.characterSet;
  198 + this.platform.shareAllLiveStream = platform.shareAllLiveStream;
202 199 this.onSubmit_text = "保存";
203 200 }
204 201 this.showDialog = true;
205 202 this.listChangeCallback = callback;
206 203 },
  204 + serverGBIdChange: function () {
  205 + if (this.platform.serverGBId.length > 10) {
  206 + this.platform.serverGBDomain = this.platform.serverGBId.substr(0, 10);
  207 + }
  208 + },
  209 + deviceGBIdChange: function () {
  210 +
  211 + this.platform.username = this.platform.deviceGBId ;
  212 + },
207 213 onSubmit: function () {
208 214 console.log("onSubmit");
209 215 var that = this;
... ... @@ -228,10 +234,30 @@ export default {
228 234 });
229 235 },
230 236 close: function () {
231   - console.log("关闭添加视频平台");
232 237 this.showDialog = false;
233 238 this.$refs.platform1.resetFields();
234 239 this.$refs.platform2.resetFields();
  240 + this.platform = {
  241 + id: null,
  242 + enable: true,
  243 + ptz: true,
  244 + rtcp: false,
  245 + name: null,
  246 + serverGBId: null,
  247 + serverGBDomain: null,
  248 + serverIP: null,
  249 + serverPort: null,
  250 + deviceGBId: null,
  251 + deviceIp: null,
  252 + devicePort: null,
  253 + username: null,
  254 + password: null,
  255 + expires: 300,
  256 + keepTimeout: 60,
  257 + transport: "UDP",
  258 + characterSet: "GB2312",
  259 + shareAllLiveStream: false,
  260 + }
235 261 },
236 262 deviceGBIdExit: async function (deviceGbId) {
237 263 var result = false;
... ...