Commit 56859d09df8d4226882d43934acf32d60a3b51d7
1 parent
f8fe76ad
添加推流列表和拉流代理,下一步与国标关联
Showing
37 changed files
with
1418 additions
and
218 deletions
src/main/java/com/genersoft/iot/vmp/conf/MediaServerConfig.java
| ... | ... | @@ -35,6 +35,8 @@ public class MediaServerConfig { |
| 35 | 35 | |
| 36 | 36 | private String wanIp; |
| 37 | 37 | |
| 38 | + private long updateTime; | |
| 39 | + | |
| 38 | 40 | @JSONField(name = "hls.fileBufSize") |
| 39 | 41 | private String hlsFileBufSize; |
| 40 | 42 | |
| ... | ... | @@ -728,4 +730,12 @@ public class MediaServerConfig { |
| 728 | 730 | public void setWanIp(String wanIp) { |
| 729 | 731 | this.wanIp = wanIp; |
| 730 | 732 | } |
| 733 | + | |
| 734 | + public long getUpdateTime() { | |
| 735 | + return updateTime; | |
| 736 | + } | |
| 737 | + | |
| 738 | + public void setUpdateTime(long updateTime) { | |
| 739 | + this.updateTime = updateTime; | |
| 740 | + } | |
| 731 | 741 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| 1 | 1 | package com.genersoft.iot.vmp.media.zlm; |
| 2 | 2 | |
| 3 | +import java.util.List; | |
| 3 | 4 | import java.util.UUID; |
| 4 | 5 | |
| 5 | 6 | import com.alibaba.fastjson.JSON; |
| ... | ... | @@ -272,26 +273,35 @@ public class ZLMHttpHookListener { |
| 272 | 273 | } |
| 273 | 274 | |
| 274 | 275 | String streamId = json.getString("stream"); |
| 276 | + String app = json.getString("app"); | |
| 275 | 277 | StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); |
| 276 | 278 | |
| 277 | - JSONObject ret = new JSONObject(); | |
| 278 | - ret.put("code", 0); | |
| 279 | - ret.put("close", true); | |
| 280 | 279 | |
| 281 | - if (streamInfo != null) { | |
| 282 | - if (redisCatchStorage.isChannelSendingRTP(streamInfo.getChannelId())) { | |
| 283 | - ret.put("close", false); | |
| 284 | - } else { | |
| 280 | + if ("rtp".equals(app)){ | |
| 281 | + JSONObject ret = new JSONObject(); | |
| 282 | + ret.put("code", 0); | |
| 283 | + ret.put("close", true); | |
| 284 | + if (streamInfo != null) { | |
| 285 | + if (redisCatchStorage.isChannelSendingRTP(streamInfo.getChannelId())) { | |
| 286 | + ret.put("close", false); | |
| 287 | + } else { | |
| 288 | + cmder.streamByeCmd(streamId); | |
| 289 | + redisCatchStorage.stopPlay(streamInfo); | |
| 290 | + storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); | |
| 291 | + } | |
| 292 | + }else{ | |
| 285 | 293 | cmder.streamByeCmd(streamId); |
| 286 | - redisCatchStorage.stopPlay(streamInfo); | |
| 287 | - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); | |
| 294 | + streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 295 | + redisCatchStorage.stopPlayback(streamInfo); | |
| 288 | 296 | } |
| 289 | - }else{ | |
| 290 | - cmder.streamByeCmd(streamId); | |
| 291 | - streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 292 | - redisCatchStorage.stopPlayback(streamInfo); | |
| 297 | + return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); | |
| 298 | + }else { | |
| 299 | + JSONObject ret = new JSONObject(); | |
| 300 | + ret.put("code", 0); | |
| 301 | + ret.put("close", false); | |
| 302 | + return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); | |
| 293 | 303 | } |
| 294 | - return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); | |
| 304 | + | |
| 295 | 305 | } |
| 296 | 306 | |
| 297 | 307 | /** |
| ... | ... | @@ -350,10 +360,21 @@ public class ZLMHttpHookListener { |
| 350 | 360 | // String data = json.getString("data"); |
| 351 | 361 | // List<MediaServerConfig> mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class); |
| 352 | 362 | // MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0); |
| 363 | + | |
| 364 | + List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_started); | |
| 365 | + if (subscribes != null && subscribes.size() > 0) { | |
| 366 | + for (ZLMHttpHookSubscribe.Event subscribe : subscribes) { | |
| 367 | + subscribe.response(json); | |
| 368 | + } | |
| 369 | + } | |
| 370 | + | |
| 353 | 371 | MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class); |
| 354 | 372 | mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp); |
| 355 | 373 | mediaServerConfig.setLocalIP(mediaIp); |
| 356 | 374 | redisCatchStorage.updateMediaInfo(mediaServerConfig); |
| 375 | + | |
| 376 | + // 重新发起代理 | |
| 377 | + | |
| 357 | 378 | JSONObject ret = new JSONObject(); |
| 358 | 379 | ret.put("code", 0); |
| 359 | 380 | ret.put("msg", "success"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
| ... | ... | @@ -3,7 +3,9 @@ package com.genersoft.iot.vmp.media.zlm; |
| 3 | 3 | import com.alibaba.fastjson.JSONObject; |
| 4 | 4 | import org.springframework.stereotype.Component; |
| 5 | 5 | |
| 6 | +import java.util.ArrayList; | |
| 6 | 7 | import java.util.HashMap; |
| 8 | +import java.util.List; | |
| 7 | 9 | import java.util.Map; |
| 8 | 10 | import java.util.concurrent.ConcurrentHashMap; |
| 9 | 11 | |
| ... | ... | @@ -67,4 +69,19 @@ public class ZLMHttpHookSubscribe { |
| 67 | 69 | } |
| 68 | 70 | return event; |
| 69 | 71 | } |
| 72 | + | |
| 73 | + public List<ZLMHttpHookSubscribe.Event> getSubscribes(HookType type) { | |
| 74 | + ZLMHttpHookSubscribe.Event event= null; | |
| 75 | + Map<JSONObject, Event> eventMap = allSubscribes.get(type); | |
| 76 | + if (eventMap == null) { | |
| 77 | + return null; | |
| 78 | + } | |
| 79 | + List<ZLMHttpHookSubscribe.Event> result = new ArrayList<>(); | |
| 80 | + for (JSONObject key : eventMap.keySet()) { | |
| 81 | + result.add(eventMap.get(key)); | |
| 82 | + } | |
| 83 | + return result; | |
| 84 | + } | |
| 85 | + | |
| 86 | + | |
| 70 | 87 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
| ... | ... | @@ -32,6 +32,7 @@ public class ZLMMediaListManager { |
| 32 | 32 | |
| 33 | 33 | public void updateMediaList() { |
| 34 | 34 | JSONObject mediaList = zlmresTfulUtils.getMediaList(); |
| 35 | + if (mediaList == null) return; | |
| 35 | 36 | String dataStr = mediaList.getString("data"); |
| 36 | 37 | |
| 37 | 38 | Integer code = mediaList.getInteger("code"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
| ... | ... | @@ -131,4 +131,25 @@ public class ZLMRESTfulUtils { |
| 131 | 131 | public JSONObject stopSendRtp(Map<String, Object> param) { |
| 132 | 132 | return sendPost("stopSendRtp",param); |
| 133 | 133 | } |
| 134 | + | |
| 135 | + public JSONObject addStreamProxy(String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) { | |
| 136 | + Map<String, Object> param = new HashMap<>(); | |
| 137 | + param.put("vhost", "__defaultVhost__"); | |
| 138 | + param.put("app", app); | |
| 139 | + param.put("stream", stream); | |
| 140 | + param.put("url", url); | |
| 141 | + param.put("enable_hls", enable_hls?1:0); | |
| 142 | + param.put("enable_mp4", enable_mp4?1:0); | |
| 143 | + param.put("rtp_type", rtp_type); | |
| 144 | + return sendPost("addStreamProxy",param); | |
| 145 | + } | |
| 146 | + | |
| 147 | + public JSONObject closeStreams(String app, String stream) { | |
| 148 | + Map<String, Object> param = new HashMap<>(); | |
| 149 | + param.put("vhost", "__defaultVhost__"); | |
| 150 | + param.put("app", app); | |
| 151 | + param.put("stream", stream); | |
| 152 | + param.put("force", 1); | |
| 153 | + return sendPost("close_streams",param); | |
| 154 | + } | |
| 134 | 155 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
| ... | ... | @@ -4,8 +4,11 @@ import com.alibaba.fastjson.JSON; |
| 4 | 4 | import com.alibaba.fastjson.JSONArray; |
| 5 | 5 | import com.alibaba.fastjson.JSONObject; |
| 6 | 6 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 7 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; | |
| 7 | 8 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 8 | 9 | //import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 10 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | |
| 11 | +import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; | |
| 9 | 12 | import org.slf4j.Logger; |
| 10 | 13 | import org.slf4j.LoggerFactory; |
| 11 | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -16,6 +19,7 @@ import org.springframework.stereotype.Component; |
| 16 | 19 | import org.springframework.util.StringUtils; |
| 17 | 20 | |
| 18 | 21 | import java.util.HashMap; |
| 22 | +import java.util.List; | |
| 19 | 23 | import java.util.Map; |
| 20 | 24 | |
| 21 | 25 | @Component |
| ... | ... | @@ -24,8 +28,8 @@ public class ZLMRunner implements CommandLineRunner { |
| 24 | 28 | |
| 25 | 29 | private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class); |
| 26 | 30 | |
| 27 | - // @Autowired | |
| 28 | - // private IVideoManagerStorager storager; | |
| 31 | + @Autowired | |
| 32 | + private IVideoManagerStorager storager; | |
| 29 | 33 | |
| 30 | 34 | @Autowired |
| 31 | 35 | private IRedisCatchStorage redisCatchStorage; |
| ... | ... | @@ -63,18 +67,27 @@ public class ZLMRunner implements CommandLineRunner { |
| 63 | 67 | @Autowired |
| 64 | 68 | private ZLMMediaListManager zlmMediaListManager; |
| 65 | 69 | |
| 70 | + @Autowired | |
| 71 | + private ZLMHttpHookSubscribe hookSubscribe; | |
| 72 | + | |
| 73 | + @Autowired | |
| 74 | + private IStreamProxyService streamProxyService; | |
| 75 | + | |
| 66 | 76 | @Override |
| 67 | 77 | public void run(String... strings) throws Exception { |
| 78 | + JSONObject subscribeKey = new JSONObject(); | |
| 79 | + // 订阅 zlm启动事件 | |
| 80 | + hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,subscribeKey,(response)->{ | |
| 81 | + MediaServerConfig mediaServerConfig = JSONObject.toJavaObject(response, MediaServerConfig.class); | |
| 82 | + zLmRunning(mediaServerConfig); | |
| 83 | + }); | |
| 84 | + | |
| 68 | 85 | // 获取zlm信息 |
| 69 | 86 | logger.info("等待zlm接入..."); |
| 70 | 87 | MediaServerConfig mediaServerConfig = getMediaServerConfig(); |
| 88 | + | |
| 71 | 89 | if (mediaServerConfig != null) { |
| 72 | - logger.info("zlm接入成功..."); | |
| 73 | - if (autoConfig) saveZLMConfig(); | |
| 74 | - mediaServerConfig = getMediaServerConfig(); | |
| 75 | - redisCatchStorage.updateMediaInfo(mediaServerConfig); | |
| 76 | - // 更新流列表 | |
| 77 | - zlmMediaListManager.updateMediaList(); | |
| 90 | + zLmRunning(mediaServerConfig); | |
| 78 | 91 | } |
| 79 | 92 | } |
| 80 | 93 | |
| ... | ... | @@ -85,8 +98,7 @@ public class ZLMRunner implements CommandLineRunner { |
| 85 | 98 | JSONArray data = responseJSON.getJSONArray("data"); |
| 86 | 99 | if (data != null && data.size() > 0) { |
| 87 | 100 | mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class); |
| 88 | - mediaServerConfig.setLocalIP(mediaIp); | |
| 89 | - mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp); | |
| 101 | + | |
| 90 | 102 | } |
| 91 | 103 | } else { |
| 92 | 104 | logger.error("getMediaServerConfig失败, 1s后重试"); |
| ... | ... | @@ -136,4 +148,27 @@ public class ZLMRunner implements CommandLineRunner { |
| 136 | 148 | } |
| 137 | 149 | } |
| 138 | 150 | |
| 151 | + /** | |
| 152 | + * zlm 连接成功或者zlm重启后 | |
| 153 | + */ | |
| 154 | + private void zLmRunning(MediaServerConfig mediaServerConfig){ | |
| 155 | + logger.info("zlm接入成功..."); | |
| 156 | + if (autoConfig) saveZLMConfig(); | |
| 157 | + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); | |
| 158 | + if (System.currentTimeMillis() - mediaInfo.getUpdateTime() < 50){ | |
| 159 | + logger.info("zlm刚刚更新,忽略这次更新"); | |
| 160 | + return; | |
| 161 | + } | |
| 162 | + mediaServerConfig.setLocalIP(mediaIp); | |
| 163 | + mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp); | |
| 164 | + redisCatchStorage.updateMediaInfo(mediaServerConfig); | |
| 165 | + // 更新流列表 | |
| 166 | + zlmMediaListManager.updateMediaList(); | |
| 167 | + // 恢复流代理 | |
| 168 | + List<StreamProxyDto> streamProxyListForEnable = storager.getStreamProxyListForEnable(true); | |
| 169 | + for (StreamProxyDto streamProxyDto : streamProxyListForEnable) { | |
| 170 | + logger.info("恢复流代理," + streamProxyDto.getApp() + "/" + streamProxyDto.getStream()); | |
| 171 | + streamProxyService.addStreamProxyToZlm(streamProxyDto); | |
| 172 | + } | |
| 173 | + } | |
| 139 | 174 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyDto.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | |
| 2 | + | |
| 3 | +public class StreamProxyDto { | |
| 4 | + private String type; | |
| 5 | + private String app; | |
| 6 | + private String stream; | |
| 7 | + private String url; | |
| 8 | + private String src_url; | |
| 9 | + private String dst_url; | |
| 10 | + private int timeout_ms; | |
| 11 | + private String ffmpeg_cmd_key; | |
| 12 | + private String rtp_type; | |
| 13 | + private boolean enable; | |
| 14 | + private boolean enable_hls; | |
| 15 | + private boolean enable_mp4; | |
| 16 | + | |
| 17 | + public String getType() { | |
| 18 | + return type; | |
| 19 | + } | |
| 20 | + | |
| 21 | + public void setType(String type) { | |
| 22 | + this.type = type; | |
| 23 | + } | |
| 24 | + | |
| 25 | + public String getApp() { | |
| 26 | + return app; | |
| 27 | + } | |
| 28 | + | |
| 29 | + public void setApp(String app) { | |
| 30 | + this.app = app; | |
| 31 | + } | |
| 32 | + | |
| 33 | + public String getStream() { | |
| 34 | + return stream; | |
| 35 | + } | |
| 36 | + | |
| 37 | + public void setStream(String stream) { | |
| 38 | + this.stream = stream; | |
| 39 | + } | |
| 40 | + | |
| 41 | + public String getUrl() { | |
| 42 | + return url; | |
| 43 | + } | |
| 44 | + | |
| 45 | + public void setUrl(String url) { | |
| 46 | + this.url = url; | |
| 47 | + } | |
| 48 | + | |
| 49 | + public String getSrc_url() { | |
| 50 | + return src_url; | |
| 51 | + } | |
| 52 | + | |
| 53 | + public void setSrc_url(String src_url) { | |
| 54 | + this.src_url = src_url; | |
| 55 | + } | |
| 56 | + | |
| 57 | + public String getDst_url() { | |
| 58 | + return dst_url; | |
| 59 | + } | |
| 60 | + | |
| 61 | + public void setDst_url(String dst_url) { | |
| 62 | + this.dst_url = dst_url; | |
| 63 | + } | |
| 64 | + | |
| 65 | + public int getTimeout_ms() { | |
| 66 | + return timeout_ms; | |
| 67 | + } | |
| 68 | + | |
| 69 | + public void setTimeout_ms(int timeout_ms) { | |
| 70 | + this.timeout_ms = timeout_ms; | |
| 71 | + } | |
| 72 | + | |
| 73 | + public String getFfmpeg_cmd_key() { | |
| 74 | + return ffmpeg_cmd_key; | |
| 75 | + } | |
| 76 | + | |
| 77 | + public void setFfmpeg_cmd_key(String ffmpeg_cmd_key) { | |
| 78 | + this.ffmpeg_cmd_key = ffmpeg_cmd_key; | |
| 79 | + } | |
| 80 | + | |
| 81 | + public String getRtp_type() { | |
| 82 | + return rtp_type; | |
| 83 | + } | |
| 84 | + | |
| 85 | + public void setRtp_type(String rtp_type) { | |
| 86 | + this.rtp_type = rtp_type; | |
| 87 | + } | |
| 88 | + | |
| 89 | + public boolean isEnable() { | |
| 90 | + return enable; | |
| 91 | + } | |
| 92 | + | |
| 93 | + public void setEnable(boolean enable) { | |
| 94 | + this.enable = enable; | |
| 95 | + } | |
| 96 | + | |
| 97 | + public boolean isEnable_hls() { | |
| 98 | + return enable_hls; | |
| 99 | + } | |
| 100 | + | |
| 101 | + public void setEnable_hls(boolean enable_hls) { | |
| 102 | + this.enable_hls = enable_hls; | |
| 103 | + } | |
| 104 | + | |
| 105 | + public boolean isEnable_mp4() { | |
| 106 | + return enable_mp4; | |
| 107 | + } | |
| 108 | + | |
| 109 | + public void setEnable_mp4(boolean enable_mp4) { | |
| 110 | + this.enable_mp4 = enable_mp4; | |
| 111 | + } | |
| 112 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| 1 | 1 | package com.genersoft.iot.vmp.storager; |
| 2 | 2 | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 3 | 4 | import com.genersoft.iot.vmp.common.RealVideo; |
| 4 | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 5 | 6 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| ... | ... | @@ -116,5 +117,5 @@ public interface IRedisCatchStorage { |
| 116 | 117 | * 获取当前媒体流列表 |
| 117 | 118 | * @return List<RealVideo> |
| 118 | 119 | */ |
| 119 | - List<Object> getMediaList(int start, int end); | |
| 120 | + JSONObject getMediaList(int start, int end); | |
| 120 | 121 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
| ... | ... | @@ -5,6 +5,7 @@ import java.util.List; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 6 | 6 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 8 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; | |
| 8 | 9 | import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
| 9 | 10 | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| 10 | 11 | import com.github.pagehelper.PageInfo; |
| ... | ... | @@ -261,4 +262,49 @@ public interface IVideoManagerStorager { |
| 261 | 262 | * @param deviceId |
| 262 | 263 | */ |
| 263 | 264 | public int clearMobilePositionsByDeviceId(String deviceId); |
| 265 | + | |
| 266 | + /** | |
| 267 | + * 新增代理流 | |
| 268 | + * @param streamProxyDto | |
| 269 | + * @return | |
| 270 | + */ | |
| 271 | + public int addStreamProxy(StreamProxyDto streamProxyDto); | |
| 272 | + | |
| 273 | + /** | |
| 274 | + * 更新代理流 | |
| 275 | + * @param streamProxyDto | |
| 276 | + * @return | |
| 277 | + */ | |
| 278 | + public int updateStreamProxy(StreamProxyDto streamProxyDto); | |
| 279 | + | |
| 280 | + /** | |
| 281 | + * 移除代理流 | |
| 282 | + * @param app | |
| 283 | + * @param stream | |
| 284 | + * @return | |
| 285 | + */ | |
| 286 | + public int deleteStreamProxy(String app, String stream); | |
| 287 | + | |
| 288 | + /** | |
| 289 | + * 按照是否启用获取代理流 | |
| 290 | + * @param enable | |
| 291 | + * @return | |
| 292 | + */ | |
| 293 | + public List<StreamProxyDto> getStreamProxyListForEnable(boolean enable); | |
| 294 | + | |
| 295 | + /** | |
| 296 | + * 按照是app和stream获取代理流 | |
| 297 | + * @param app | |
| 298 | + * @param stream | |
| 299 | + * @return | |
| 300 | + */ | |
| 301 | + public StreamProxyDto queryStreamProxy(String app, String stream); | |
| 302 | + | |
| 303 | + /** | |
| 304 | + * 获取代理流 | |
| 305 | + * @param page | |
| 306 | + * @param count | |
| 307 | + * @return | |
| 308 | + */ | |
| 309 | + PageInfo<StreamProxyDto> queryStreamProxyList(Integer page, Integer count); | |
| 264 | 310 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.storager.dao; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; | |
| 4 | +import org.apache.ibatis.annotations.*; | |
| 5 | +import org.springframework.stereotype.Repository; | |
| 6 | + | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 9 | +@Mapper | |
| 10 | +@Repository | |
| 11 | +public interface StreamProxyMapper { | |
| 12 | + | |
| 13 | + @Insert("INSERT INTO stream_proxy (type, app, stream, url, src_url, dst_url, " + | |
| 14 | + "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable) VALUES" + | |
| 15 | + "('${type}','${app}', '${stream}', '${url}', '${src_url}', '${dst_url}', " + | |
| 16 | + "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable} )") | |
| 17 | + int add(StreamProxyDto streamProxyDto); | |
| 18 | + | |
| 19 | + @Update("UPDATE stream_proxy " + | |
| 20 | + "SET type=#{type}, " + | |
| 21 | + "app=#{app}," + | |
| 22 | + "stream=#{stream}," + | |
| 23 | + "url=#{url}, " + | |
| 24 | + "src_url=#{src_url}," + | |
| 25 | + "dst_url=#{dst_url}, " + | |
| 26 | + "timeout_ms=#{timeout_ms}, " + | |
| 27 | + "ffmpeg_cmd_key=#{ffmpeg_cmd_key}, " + | |
| 28 | + "rtp_type=#{rtp_type}, " + | |
| 29 | + "enable_hls=#{enable_hls}, " + | |
| 30 | + "enable=#{enable}, " + | |
| 31 | + "enable_mp4=#{enable_mp4} " + | |
| 32 | + "WHERE app=#{app} AND stream=#{stream}") | |
| 33 | + int update(StreamProxyDto streamProxyDto); | |
| 34 | + | |
| 35 | + @Delete("DELETE FROM stream_proxy WHERE app=#{app} AND stream=#{stream}") | |
| 36 | + int del(String app, String stream); | |
| 37 | + | |
| 38 | + @Select("SELECT * FROM stream_proxy") | |
| 39 | + List<StreamProxyDto> selectAll(); | |
| 40 | + | |
| 41 | + @Select("SELECT * FROM stream_proxy WHERE enable=${enable}") | |
| 42 | + List<StreamProxyDto> selectForEnable(boolean enable); | |
| 43 | + | |
| 44 | + @Select("SELECT * FROM stream_proxy WHERE app=#{app} AND stream=#{stream}") | |
| 45 | + StreamProxyDto selectOne(String app, String stream); | |
| 46 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.impl; |
| 2 | 2 | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 3 | 4 | import com.genersoft.iot.vmp.common.RealVideo; |
| 4 | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 5 | 6 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| ... | ... | @@ -92,6 +93,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 92 | 93 | */ |
| 93 | 94 | @Override |
| 94 | 95 | public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) { |
| 96 | + mediaServerConfig.setUpdateTime(System.currentTimeMillis()); | |
| 95 | 97 | return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig); |
| 96 | 98 | } |
| 97 | 99 | |
| ... | ... | @@ -280,9 +282,13 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 280 | 282 | * @return List<RealVideo> |
| 281 | 283 | */ |
| 282 | 284 | @Override |
| 283 | - public List<Object> getMediaList(int start, int end) { | |
| 285 | + public JSONObject getMediaList(int start, int end) { | |
| 284 | 286 | String key = VideoManagerConstants.MEDIA_STREAM_PREFIX; |
| 285 | 287 | Set<Object> realVideos = redis.ZRange(key, start, end); |
| 286 | - return new ArrayList(realVideos); | |
| 288 | + JSONObject jsonObject = new JSONObject(); | |
| 289 | + jsonObject.put("list", new ArrayList(realVideos)); | |
| 290 | + jsonObject.put("total", redis.zSize(key)); | |
| 291 | + | |
| 292 | + return jsonObject; | |
| 287 | 293 | } |
| 288 | 294 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
| ... | ... | @@ -5,14 +5,11 @@ import java.util.*; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 6 | 6 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; |
| 8 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; | |
| 8 | 9 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 9 | 10 | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| 10 | -import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; | |
| 11 | -import com.genersoft.iot.vmp.storager.dao.DeviceMapper; | |
| 12 | -import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; | |
| 13 | -import com.genersoft.iot.vmp.storager.dao.PatformChannelMapper; | |
| 11 | +import com.genersoft.iot.vmp.storager.dao.*; | |
| 14 | 12 | import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
| 15 | -import com.genersoft.iot.vmp.storager.dao.DeviceMobilePositionMapper; | |
| 16 | 13 | import com.github.pagehelper.PageHelper; |
| 17 | 14 | import com.github.pagehelper.PageInfo; |
| 18 | 15 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -49,6 +46,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 49 | 46 | @Autowired |
| 50 | 47 | private PatformChannelMapper patformChannelMapper; |
| 51 | 48 | |
| 49 | + @Autowired | |
| 50 | + private StreamProxyMapper streamProxyMapper; | |
| 51 | + | |
| 52 | 52 | |
| 53 | 53 | |
| 54 | 54 | |
| ... | ... | @@ -233,7 +233,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 233 | 233 | |
| 234 | 234 | /** |
| 235 | 235 | * 添加Mobile Position设备移动位置 |
| 236 | - * @param MobilePosition | |
| 236 | + * @param mobilePosition | |
| 237 | 237 | */ |
| 238 | 238 | @Override |
| 239 | 239 | public synchronized boolean insertMobilePosition(MobilePosition mobilePosition) { |
| ... | ... | @@ -388,4 +388,68 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 388 | 388 | return deviceMobilePositionMapper.clearMobilePositionsByDeviceId(deviceId); |
| 389 | 389 | } |
| 390 | 390 | |
| 391 | + /** | |
| 392 | + * 新增代理流 | |
| 393 | + * @param streamProxyDto | |
| 394 | + * @return | |
| 395 | + */ | |
| 396 | + @Override | |
| 397 | + public int addStreamProxy(StreamProxyDto streamProxyDto) { | |
| 398 | + return streamProxyMapper.add(streamProxyDto); | |
| 399 | + } | |
| 400 | + | |
| 401 | + /** | |
| 402 | + * 更新代理流 | |
| 403 | + * @param streamProxyDto | |
| 404 | + * @return | |
| 405 | + */ | |
| 406 | + @Override | |
| 407 | + public int updateStreamProxy(StreamProxyDto streamProxyDto) { | |
| 408 | + return streamProxyMapper.update(streamProxyDto); | |
| 409 | + } | |
| 410 | + | |
| 411 | + /** | |
| 412 | + * 移除代理流 | |
| 413 | + * @param id | |
| 414 | + * @return | |
| 415 | + */ | |
| 416 | + @Override | |
| 417 | + public int deleteStreamProxy(String app, String stream) { | |
| 418 | + return streamProxyMapper.del(app, stream); | |
| 419 | + } | |
| 420 | + | |
| 421 | + /** | |
| 422 | + * 根据是否启用获取代理流列表 | |
| 423 | + * @param enable | |
| 424 | + * @return | |
| 425 | + */ | |
| 426 | + @Override | |
| 427 | + public List<StreamProxyDto> getStreamProxyListForEnable(boolean enable) { | |
| 428 | + return streamProxyMapper.selectForEnable(enable); | |
| 429 | + } | |
| 430 | + | |
| 431 | + /** | |
| 432 | + * 分页查询代理流列表 | |
| 433 | + * @param page | |
| 434 | + * @param count | |
| 435 | + * @return | |
| 436 | + */ | |
| 437 | + @Override | |
| 438 | + public PageInfo<StreamProxyDto> queryStreamProxyList(Integer page, Integer count) { | |
| 439 | + PageHelper.startPage(page, count); | |
| 440 | + List<StreamProxyDto> all = streamProxyMapper.selectAll(); | |
| 441 | + return new PageInfo<>(all); | |
| 442 | + } | |
| 443 | + | |
| 444 | + | |
| 445 | + /** | |
| 446 | + * 按照是app和stream获取代理流 | |
| 447 | + * @param app | |
| 448 | + * @param stream | |
| 449 | + * @return | |
| 450 | + */ | |
| 451 | + @Override | |
| 452 | + public StreamProxyDto queryStreamProxy(String app, String stream){ | |
| 453 | + return streamProxyMapper.selectOne(app, stream); | |
| 454 | + } | |
| 391 | 455 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/media/MediaController.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.media; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 5 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 6 | +import com.genersoft.iot.vmp.vmanager.service.IMediaService; | |
| 7 | +import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; | |
| 8 | +import org.slf4j.Logger; | |
| 9 | +import org.slf4j.LoggerFactory; | |
| 10 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 11 | +import org.springframework.stereotype.Controller; | |
| 12 | +import org.springframework.web.bind.annotation.*; | |
| 13 | + | |
| 14 | + | |
| 15 | +@Controller | |
| 16 | +@CrossOrigin | |
| 17 | +@RequestMapping(value = "/api/media") | |
| 18 | +public class MediaController { | |
| 19 | + | |
| 20 | + private final static Logger logger = LoggerFactory.getLogger(MediaController.class); | |
| 21 | + | |
| 22 | + @Autowired | |
| 23 | + private IRedisCatchStorage redisCatchStorage; | |
| 24 | + | |
| 25 | + @Autowired | |
| 26 | + private IStreamProxyService streamProxyService; | |
| 27 | + | |
| 28 | + @Autowired | |
| 29 | + private IMediaService mediaService; | |
| 30 | + | |
| 31 | + | |
| 32 | + @RequestMapping(value = "/list") | |
| 33 | + @ResponseBody | |
| 34 | + public JSONObject list( @RequestParam(required = false)Integer page, | |
| 35 | + @RequestParam(required = false)Integer count, | |
| 36 | + @RequestParam(required = false)String q, | |
| 37 | + @RequestParam(required = false)Boolean online ){ | |
| 38 | + | |
| 39 | + JSONObject jsonObject = redisCatchStorage.getMediaList(page - 1, page - 1 + count); | |
| 40 | + return jsonObject; | |
| 41 | + } | |
| 42 | + | |
| 43 | + @RequestMapping(value = "/getStreamInfoByAppAndStream") | |
| 44 | + @ResponseBody | |
| 45 | + public StreamInfo getStreamInfoByAppAndStream(String app, String stream){ | |
| 46 | + return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream); | |
| 47 | + } | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
| ... | ... | @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 8 | 8 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 9 | 9 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 10 | 10 | import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult; |
| 11 | +import com.genersoft.iot.vmp.vmanager.service.IMediaService; | |
| 11 | 12 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| 12 | 13 | import org.slf4j.Logger; |
| 13 | 14 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -55,6 +56,9 @@ public class PlayController { |
| 55 | 56 | @Autowired |
| 56 | 57 | private IPlayService playService; |
| 57 | 58 | |
| 59 | + @Autowired | |
| 60 | + private IMediaService mediaService; | |
| 61 | + | |
| 58 | 62 | @GetMapping("/play/{deviceId}/{channelId}") |
| 59 | 63 | public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, |
| 60 | 64 | @PathVariable String channelId) { |
| ... | ... | @@ -159,18 +163,20 @@ public class PlayController { |
| 159 | 163 | JSONObject data = jsonObject.getJSONObject("data"); |
| 160 | 164 | if (data != null) { |
| 161 | 165 | result.put("key", data.getString("key")); |
| 162 | - StreamInfo streamInfoResult = new StreamInfo(); | |
| 163 | - streamInfoResult.setRtmp(dstUrl); | |
| 164 | - streamInfoResult.setRtsp(String.format("rtsp://%s:%s/convert/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); | |
| 166 | +// StreamInfo streamInfoResult = new StreamInfo(); | |
| 167 | +// streamInfoResult.setRtmp(dstUrl); | |
| 168 | +// streamInfoResult.setRtsp(String.format("rtsp://%s:%s/convert/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); | |
| 169 | +// streamInfoResult.setStreamId(streamId); | |
| 170 | +// streamInfoResult.setFlv(String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 171 | +// streamInfoResult.setWs_flv(String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 172 | +// streamInfoResult.setHls(String.format("http://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 173 | +// streamInfoResult.setWs_hls(String.format("ws://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 174 | +// streamInfoResult.setFmp4(String.format("http://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 175 | +// streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 176 | +// streamInfoResult.setTs(String.format("http://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 177 | +// streamInfoResult.setWs_ts(String.format("ws://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 178 | + StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStream("convert", streamId); | |
| 165 | 179 | streamInfoResult.setStreamId(streamId); |
| 166 | - streamInfoResult.setFlv(String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 167 | - streamInfoResult.setWs_flv(String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 168 | - streamInfoResult.setHls(String.format("http://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 169 | - streamInfoResult.setWs_hls(String.format("ws://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 170 | - streamInfoResult.setFmp4(String.format("http://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 171 | - streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 172 | - streamInfoResult.setTs(String.format("http://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 173 | - streamInfoResult.setWs_ts(String.format("ws://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 174 | 180 | result.put("data", streamInfoResult); |
| 175 | 181 | } |
| 176 | 182 | }else { | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/service/IMediaService.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.service; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 媒体信息业务 | |
| 7 | + */ | |
| 8 | +public interface IMediaService { | |
| 9 | + | |
| 10 | + /** | |
| 11 | + * 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在 | |
| 12 | + * @param app | |
| 13 | + * @param stream | |
| 14 | + * @return | |
| 15 | + */ | |
| 16 | + StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream); | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 根据应用名和流ID获取播放地址, 只是地址拼接 | |
| 20 | + * @param app | |
| 21 | + * @param stream | |
| 22 | + * @return | |
| 23 | + */ | |
| 24 | + StreamInfo getStreamInfoByAppAndStream(String app, String stream); | |
| 25 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/service/IStreamProxyService.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.service; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; | |
| 5 | +import com.genersoft.iot.vmp.vmanager.streamProxy.StreamProxyController; | |
| 6 | +import com.github.pagehelper.PageInfo; | |
| 7 | + | |
| 8 | +public interface IStreamProxyService { | |
| 9 | + | |
| 10 | + /** | |
| 11 | + * 保存视频代理 | |
| 12 | + * @param param | |
| 13 | + */ | |
| 14 | + void save(StreamProxyDto param); | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 添加视频代理到zlm | |
| 18 | + * @param param | |
| 19 | + * @return | |
| 20 | + */ | |
| 21 | + JSONObject addStreamProxyToZlm(StreamProxyDto param); | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 从zlm移除视频代理 | |
| 25 | + * @param param | |
| 26 | + * @return | |
| 27 | + */ | |
| 28 | + JSONObject removeStreamProxyFromZlm(StreamProxyDto param); | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 分页查询 | |
| 32 | + * @param page | |
| 33 | + * @param count | |
| 34 | + * @return | |
| 35 | + */ | |
| 36 | + PageInfo<StreamProxyDto> getAll(Integer page, Integer count); | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 删除视频代理 | |
| 40 | + * @param app | |
| 41 | + * @param stream | |
| 42 | + */ | |
| 43 | + void del(String app, String stream); | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 启用视频代理 | |
| 47 | + * @param app | |
| 48 | + * @param stream | |
| 49 | + * @return | |
| 50 | + */ | |
| 51 | + boolean start(String app, String stream); | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 停用用视频代理 | |
| 55 | + * @param app | |
| 56 | + * @param stream | |
| 57 | + * @return | |
| 58 | + */ | |
| 59 | + boolean stop(String app, String stream); | |
| 60 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/MediaServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.service.impl; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 5 | +import com.genersoft.iot.vmp.conf.MediaServerConfig; | |
| 6 | +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | |
| 7 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 8 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | |
| 9 | +import com.genersoft.iot.vmp.vmanager.service.IMediaService; | |
| 10 | +import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; | |
| 11 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 12 | +import org.springframework.stereotype.Service; | |
| 13 | + | |
| 14 | +@Service | |
| 15 | +public class MediaServiceImpl implements IMediaService { | |
| 16 | + | |
| 17 | + @Autowired | |
| 18 | + private IRedisCatchStorage redisCatchStorage; | |
| 19 | + | |
| 20 | + @Autowired | |
| 21 | + private IVideoManagerStorager storager; | |
| 22 | + | |
| 23 | + @Autowired | |
| 24 | + private ZLMRESTfulUtils zlmresTfulUtils; | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public StreamInfo getStreamInfoByAppAndStream(String app, String stream) { | |
| 28 | + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); | |
| 29 | + StreamInfo streamInfoResult = new StreamInfo(); | |
| 30 | + streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), app, stream)); | |
| 31 | + streamInfoResult.setRtsp(String.format("rtsp://%s:%s/%s/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), app, stream)); | |
| 32 | + streamInfoResult.setFlv(String.format("http://%s:%s/%s/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 33 | + streamInfoResult.setWs_flv(String.format("ws://%s:%s/%s/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 34 | + streamInfoResult.setHls(String.format("http://%s:%s/%s/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 35 | + streamInfoResult.setWs_hls(String.format("ws://%s:%s/%s/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 36 | + streamInfoResult.setFmp4(String.format("http://%s:%s/%s/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 37 | + streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/%s/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 38 | + streamInfoResult.setTs(String.format("http://%s:%s/%s/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 39 | + streamInfoResult.setWs_ts(String.format("ws://%s:%s/%s/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); | |
| 40 | + return streamInfoResult; | |
| 41 | + } | |
| 42 | + | |
| 43 | + @Override | |
| 44 | + public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream) { | |
| 45 | + StreamInfo streamInfo = null; | |
| 46 | + JSONObject mediaList = zlmresTfulUtils.getMediaList(app, stream); | |
| 47 | + if (mediaList != null) { | |
| 48 | + streamInfo = getStreamInfoByAppAndStream(app, stream); | |
| 49 | + } | |
| 50 | + return streamInfo; | |
| 51 | + } | |
| 52 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
| ... | ... | @@ -15,6 +15,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 15 | 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 16 | 16 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 17 | 17 | import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult; |
| 18 | +import com.genersoft.iot.vmp.vmanager.service.IMediaService; | |
| 18 | 19 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| 19 | 20 | import org.slf4j.Logger; |
| 20 | 21 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -46,6 +47,9 @@ public class PlayServiceImpl implements IPlayService { |
| 46 | 47 | @Autowired |
| 47 | 48 | private ZLMRESTfulUtils zlmresTfulUtils; |
| 48 | 49 | |
| 50 | + @Autowired | |
| 51 | + private IMediaService mediaService; | |
| 52 | + | |
| 49 | 53 | |
| 50 | 54 | @Override |
| 51 | 55 | public PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) { |
| ... | ... | @@ -148,26 +152,27 @@ public class PlayServiceImpl implements IPlayService { |
| 148 | 152 | |
| 149 | 153 | public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) { |
| 150 | 154 | String streamId = resonse.getString("id"); |
| 151 | - StreamInfo streamInfo = new StreamInfo(); | |
| 155 | + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream("rtp", streamId); | |
| 156 | +// StreamInfo streamInfo = new StreamInfo(); | |
| 152 | 157 | streamInfo.setStreamId(streamId); |
| 153 | 158 | streamInfo.setDeviceID(deviceId); |
| 154 | 159 | streamInfo.setChannelId(channelId); |
| 155 | - MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo(); | |
| 156 | - | |
| 157 | - streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 158 | - streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 159 | - | |
| 160 | - streamInfo.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 161 | - streamInfo.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 162 | - | |
| 163 | - streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 164 | - streamInfo.setWs_hls(String.format("ws://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 165 | - | |
| 166 | - streamInfo.setTs(String.format("http://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 167 | - streamInfo.setWs_ts(String.format("ws://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 168 | - | |
| 169 | - streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtmpPort(), streamId)); | |
| 170 | - streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtspPort(), streamId)); | |
| 160 | +// MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo(); | |
| 161 | + | |
| 162 | +// streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 163 | +// streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 164 | +// | |
| 165 | +// streamInfo.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 166 | +// streamInfo.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 167 | +// | |
| 168 | +// streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 169 | +// streamInfo.setWs_hls(String.format("ws://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 170 | +// | |
| 171 | +// streamInfo.setTs(String.format("http://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 172 | +// streamInfo.setWs_ts(String.format("ws://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | |
| 173 | +// | |
| 174 | +// streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtmpPort(), streamId)); | |
| 175 | +// streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtspPort(), streamId)); | |
| 171 | 176 | |
| 172 | 177 | return streamInfo; |
| 173 | 178 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/StreamProxyServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.service.impl; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.genersoft.iot.vmp.conf.MediaServerConfig; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | |
| 6 | +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | |
| 7 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; | |
| 8 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 9 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | |
| 10 | +import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper; | |
| 11 | +import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; | |
| 12 | +import com.genersoft.iot.vmp.vmanager.streamProxy.StreamProxyController; | |
| 13 | +import com.github.pagehelper.PageHelper; | |
| 14 | +import com.github.pagehelper.PageInfo; | |
| 15 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 16 | +import org.springframework.stereotype.Service; | |
| 17 | + | |
| 18 | +import java.util.List; | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * 视频代理业务 | |
| 22 | + */ | |
| 23 | +@Service | |
| 24 | +public class StreamProxyServiceImpl implements IStreamProxyService { | |
| 25 | + | |
| 26 | + @Autowired | |
| 27 | + private IVideoManagerStorager videoManagerStorager; | |
| 28 | + | |
| 29 | + @Autowired | |
| 30 | + private IRedisCatchStorage redisCatchStorage; | |
| 31 | + | |
| 32 | + @Autowired | |
| 33 | + private ZLMRESTfulUtils zlmresTfulUtils; | |
| 34 | + | |
| 35 | + @Autowired | |
| 36 | + private StreamProxyMapper streamProxyMapper; | |
| 37 | + | |
| 38 | + | |
| 39 | + @Override | |
| 40 | + public void save(StreamProxyDto param) { | |
| 41 | + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); | |
| 42 | + String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), | |
| 43 | + param.getStream() ); | |
| 44 | + param.setDst_url(dstUrl); | |
| 45 | + // 更新 | |
| 46 | + if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) { | |
| 47 | + int result = videoManagerStorager.updateStreamProxy(param); | |
| 48 | + if (result > 0 && param.isEnable()) { | |
| 49 | + addStreamProxyToZlm(param); | |
| 50 | + } | |
| 51 | + }else { // 新增 | |
| 52 | + int result = videoManagerStorager.addStreamProxy(param); | |
| 53 | + if (result > 0 && param.isEnable()) { | |
| 54 | + addStreamProxyToZlm(param); | |
| 55 | + } | |
| 56 | + } | |
| 57 | + } | |
| 58 | + | |
| 59 | + @Override | |
| 60 | + public JSONObject addStreamProxyToZlm(StreamProxyDto param) { | |
| 61 | + JSONObject result = null; | |
| 62 | + if ("default".equals(param.getType())){ | |
| 63 | + result = zlmresTfulUtils.addStreamProxy(param.getApp(), param.getStream(), param.getUrl(), | |
| 64 | + param.isEnable_hls(), param.isEnable_mp4(), param.getRtp_type()); | |
| 65 | + }else if ("ffmpeg".equals(param.getType())) { | |
| 66 | + result = zlmresTfulUtils.addFFmpegSource(param.getSrc_url(), param.getDst_url(), | |
| 67 | + param.getTimeout_ms() + ""); | |
| 68 | + } | |
| 69 | + return result; | |
| 70 | + } | |
| 71 | + | |
| 72 | + @Override | |
| 73 | + public JSONObject removeStreamProxyFromZlm(StreamProxyDto param) { | |
| 74 | + JSONObject result = zlmresTfulUtils.closeStreams(param.getApp(), param.getStream()); | |
| 75 | + return result; | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Override | |
| 79 | + public PageInfo<StreamProxyDto> getAll(Integer page, Integer count) { | |
| 80 | + return videoManagerStorager.queryStreamProxyList(page, count); | |
| 81 | + } | |
| 82 | + | |
| 83 | + @Override | |
| 84 | + public void del(String app, String stream) { | |
| 85 | + StreamProxyDto streamProxyDto = new StreamProxyDto(); | |
| 86 | + streamProxyDto.setApp(app); | |
| 87 | + streamProxyDto.setStream(stream); | |
| 88 | + JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyDto); | |
| 89 | + if (jsonObject.getInteger("code") == 0) { | |
| 90 | + videoManagerStorager.deleteStreamProxy(app, stream); | |
| 91 | + } | |
| 92 | + } | |
| 93 | + | |
| 94 | + @Override | |
| 95 | + public boolean start(String app, String stream) { | |
| 96 | + boolean result = false; | |
| 97 | + StreamProxyDto streamProxyDto = videoManagerStorager.queryStreamProxy(app, stream); | |
| 98 | + if (!streamProxyDto.isEnable() && streamProxyDto != null) { | |
| 99 | + JSONObject jsonObject = addStreamProxyToZlm(streamProxyDto); | |
| 100 | + if (jsonObject.getInteger("code") == 0) { | |
| 101 | + result = true; | |
| 102 | + streamProxyDto.setEnable(true); | |
| 103 | + videoManagerStorager.updateStreamProxy(streamProxyDto); | |
| 104 | + } | |
| 105 | + } | |
| 106 | + return result; | |
| 107 | + } | |
| 108 | + | |
| 109 | + @Override | |
| 110 | + public boolean stop(String app, String stream) { | |
| 111 | + boolean result = false; | |
| 112 | + StreamProxyDto streamProxyDto = videoManagerStorager.queryStreamProxy(app, stream); | |
| 113 | + if (streamProxyDto.isEnable() && streamProxyDto != null) { | |
| 114 | + JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyDto); | |
| 115 | + if (jsonObject.getInteger("code") == 0) { | |
| 116 | + result = true; | |
| 117 | + streamProxyDto.setEnable(false); | |
| 118 | + videoManagerStorager.updateStreamProxy(streamProxyDto); | |
| 119 | + } | |
| 120 | + } | |
| 121 | + return result; | |
| 122 | + } | |
| 123 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.streamProxy; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | |
| 5 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; | |
| 6 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 7 | +import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; | |
| 8 | +import com.github.pagehelper.PageInfo; | |
| 9 | +import org.slf4j.Logger; | |
| 10 | +import org.slf4j.LoggerFactory; | |
| 11 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 12 | +import org.springframework.stereotype.Controller; | |
| 13 | +import org.springframework.web.bind.annotation.*; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * 拉流代理接口 | |
| 17 | + */ | |
| 18 | +@Controller | |
| 19 | +@CrossOrigin | |
| 20 | +@RequestMapping(value = "/api/proxy") | |
| 21 | +public class StreamProxyController { | |
| 22 | + | |
| 23 | + private final static Logger logger = LoggerFactory.getLogger(StreamProxyController.class); | |
| 24 | + | |
| 25 | + @Autowired | |
| 26 | + private IRedisCatchStorage redisCatchStorage; | |
| 27 | + | |
| 28 | + @Autowired | |
| 29 | + private IStreamProxyService streamProxyService; | |
| 30 | + | |
| 31 | + | |
| 32 | + @RequestMapping(value = "/list") | |
| 33 | + @ResponseBody | |
| 34 | + public PageInfo<StreamProxyDto> list(@RequestParam(required = false)Integer page, | |
| 35 | + @RequestParam(required = false)Integer count, | |
| 36 | + @RequestParam(required = false)String q, | |
| 37 | + @RequestParam(required = false)Boolean online ){ | |
| 38 | + | |
| 39 | + return streamProxyService.getAll(page, count); | |
| 40 | + } | |
| 41 | + | |
| 42 | + @RequestMapping(value = "/save") | |
| 43 | + @ResponseBody | |
| 44 | + public Object save(@RequestBody StreamProxyDto param){ | |
| 45 | + logger.info("添加代理: " + JSONObject.toJSONString(param)); | |
| 46 | + streamProxyService.save(param); | |
| 47 | + return "success"; | |
| 48 | + } | |
| 49 | + | |
| 50 | + @RequestMapping(value = "/del") | |
| 51 | + @ResponseBody | |
| 52 | + public Object del(String app, String stream){ | |
| 53 | + logger.info("移除代理: " + app + "/" + stream); | |
| 54 | + streamProxyService.del(app, stream); | |
| 55 | + return "success"; | |
| 56 | + } | |
| 57 | + | |
| 58 | + @RequestMapping(value = "/start") | |
| 59 | + @ResponseBody | |
| 60 | + public Object start(String app, String stream){ | |
| 61 | + logger.info("启用代理: " + app + "/" + stream); | |
| 62 | + boolean result = streamProxyService.start(app, stream); | |
| 63 | + return "success"; | |
| 64 | + } | |
| 65 | + | |
| 66 | + @RequestMapping(value = "/stop") | |
| 67 | + @ResponseBody | |
| 68 | + public Object stop(String app, String stream){ | |
| 69 | + logger.info("停用代理: " + app + "/" + stream); | |
| 70 | + boolean result = streamProxyService.stop(app, stream); | |
| 71 | + return "success"; | |
| 72 | + } | |
| 73 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/ApiMediaController.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.web; | |
| 2 | - | |
| 3 | -import com.alibaba.fastjson.JSONObject; | |
| 4 | -import com.genersoft.iot.vmp.common.RealVideo; | |
| 5 | -import com.genersoft.iot.vmp.conf.SipConfig; | |
| 6 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 7 | -import org.slf4j.Logger; | |
| 8 | -import org.slf4j.LoggerFactory; | |
| 9 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 10 | -import org.springframework.stereotype.Controller; | |
| 11 | -import org.springframework.web.bind.annotation.CrossOrigin; | |
| 12 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 13 | -import org.springframework.web.bind.annotation.RequestParam; | |
| 14 | -import org.springframework.web.bind.annotation.ResponseBody; | |
| 15 | - | |
| 16 | -import java.util.List; | |
| 17 | - | |
| 18 | -/** | |
| 19 | - * 兼容LiveGBS的API:系统接口 | |
| 20 | - */ | |
| 21 | -@Controller | |
| 22 | -@CrossOrigin | |
| 23 | -@RequestMapping(value = "/api/v1/media") | |
| 24 | -public class ApiMediaController { | |
| 25 | - | |
| 26 | - private final static Logger logger = LoggerFactory.getLogger(ApiMediaController.class); | |
| 27 | - | |
| 28 | - @Autowired | |
| 29 | - private IRedisCatchStorage redisCatchStorage; | |
| 30 | - | |
| 31 | - | |
| 32 | - @RequestMapping(value = "/list") | |
| 33 | - @ResponseBody | |
| 34 | - public JSONObject list( @RequestParam(required = false)Integer start, | |
| 35 | - @RequestParam(required = false)Integer limit, | |
| 36 | - @RequestParam(required = false)String q, | |
| 37 | - @RequestParam(required = false)Boolean online ){ | |
| 38 | - | |
| 39 | - List<Object> mediaList = redisCatchStorage.getMediaList(start - 1, start - 1 + limit); | |
| 40 | - JSONObject jsonObject = new JSONObject(); | |
| 41 | - jsonObject.put("code", 0); | |
| 42 | - jsonObject.put("data", mediaList); | |
| 43 | - return jsonObject; | |
| 44 | - } | |
| 45 | -} |
src/main/resources/wvp.sqlite
No preview for this file type
web_src/package-lock.json
| ... | ... | @@ -10924,6 +10924,26 @@ |
| 10924 | 10924 | "clipboard": "^2.0.0" |
| 10925 | 10925 | } |
| 10926 | 10926 | }, |
| 10927 | + "vue-clipboards": { | |
| 10928 | + "version": "1.3.0", | |
| 10929 | + "resolved": "https://registry.npmjs.org/vue-clipboards/-/vue-clipboards-1.3.0.tgz", | |
| 10930 | + "integrity": "sha512-VMDYHpLQH0EUmqfk9b5XMrkvSu/HjNsLW2EBR4OS6JZHcv/PxmWYdoTBPVlp5eYrhWy07La8nWpRwAh09Mgufw==", | |
| 10931 | + "requires": { | |
| 10932 | + "clipboard": "^1.7.1" | |
| 10933 | + }, | |
| 10934 | + "dependencies": { | |
| 10935 | + "clipboard": { | |
| 10936 | + "version": "1.7.1", | |
| 10937 | + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz", | |
| 10938 | + "integrity": "sha1-Ng1taUbpmnof7zleQrqStem1oWs=", | |
| 10939 | + "requires": { | |
| 10940 | + "good-listener": "^1.2.2", | |
| 10941 | + "select": "^1.1.2", | |
| 10942 | + "tiny-emitter": "^2.0.0" | |
| 10943 | + } | |
| 10944 | + } | |
| 10945 | + } | |
| 10946 | + }, | |
| 10927 | 10947 | "vue-cookies": { |
| 10928 | 10948 | "version": "1.7.4", |
| 10929 | 10949 | "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz", | ... | ... |
web_src/package.json
web_src/src/components/ParentPlatformList.vue
| ... | ... | @@ -68,9 +68,9 @@ |
| 68 | 68 | </template> |
| 69 | 69 | |
| 70 | 70 | <script> |
| 71 | -import platformEdit from './platformEdit.vue' | |
| 71 | +import platformEdit from './dialog/platformEdit.vue' | |
| 72 | 72 | import uiHeader from './UiHeader.vue' |
| 73 | -import chooseChannelDialog from './gb28181/chooseChannel.vue' | |
| 73 | +import chooseChannelDialog from './dialog/chooseChannel.vue' | |
| 74 | 74 | export default { |
| 75 | 75 | name: 'app', |
| 76 | 76 | components: { | ... | ... |
web_src/src/components/PushVideoList.vue
| 1 | 1 | <template> |
| 2 | - <div id="app"> | |
| 2 | + <div id="pushVideoList"> | |
| 3 | 3 | <el-container> |
| 4 | 4 | <el-header> |
| 5 | 5 | <uiHeader></uiHeader> |
| ... | ... | @@ -7,28 +7,27 @@ |
| 7 | 7 | <el-main> |
| 8 | 8 | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> |
| 9 | 9 | <span style="font-size: 1rem; font-weight: bold;">推流列表</span> |
| 10 | - <div style="position: absolute; right: 1rem; top: 0.3rem;"> | |
| 11 | - <el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button> | |
| 12 | - </div> | |
| 13 | 10 | </div> |
| 14 | - <!-- <devicePlayer ref="devicePlayer"></devicePlayer> --> | |
| 15 | - <el-table :data="deviceList" border style="width: 100%" :height="winHeight"> | |
| 16 | - <el-table-column prop="schema" label="协议" width="180" align="center"> | |
| 11 | + <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> | |
| 12 | + <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStreamProxy">添加代理</el-button> | |
| 13 | + </div> | |
| 14 | + <devicePlayer ref="devicePlayer"></devicePlayer> | |
| 15 | + <el-table :data="pushList" border style="width: 100%" :height="winHeight"> | |
| 16 | + <el-table-column prop="app" label="APP" width="180" align="center"> | |
| 17 | 17 | </el-table-column> |
| 18 | - <el-table-column prop="streamUrl" label="流地址" width="240" align="center"> | |
| 18 | + <el-table-column prop="stream" label="流ID" width="240" align="center"> | |
| 19 | 19 | </el-table-column> |
| 20 | - <el-table-column prop="online" label="在线人数" width="240" align="center"> | |
| 20 | + <el-table-column prop="totalReaderCount" label="在线人数" width="240" align="center"> | |
| 21 | 21 | </el-table-column> |
| 22 | - <el-table-column prop="startTime" label="开始时间" align="center"> | |
| 22 | + <el-table-column prop="createStamp" label="开始时间" align="center"> | |
| 23 | 23 | </el-table-column> |
| 24 | 24 | |
| 25 | 25 | |
| 26 | 26 | <el-table-column label="操作" width="360" align="center" fixed="right"> |
| 27 | 27 | <template slot-scope="scope"> |
| 28 | - <el-button size="mini" :ref="scope.row.deviceId + 'refbtn' " icon="el-icon-refresh" @click="refDevice(scope.row)">刷新</el-button> | |
| 29 | 28 | <el-button-group> |
| 30 | - <el-button size="mini" icon="el-icon-video-play" @click="sendDevicePush(scope.row)">播放</el-button> | |
| 31 | - <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopDevicePush(scope.row)">停止</el-button> | |
| 29 | + <el-button size="mini" icon="el-icon-video-play" @click="playPuhsh(scope.row)">播放</el-button> | |
| 30 | + <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopPuhsh(scope.row)">停止</el-button> | |
| 32 | 31 | </el-button-group> |
| 33 | 32 | </template> |
| 34 | 33 | </el-table-column> |
| ... | ... | @@ -43,25 +42,27 @@ |
| 43 | 42 | layout="total, sizes, prev, pager, next" |
| 44 | 43 | :total="total"> |
| 45 | 44 | </el-pagination> |
| 46 | - | |
| 45 | + <streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit> | |
| 47 | 46 | </el-main> |
| 48 | 47 | </el-container> |
| 49 | 48 | </div> |
| 50 | 49 | </template> |
| 51 | 50 | |
| 52 | 51 | <script> |
| 52 | + import streamProxyEdit from './dialog/StreamProxyEdit.vue' | |
| 53 | + import devicePlayer from './dialog/devicePlayer.vue' | |
| 53 | 54 | import uiHeader from './UiHeader.vue' |
| 54 | 55 | export default { |
| 55 | - name: 'app', | |
| 56 | + name: 'pushVideoList', | |
| 56 | 57 | components: { |
| 58 | + devicePlayer, | |
| 59 | + streamProxyEdit, | |
| 57 | 60 | uiHeader |
| 58 | 61 | }, |
| 59 | 62 | data() { |
| 60 | 63 | return { |
| 61 | - deviceList: [], //设备列表 | |
| 62 | - currentDevice: {}, //当前操作设备对象 | |
| 63 | - | |
| 64 | - videoComponentList: [], | |
| 64 | + pushList: [], //设备列表 | |
| 65 | + currentPusher: {}, //当前操作设备对象 | |
| 65 | 66 | updateLooper: 0, //数据刷新轮训标志 |
| 66 | 67 | currentDeviceChannelsLenth:0, |
| 67 | 68 | winHeight: window.innerHeight - 200, |
| ... | ... | @@ -72,23 +73,10 @@ |
| 72 | 73 | }; |
| 73 | 74 | }, |
| 74 | 75 | computed: { |
| 75 | - getcurrentDeviceChannels: function() { | |
| 76 | - let data = this.currentDevice['channelMap']; | |
| 77 | - let channels = null; | |
| 78 | - if (data) { | |
| 79 | - channels = Object.keys(data).map(key => { | |
| 80 | - return data[key]; | |
| 81 | - }); | |
| 82 | - this.currentDeviceChannelsLenth = channels.length; | |
| 83 | - } | |
| 84 | - | |
| 85 | - console.log("数据:" + JSON.stringify(channels)); | |
| 86 | - return channels; | |
| 87 | - } | |
| 88 | 76 | }, |
| 89 | 77 | mounted() { |
| 90 | 78 | this.initData(); |
| 91 | - this.updateLooper = setInterval(this.initData, 10000); | |
| 79 | + // this.updateLooper = setInterval(this.initData, 10000); | |
| 92 | 80 | }, |
| 93 | 81 | destroyed() { |
| 94 | 82 | this.$destroy('videojs'); |
| ... | ... | @@ -96,20 +84,20 @@ |
| 96 | 84 | }, |
| 97 | 85 | methods: { |
| 98 | 86 | initData: function() { |
| 99 | - this.getDeviceList(); | |
| 87 | + this.getPushList(); | |
| 100 | 88 | }, |
| 101 | 89 | currentChange: function(val){ |
| 102 | 90 | this.currentPage = val; |
| 103 | - this.getDeviceList(); | |
| 91 | + this.getPushList(); | |
| 104 | 92 | }, |
| 105 | 93 | handleSizeChange: function(val){ |
| 106 | 94 | this.count = val; |
| 107 | - this.getDeviceList(); | |
| 95 | + this.getPushList(); | |
| 108 | 96 | }, |
| 109 | - getDeviceList: function() { | |
| 97 | + getPushList: function() { | |
| 110 | 98 | let that = this; |
| 111 | 99 | this.getDeviceListLoading = true; |
| 112 | - this.$axios.get(`/api/devices`,{ | |
| 100 | + this.$axios.get(`/api/media/list`,{ | |
| 113 | 101 | params: { |
| 114 | 102 | page: that.currentPage, |
| 115 | 103 | count: that.count |
| ... | ... | @@ -119,83 +107,44 @@ |
| 119 | 107 | console.log(res); |
| 120 | 108 | console.log(res.data.list); |
| 121 | 109 | that.total = res.data.total; |
| 122 | - that.deviceList = res.data.list; | |
| 110 | + that.pushList = res.data.list; | |
| 123 | 111 | that.getDeviceListLoading = false; |
| 124 | 112 | }) |
| 125 | 113 | .catch(function (error) { |
| 126 | 114 | console.log(error); |
| 127 | 115 | that.getDeviceListLoading = false; |
| 128 | 116 | }); |
| 129 | - | |
| 130 | 117 | }, |
| 131 | - showChannelList: function(row) { | |
| 132 | - console.log(JSON.stringify(row)) | |
| 133 | - this.$router.push(`/channelList/${row.deviceId}/0/15/1`); | |
| 118 | + addStreamProxy: function(){ | |
| 119 | + console.log(2222) | |
| 120 | + this.$refs.streamProxyEdit.openDialog(null, this.initData) | |
| 134 | 121 | }, |
| 135 | - showDevicePosition: function(row) { | |
| 136 | - console.log(JSON.stringify(row)) | |
| 137 | - this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`); | |
| 122 | + saveStreamProxy: function(){ | |
| 138 | 123 | }, |
| 139 | - | |
| 140 | - //gb28181平台对接 | |
| 141 | - //刷新设备信息 | |
| 142 | - refDevice: function(itemData) { | |
| 143 | - ///api/devices/{deviceId}/sync | |
| 144 | - console.log("刷新对应设备:" + itemData.deviceId); | |
| 145 | - var that = this; | |
| 146 | - that.$refs[itemData.deviceId + 'refbtn' ].loading = true; | |
| 147 | - this.$axios({ | |
| 148 | - method: 'post', | |
| 149 | - url: '/api/devices/' + itemData.deviceId + '/sync' | |
| 150 | - }).then(function(res) { | |
| 151 | - console.log("刷新设备结果:"+JSON.stringify(res)); | |
| 152 | - if (!res.data.deviceId) { | |
| 153 | - that.$message({ | |
| 154 | - showClose: true, | |
| 155 | - message: res.data, | |
| 156 | - type: 'error' | |
| 157 | - }); | |
| 158 | - }else{ | |
| 159 | - that.$message({ | |
| 160 | - showClose: true, | |
| 161 | - message: '请求成功', | |
| 162 | - type: 'success' | |
| 163 | - }); | |
| 124 | + playPuhsh: function(row){ | |
| 125 | + let that = this; | |
| 126 | + this.getListLoading = true; | |
| 127 | + this.$axios.get(`/api/media/getStreamInfoByAppAndStream`,{ | |
| 128 | + params: { | |
| 129 | + app: row.app, | |
| 130 | + stream: row.stream | |
| 164 | 131 | } |
| 165 | - that.initData() | |
| 166 | - that.$refs[itemData.deviceId + 'refbtn' ].loading = false; | |
| 167 | - }).catch(function(e) { | |
| 168 | - console.error(e) | |
| 169 | - that.$refs[itemData.deviceId + 'refbtn' ].loading = false; | |
| 170 | - });; | |
| 171 | - }, | |
| 172 | - //通知设备上传媒体流 | |
| 173 | - sendDevicePush: function(itemData) { | |
| 174 | - // let deviceId = this.currentDevice.deviceId; | |
| 175 | - // let channelId = itemData.channelId; | |
| 176 | - // console.log("通知设备推流1:" + deviceId + " : " + channelId); | |
| 177 | - // let that = this; | |
| 178 | - // this.$axios({ | |
| 179 | - // method: 'get', | |
| 180 | - // url: '/api/play/' + deviceId + '/' + channelId | |
| 181 | - // }).then(function(res) { | |
| 182 | - // let ssrc = res.data.ssrc; | |
| 183 | - // that.$refs.devicePlayer.play(ssrc,deviceId,channelId); | |
| 184 | - // }).catch(function(e) { | |
| 185 | - // }); | |
| 132 | + }) | |
| 133 | + .then(function (res) { | |
| 134 | + that.getListLoading = false; | |
| 135 | + that.$refs.devicePlayer.openDialog("streamPlay", null, null, { | |
| 136 | + streamInfo: res.data, | |
| 137 | + hasAudio: true | |
| 138 | + }); | |
| 139 | + }) | |
| 140 | + .catch(function (error) { | |
| 141 | + console.log(error); | |
| 142 | + that.getListLoading = false; | |
| 143 | + }); | |
| 186 | 144 | }, |
| 187 | - transportChange: function (row) { | |
| 188 | - console.log(row); | |
| 189 | - console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `); | |
| 190 | - let that = this; | |
| 191 | - this.$axios({ | |
| 192 | - method: 'get', | |
| 193 | - url: '/api/devices/' + row.deviceId + '/transport/' + row.streamMode | |
| 194 | - }).then(function(res) { | |
| 195 | - | |
| 196 | - }).catch(function(e) { | |
| 197 | - }); | |
| 198 | - } | |
| 145 | + stopPuhsh: function(row){ | |
| 146 | + console.log(row) | |
| 147 | + } | |
| 199 | 148 | |
| 200 | 149 | } |
| 201 | 150 | }; | ... | ... |
web_src/src/components/StreamProxyList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div id="streamProxyList"> | |
| 3 | + <el-container> | |
| 4 | + <el-header> | |
| 5 | + <uiHeader></uiHeader> | |
| 6 | + </el-header> | |
| 7 | + <el-main> | |
| 8 | + <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> | |
| 9 | + <span style="font-size: 1rem; font-weight: bold;">拉流代理列表</span> | |
| 10 | + </div> | |
| 11 | + <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> | |
| 12 | + <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStreamProxy">添加代理</el-button> | |
| 13 | + </div> | |
| 14 | + <devicePlayer ref="devicePlayer"></devicePlayer> | |
| 15 | + <el-table :data="streamProxyList" border style="width: 100%" :height="winHeight"> | |
| 16 | + <el-table-column prop="app" label="应用名" align="center" show-overflow-tooltip/> | |
| 17 | + <el-table-column prop="stream" label="流ID" align="center" show-overflow-tooltip/> | |
| 18 | + <el-table-column label="流地址" width="400" align="center" show-overflow-tooltip > | |
| 19 | + <template slot-scope="scope"> | |
| 20 | + <div slot="reference" class="name-wrapper"> | |
| 21 | + | |
| 22 | + <el-tag size="medium" v-if="scope.row.type == 'default'"> | |
| 23 | + <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.url" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i> | |
| 24 | + {{scope.row.url}} | |
| 25 | + </el-tag> | |
| 26 | + <el-tag size="medium" v-if="scope.row.type != 'default'"> | |
| 27 | + <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.src_url" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i> | |
| 28 | + {{scope.row.src_url}} | |
| 29 | + </el-tag> | |
| 30 | + </div> | |
| 31 | + </template> | |
| 32 | + </el-table-column> | |
| 33 | + | |
| 34 | + <el-table-column label="转HLS" width="120" align="center"> | |
| 35 | + <template slot-scope="scope"> | |
| 36 | + <div slot="reference" class="name-wrapper"> | |
| 37 | + <el-tag size="medium" v-if="scope.row.enable_hls">已启用</el-tag> | |
| 38 | + <el-tag size="medium" type="info" v-if="!scope.row.enable_hls">未启用</el-tag> | |
| 39 | + </div> | |
| 40 | + </template> | |
| 41 | + </el-table-column> | |
| 42 | + <el-table-column label="MP4录制" width="120" align="center"> | |
| 43 | + <template slot-scope="scope"> | |
| 44 | + <div slot="reference" class="name-wrapper"> | |
| 45 | + <el-tag size="medium" v-if="scope.row.enable_mp4">已启用</el-tag> | |
| 46 | + <el-tag size="medium" type="info" v-if="!scope.row.enable_mp4">未启用</el-tag> | |
| 47 | + </div> | |
| 48 | + </template> | |
| 49 | + </el-table-column> | |
| 50 | + <el-table-column label="启用" width="120" align="center"> | |
| 51 | + <template slot-scope="scope"> | |
| 52 | + <div slot="reference" class="name-wrapper"> | |
| 53 | + <el-tag size="medium" v-if="scope.row.enable">已启用</el-tag> | |
| 54 | + <el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag> | |
| 55 | + </div> | |
| 56 | + </template> | |
| 57 | + </el-table-column> | |
| 58 | + | |
| 59 | + | |
| 60 | + <el-table-column label="操作" width="360" align="center" fixed="right"> | |
| 61 | + <template slot-scope="scope"> | |
| 62 | + <el-button-group> | |
| 63 | + <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.enable" @click="play(scope.row)">播放</el-button> | |
| 64 | + <el-button size="mini" icon="el-icon-close" type="success" v-if="scope.row.enable" @click="stop(scope.row)">停用</el-button> | |
| 65 | + <el-button size="mini" icon="el-icon-check" type="primary" v-if="!scope.row.enable" @click="start(scope.row)">启用</el-button> | |
| 66 | + <el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteStreamProxy(scope.row)">删除</el-button> | |
| 67 | + </el-button-group> | |
| 68 | + </template> | |
| 69 | + </el-table-column> | |
| 70 | + </el-table> | |
| 71 | + <el-pagination | |
| 72 | + style="float: right" | |
| 73 | + @size-change="handleSizeChange" | |
| 74 | + @current-change="currentChange" | |
| 75 | + :current-page="currentPage" | |
| 76 | + :page-size="count" | |
| 77 | + :page-sizes="[15, 25, 35, 50]" | |
| 78 | + layout="total, sizes, prev, pager, next" | |
| 79 | + :total="total"> | |
| 80 | + </el-pagination> | |
| 81 | + <streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit> | |
| 82 | + </el-main> | |
| 83 | + </el-container> | |
| 84 | + </div> | |
| 85 | +</template> | |
| 86 | + | |
| 87 | +<script> | |
| 88 | + import streamProxyEdit from './dialog/StreamProxyEdit.vue' | |
| 89 | + import devicePlayer from './dialog/devicePlayer.vue' | |
| 90 | + import uiHeader from './UiHeader.vue' | |
| 91 | + export default { | |
| 92 | + name: 'streamProxyList', | |
| 93 | + components: { | |
| 94 | + devicePlayer, | |
| 95 | + streamProxyEdit, | |
| 96 | + uiHeader | |
| 97 | + }, | |
| 98 | + data() { | |
| 99 | + return { | |
| 100 | + streamProxyList: [], | |
| 101 | + currentPusher: {}, //当前操作设备对象 | |
| 102 | + updateLooper: 0, //数据刷新轮训标志 | |
| 103 | + currentDeviceChannelsLenth:0, | |
| 104 | + winHeight: window.innerHeight - 200, | |
| 105 | + currentPage:1, | |
| 106 | + count:15, | |
| 107 | + total:0, | |
| 108 | + getListLoading: false | |
| 109 | + }; | |
| 110 | + }, | |
| 111 | + computed: { | |
| 112 | + }, | |
| 113 | + mounted() { | |
| 114 | + this.initData(); | |
| 115 | + // this.updateLooper = setInterval(this.initData, 10000); | |
| 116 | + }, | |
| 117 | + destroyed() { | |
| 118 | + this.$destroy('videojs'); | |
| 119 | + clearTimeout(this.updateLooper); | |
| 120 | + }, | |
| 121 | + methods: { | |
| 122 | + initData: function() { | |
| 123 | + this.getStreamProxyList(); | |
| 124 | + }, | |
| 125 | + currentChange: function(val){ | |
| 126 | + this.currentPage = val; | |
| 127 | + this.getStreamProxyList(); | |
| 128 | + }, | |
| 129 | + handleSizeChange: function(val){ | |
| 130 | + this.count = val; | |
| 131 | + this.getStreamProxyList(); | |
| 132 | + }, | |
| 133 | + getStreamProxyList: function() { | |
| 134 | + let that = this; | |
| 135 | + this.getListLoading = true; | |
| 136 | + this.$axios.get(`/api/proxy/list`,{ | |
| 137 | + params: { | |
| 138 | + page: that.currentPage, | |
| 139 | + count: that.count | |
| 140 | + } | |
| 141 | + } ) | |
| 142 | + .then(function (res) { | |
| 143 | + console.log(res); | |
| 144 | + console.log(res.data.list); | |
| 145 | + that.total = res.data.total; | |
| 146 | + that.streamProxyList = res.data.list; | |
| 147 | + that.getListLoading = false; | |
| 148 | + }) | |
| 149 | + .catch(function (error) { | |
| 150 | + console.log(error); | |
| 151 | + that.getListLoading = false; | |
| 152 | + }); | |
| 153 | + }, | |
| 154 | + addStreamProxy: function(){ | |
| 155 | + this.$refs.streamProxyEdit.openDialog(null, this.initData) | |
| 156 | + }, | |
| 157 | + saveStreamProxy: function(){ | |
| 158 | + }, | |
| 159 | + play: function(row){ | |
| 160 | + let that = this; | |
| 161 | + this.getListLoading = true; | |
| 162 | + this.$axios.get(`/api/media/getStreamInfoByAppAndStream`,{ | |
| 163 | + params: { | |
| 164 | + app: row.app, | |
| 165 | + stream: row.stream | |
| 166 | + } | |
| 167 | + }) | |
| 168 | + .then(function (res) { | |
| 169 | + that.getListLoading = false; | |
| 170 | + that.$refs.devicePlayer.openDialog("streamPlay", null, null, { | |
| 171 | + streamInfo: res.data, | |
| 172 | + hasAudio: true | |
| 173 | + }); | |
| 174 | + }) | |
| 175 | + .catch(function (error) { | |
| 176 | + console.log(error); | |
| 177 | + that.getListLoading = false; | |
| 178 | + }); | |
| 179 | + | |
| 180 | + }, | |
| 181 | + deleteStreamProxy: function(row){ | |
| 182 | + console.log(1111) | |
| 183 | + let that = this; | |
| 184 | + this.getListLoading = true; | |
| 185 | + this.$axios.get(`/api/proxy/del`,{ | |
| 186 | + params: { | |
| 187 | + app: row.app, | |
| 188 | + stream: row.stream | |
| 189 | + } | |
| 190 | + }) | |
| 191 | + .then(function (res) { | |
| 192 | + that.getListLoading = false; | |
| 193 | + that.initData() | |
| 194 | + }) | |
| 195 | + .catch(function (error) { | |
| 196 | + console.log(error); | |
| 197 | + that.getListLoading = false; | |
| 198 | + }); | |
| 199 | + }, | |
| 200 | + start: function(row){ | |
| 201 | + let that = this; | |
| 202 | + this.getListLoading = true; | |
| 203 | + this.$axios.get(`/api/proxy/start`,{ | |
| 204 | + params: { | |
| 205 | + app: row.app, | |
| 206 | + stream: row.stream | |
| 207 | + } | |
| 208 | + }) | |
| 209 | + .then(function (res) { | |
| 210 | + that.getListLoading = false; | |
| 211 | + that.initData() | |
| 212 | + }) | |
| 213 | + .catch(function (error) { | |
| 214 | + console.log(error); | |
| 215 | + that.getListLoading = false; | |
| 216 | + }); | |
| 217 | + }, | |
| 218 | + stop: function(row){ | |
| 219 | + let that = this; | |
| 220 | + this.getListLoading = true; | |
| 221 | + this.$axios.get(`/api/proxy/stop`,{ | |
| 222 | + params: { | |
| 223 | + app: row.app, | |
| 224 | + stream: row.stream | |
| 225 | + } | |
| 226 | + }) | |
| 227 | + .then(function (res) { | |
| 228 | + that.getListLoading = false; | |
| 229 | + that.initData() | |
| 230 | + }) | |
| 231 | + .catch(function (error) { | |
| 232 | + console.log(error); | |
| 233 | + that.getListLoading = false; | |
| 234 | + }); | |
| 235 | + } | |
| 236 | + | |
| 237 | + } | |
| 238 | + }; | |
| 239 | +</script> | |
| 240 | + | |
| 241 | +<style> | |
| 242 | + .videoList { | |
| 243 | + display: flex; | |
| 244 | + flex-wrap: wrap; | |
| 245 | + align-content: flex-start; | |
| 246 | + } | |
| 247 | + | |
| 248 | + .video-item { | |
| 249 | + position: relative; | |
| 250 | + width: 15rem; | |
| 251 | + height: 10rem; | |
| 252 | + margin-right: 1rem; | |
| 253 | + background-color: #000000; | |
| 254 | + } | |
| 255 | + | |
| 256 | + .video-item-img { | |
| 257 | + position: absolute; | |
| 258 | + top: 0; | |
| 259 | + bottom: 0; | |
| 260 | + left: 0; | |
| 261 | + right: 0; | |
| 262 | + margin: auto; | |
| 263 | + width: 100%; | |
| 264 | + height: 100%; | |
| 265 | + } | |
| 266 | + | |
| 267 | + .video-item-img:after { | |
| 268 | + content: ""; | |
| 269 | + display: inline-block; | |
| 270 | + position: absolute; | |
| 271 | + z-index: 2; | |
| 272 | + top: 0; | |
| 273 | + bottom: 0; | |
| 274 | + left: 0; | |
| 275 | + right: 0; | |
| 276 | + margin: auto; | |
| 277 | + width: 3rem; | |
| 278 | + height: 3rem; | |
| 279 | + background-image: url("../assets/loading.png"); | |
| 280 | + background-size: cover; | |
| 281 | + background-color: #000000; | |
| 282 | + } | |
| 283 | + | |
| 284 | + .video-item-title { | |
| 285 | + position: absolute; | |
| 286 | + bottom: 0; | |
| 287 | + color: #000000; | |
| 288 | + background-color: #ffffff; | |
| 289 | + line-height: 1.5rem; | |
| 290 | + padding: 0.3rem; | |
| 291 | + width: 14.4rem; | |
| 292 | + } | |
| 293 | + .cpoy-btn { | |
| 294 | + cursor: pointer; | |
| 295 | + margin-right: 10px; | |
| 296 | + } | |
| 297 | +</style> | ... | ... |
web_src/src/components/UiHeader.vue
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | <el-menu-item index="/">控制台</el-menu-item> |
| 5 | 5 | <el-menu-item index="/deviceList">设备列表</el-menu-item> |
| 6 | 6 | <el-menu-item index="/pushVideoList">推流列表</el-menu-item> |
| 7 | + <el-menu-item index="/streamProxyList">拉流代理</el-menu-item> | |
| 7 | 8 | <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> |
| 8 | 9 | <el-switch v-model="alarmNotify" active-text="报警信息推送" style="display: block float: right" @change="sseControl"></el-switch> |
| 9 | 10 | <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item> | ... | ... |
web_src/src/components/channelList.vue
web_src/src/components/dialog/StreamProxyEdit.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div id="addStreamProxy" v-loading="isLoging"> | |
| 3 | + <el-dialog | |
| 4 | + title="添加代理" | |
| 5 | + width="40%" | |
| 6 | + top="2rem" | |
| 7 | + :close-on-click-modal="false" | |
| 8 | + :visible.sync="showDialog" | |
| 9 | + :destroy-on-close="true" | |
| 10 | + @close="close()" | |
| 11 | + > | |
| 12 | + <div id="shared" style="margin-top: 1rem;margin-right: 100px;"> | |
| 13 | + <el-form ref="streamProxy" :rules="rules" :model="proxyParam" label-width="140px"> | |
| 14 | + <el-form-item label="类型" prop="type"> | |
| 15 | + <el-select | |
| 16 | + v-model="proxyParam.type" | |
| 17 | + style="width: 100%" | |
| 18 | + placeholder="请选择代理类型" | |
| 19 | + > | |
| 20 | + <el-option label="默认" value="default"></el-option> | |
| 21 | + <el-option label="FFmpeg" value="ffmpeg"></el-option> | |
| 22 | + </el-select> | |
| 23 | + </el-form-item> | |
| 24 | + <el-form-item label="应用名" prop="app"> | |
| 25 | + <el-input v-model="proxyParam.app" clearable></el-input> | |
| 26 | + </el-form-item> | |
| 27 | + <el-form-item label="流ID" prop="stream"> | |
| 28 | + <el-input v-model="proxyParam.stream" clearable></el-input> | |
| 29 | + </el-form-item> | |
| 30 | + <el-form-item label="拉流地址" prop="url" v-if="proxyParam.type=='default'"> | |
| 31 | + <el-input v-model="proxyParam.url" clearable></el-input> | |
| 32 | + </el-form-item> | |
| 33 | + <el-form-item label="拉流地址" prop="src_url" v-if="proxyParam.type=='ffmpeg'"> | |
| 34 | + <el-input v-model="proxyParam.src_url" clearable></el-input> | |
| 35 | + </el-form-item> | |
| 36 | + <el-form-item label="超时时间" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'"> | |
| 37 | + <el-input v-model="proxyParam.timeout_ms" clearable></el-input> | |
| 38 | + </el-form-item> | |
| 39 | + <el-form-item label="FFmpeg命令模板" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'"> | |
| 40 | + <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input> | |
| 41 | + </el-form-item> | |
| 42 | + <el-form-item label="拉流方式" prop="rtp_type" v-if="proxyParam.type=='default'"> | |
| 43 | + <el-select | |
| 44 | + v-model="proxyParam.rtp_type" | |
| 45 | + style="width: 100%" | |
| 46 | + placeholder="请选择拉流方式" | |
| 47 | + > | |
| 48 | + <el-option label="TCP" value="0"></el-option> | |
| 49 | + <el-option label="UDP" value="1"></el-option> | |
| 50 | + <el-option label="组播" value="2"></el-option> | |
| 51 | + </el-select> | |
| 52 | + </el-form-item> | |
| 53 | + <el-form-item label="其他选项"> | |
| 54 | + <div style="float: left;"> | |
| 55 | + <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox> | |
| 56 | + <el-checkbox label="转HLS" v-model="proxyParam.enable_hls" ></el-checkbox> | |
| 57 | + <el-checkbox label="MP4录制" v-model="proxyParam.enable_mp4" ></el-checkbox> | |
| 58 | + </div> | |
| 59 | + | |
| 60 | + </el-form-item> | |
| 61 | + <el-form-item> | |
| 62 | + <div style="float: right;"> | |
| 63 | + <el-button type="primary" @click="onSubmit">{{onSubmit_text}}</el-button> | |
| 64 | + <el-button @click="close">取消</el-button> | |
| 65 | + </div> | |
| 66 | + | |
| 67 | + </el-form-item> | |
| 68 | + </el-form> | |
| 69 | + </div> | |
| 70 | + </el-dialog> | |
| 71 | + </div> | |
| 72 | +</template> | |
| 73 | + | |
| 74 | +<script> | |
| 75 | +export default { | |
| 76 | + name: "streamProxyEdit", | |
| 77 | + props: {}, | |
| 78 | + computed: {}, | |
| 79 | + created() {}, | |
| 80 | + data() { | |
| 81 | + // var deviceGBIdRules = async (rule, value, callback) => { | |
| 82 | + // console.log(value); | |
| 83 | + // if (value === "") { | |
| 84 | + // callback(new Error("请输入设备国标编号")); | |
| 85 | + // } else { | |
| 86 | + // var exit = await this.deviceGBIdExit(value); | |
| 87 | + // console.log(exit); | |
| 88 | + // console.log(exit == "true"); | |
| 89 | + // console.log(exit === "true"); | |
| 90 | + // if (exit) { | |
| 91 | + // callback(new Error("设备国标编号已存在")); | |
| 92 | + // } else { | |
| 93 | + // callback(); | |
| 94 | + // } | |
| 95 | + // } | |
| 96 | + // }; | |
| 97 | + return { | |
| 98 | + listChangeCallback: null, | |
| 99 | + showDialog: false, | |
| 100 | + isLoging: false, | |
| 101 | + onSubmit_text: "立即创建", | |
| 102 | + proxyParam: { | |
| 103 | + type: "default", | |
| 104 | + app: null, | |
| 105 | + stream: null, | |
| 106 | + url: "rtmp://58.200.131.2:1935/livetv/hunantv", | |
| 107 | + src_url: null, | |
| 108 | + timeout_ms: null, | |
| 109 | + ffmpeg_cmd_key: null, | |
| 110 | + rtp_type: null, | |
| 111 | + enable: true, | |
| 112 | + enable_hls: true, | |
| 113 | + enable_mp4: false, | |
| 114 | + }, | |
| 115 | + | |
| 116 | + rules: { | |
| 117 | + app: [{ required: true, message: "请输入应用名", trigger: "blur" }], | |
| 118 | + stream: [{ required: true, message: "请输入流ID", trigger: "blur" }], | |
| 119 | + url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }], | |
| 120 | + src_url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }], | |
| 121 | + timeout_ms: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }], | |
| 122 | + ffmpeg_cmd_key: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }], | |
| 123 | + }, | |
| 124 | + }; | |
| 125 | + }, | |
| 126 | + methods: { | |
| 127 | + openDialog: function (proxyParam, callback) { | |
| 128 | + this.showDialog = true; | |
| 129 | + this.listChangeCallback = callback; | |
| 130 | + if (proxyParam != null) { | |
| 131 | + this.proxyParam = proxyParam; | |
| 132 | + this.onSubmit_text = "保存"; | |
| 133 | + } else { | |
| 134 | + this.onSubmit_text = "立即创建"; | |
| 135 | + } | |
| 136 | + }, | |
| 137 | + onSubmit: function () { | |
| 138 | + console.log("onSubmit"); | |
| 139 | + var that = this; | |
| 140 | + that.$axios | |
| 141 | + .post(`/api/proxy/save`, that.proxyParam) | |
| 142 | + .then(function (res) { | |
| 143 | + console.log(res); | |
| 144 | + console.log(res.data == "success"); | |
| 145 | + if (res.data == "success") { | |
| 146 | + that.$message({ | |
| 147 | + showClose: true, | |
| 148 | + message: "保存成功", | |
| 149 | + type: "success", | |
| 150 | + }); | |
| 151 | + that.showDialog = false; | |
| 152 | + if (that.listChangeCallback != null) { | |
| 153 | + that.listChangeCallback(); | |
| 154 | + } | |
| 155 | + } | |
| 156 | + }) | |
| 157 | + .catch(function (error) { | |
| 158 | + console.log(error); | |
| 159 | + }); | |
| 160 | + }, | |
| 161 | + close: function () { | |
| 162 | + console.log("关闭添加视频平台"); | |
| 163 | + this.showDialog = false; | |
| 164 | + this.$refs.streamProxy.resetFields(); | |
| 165 | + }, | |
| 166 | + deviceGBIdExit: async function (deviceGbId) { | |
| 167 | + var result = false; | |
| 168 | + var that = this; | |
| 169 | + await that.$axios | |
| 170 | + .post(`/api/platforms/exit/${deviceGbId}`) | |
| 171 | + .then(function (res) { | |
| 172 | + result = res.data; | |
| 173 | + }) | |
| 174 | + .catch(function (error) { | |
| 175 | + console.log(error); | |
| 176 | + }); | |
| 177 | + return result; | |
| 178 | + }, | |
| 179 | + checkExpires: function() { | |
| 180 | + if (this.platform.enable && this.platform.expires == "0") { | |
| 181 | + this.platform.expires = "300"; | |
| 182 | + } | |
| 183 | + } | |
| 184 | + }, | |
| 185 | +}; | |
| 186 | +</script> | ... | ... |
web_src/src/components/gb28181/chooseChannel.vue renamed to web_src/src/components/dialog/chooseChannel.vue
web_src/src/components/gb28181/chooseChannelForGb.vue renamed to web_src/src/components/dialog/chooseChannelForGb.vue
web_src/src/components/gb28181/devicePlayer.vue renamed to web_src/src/components/dialog/devicePlayer.vue
| ... | ... | @@ -26,7 +26,7 @@ |
| 26 | 26 | </div> |
| 27 | 27 | </el-tab-pane> |
| 28 | 28 | <!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}--> |
| 29 | - <el-tab-pane label="录像查询" name="record"> | |
| 29 | + <el-tab-pane label="录像查询" name="record" v-if="showRrecord"> | |
| 30 | 30 | <el-date-picker size="mini" v-model="videoHistory.date" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="queryRecords()"></el-date-picker> |
| 31 | 31 | <el-table :data="videoHistory.searchHistoryResult" height="150" v-loading="recordsLoading"> |
| 32 | 32 | <el-table-column label="名称" prop="name"></el-table-column> |
| ... | ... | @@ -42,7 +42,7 @@ |
| 42 | 42 | </el-table> |
| 43 | 43 | </el-tab-pane> |
| 44 | 44 | <!--遥控界面--> |
| 45 | - <el-tab-pane label="云台控制" name="control"> | |
| 45 | + <el-tab-pane label="云台控制" name="control" v-if="showPtz"> | |
| 46 | 46 | <div style="display: flex; justify-content: left;"> |
| 47 | 47 | <div class="control-wrapper"> |
| 48 | 48 | <div class="control-btn control-top" @mousedown="ptzCamera(0, 2, 0)" @mouseup="ptzCamera(0, 0, 0)"> |
| ... | ... | @@ -136,7 +136,7 @@ |
| 136 | 136 | </template> |
| 137 | 137 | |
| 138 | 138 | <script> |
| 139 | -import player from './player.vue' | |
| 139 | +import player from '../dialog/player.vue' | |
| 140 | 140 | export default { |
| 141 | 141 | name: 'devicePlayer', |
| 142 | 142 | props: {}, |
| ... | ... | @@ -184,7 +184,9 @@ export default { |
| 184 | 184 | tracks: [], |
| 185 | 185 | coverPlaying:false, |
| 186 | 186 | tracksLoading: false, |
| 187 | - recordPlay: "" | |
| 187 | + recordPlay: "", | |
| 188 | + showPtz: true, | |
| 189 | + showRrecord: true, | |
| 188 | 190 | }; |
| 189 | 191 | }, |
| 190 | 192 | methods: { |
| ... | ... | @@ -230,6 +232,11 @@ export default { |
| 230 | 232 | this.videoHistory.date = param.date; |
| 231 | 233 | this.queryRecords() |
| 232 | 234 | break; |
| 235 | + case "streamPlay": | |
| 236 | + this.showRrecord = false, | |
| 237 | + this.showPtz = false, | |
| 238 | + this.play(param.streamInfo, param.hasAudio) | |
| 239 | + break; | |
| 233 | 240 | case "control": |
| 234 | 241 | break; |
| 235 | 242 | } | ... | ... |
web_src/src/components/platformEdit.vue renamed to web_src/src/components/dialog/platformEdit.vue
web_src/src/components/gb28181/player.vue renamed to web_src/src/components/dialog/player.vue
web_src/src/main.js
| ... | ... | @@ -11,6 +11,8 @@ import echarts from 'echarts'; |
| 11 | 11 | import VueClipboard from 'vue-clipboard2'; |
| 12 | 12 | import { Notification } from 'element-ui'; |
| 13 | 13 | import Fingerprint2 from 'fingerprintjs2'; |
| 14 | +import VueClipboards from 'vue-clipboards'; | |
| 15 | + | |
| 14 | 16 | |
| 15 | 17 | // 生成唯一ID |
| 16 | 18 | Fingerprint2.get(function(components) { |
| ... | ... | @@ -32,6 +34,7 @@ Fingerprint2.get(function(components) { |
| 32 | 34 | Vue.use(VueClipboard); |
| 33 | 35 | Vue.use(ElementUI); |
| 34 | 36 | Vue.use(VueCookies); |
| 37 | +Vue.use(VueClipboards); | |
| 35 | 38 | Vue.prototype.$axios = axios; |
| 36 | 39 | Vue.prototype.$notify = Notification; |
| 37 | 40 | ... | ... |
web_src/src/router/index.js
| ... | ... | @@ -5,6 +5,7 @@ import control from '../components/control.vue' |
| 5 | 5 | import deviceList from '../components/DeviceList.vue' |
| 6 | 6 | import channelList from '../components/channelList.vue' |
| 7 | 7 | import pushVideoList from '../components/PushVideoList.vue' |
| 8 | +import streamProxyList from '../components/StreamProxyList.vue' | |
| 8 | 9 | import devicePosition from '../components/devicePosition.vue' |
| 9 | 10 | import login from '../components/Login.vue' |
| 10 | 11 | import parentPlatformList from '../components/ParentPlatformList.vue' |
| ... | ... | @@ -33,6 +34,10 @@ export default new VueRouter({ |
| 33 | 34 | component: pushVideoList, |
| 34 | 35 | }, |
| 35 | 36 | { |
| 37 | + path: '/streamProxyList', | |
| 38 | + component: streamProxyList, | |
| 39 | + }, | |
| 40 | + { | |
| 36 | 41 | path: '/login', |
| 37 | 42 | name: '登录', |
| 38 | 43 | component: login, | ... | ... |