From 7d9cc96ef54399795deb5b7fc7682e6323dc1202 Mon Sep 17 00:00:00 2001 From: 648540858 <456panlinlin> Date: 星期五, 25 三月 2022 16:05:14 +0800 Subject: [PATCH] 优化国标录像下载,添加进度条以及自动合并文件下载,需要结合新版assist服务使用。 --- src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java | 24 src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java | 28 + src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java | 139 ++++++++ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java | 1 web_src/package-lock.json | 6 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java | 4 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java | 1 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java | 38 ++ web_src/src/components/dialog/devicePlayer.vue | 53 ++- src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java | 2 web_src/build/webpack.dev.conf.js | 1 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java | 11 src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java | 2 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java | 6 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java | 1 web_src/config/index.js | 4 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java | 142 ++++++++ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java | 7 /dev/null | 190 ----------- src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java | 9 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java | 11 web_src/src/components/dialog/recordDownload.vue | 195 +++++++++++ web_src/src/router/index.js | 6 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java | 121 +++++++ src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java | 2 25 files changed, 761 insertions(+), 243 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java index 0626384..4e4ba15 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java @@ -31,6 +31,9 @@ private String rtc; private String mediaServerId; private Object tracks; + private String startTime; + private String endTime; + private double progress; public static class TransactionInfo{ public String callId; @@ -264,4 +267,29 @@ public void setHttps_ts(String https_ts) { this.https_ts = https_ts; } + + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public double getProgress() { + return progress; + } + + public void setProgress(double progress) { + this.progress = progress; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java index c2dedec..87d2635 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java @@ -1,5 +1,7 @@ package com.genersoft.iot.vmp.gb28181.bean; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; + public class SsrcTransaction { private String deviceId; @@ -10,6 +12,7 @@ private byte[] dialog; private String mediaServerId; private String ssrc; + private VideoStreamSessionManager.SessionType type; public String getDeviceId() { return deviceId; @@ -74,4 +77,12 @@ public void setSsrc(String ssrc) { this.ssrc = ssrc; } + + public VideoStreamSessionManager.SessionType getType() { + return type; + } + + public void setType(VideoStreamSessionManager.SessionType type) { + this.type = type; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java index d511f42..50957f6 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java @@ -156,8 +156,6 @@ List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId); if (parentPlatforms != null && parentPlatforms.size() > 0) { for (ParentPlatform platform : parentPlatforms) { -// String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platform.getServerGBId(); -// SubscribeInfo subscribeInfo = redisCatchStorage.getSubscribe(key); SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(event.getPlatformId()); if (subscribeInfo == null) continue; logger.info("[Catalog浜嬩欢: {}]骞冲彴锛歿}锛屽奖鍝嶉�氶亾{}", event.getType(), platform.getServerGBId(), gbId); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index ba8f24c..6eed17e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -30,6 +30,12 @@ @Autowired private UserSetup userSetup; + public enum SessionType { + play, + playback, + download + } + /** * 娣诲姞涓�涓偣鎾�/鍥炴斁鐨勪簨鍔′俊鎭� * 鍚庣画鍙互閫氳繃娴両d/callID @@ -40,7 +46,7 @@ * @param mediaServerId 鎵�浣跨敤鐨勬祦濯掍綋ID * @param transaction 浜嬪姟 */ - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction){ + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction, SessionType type){ SsrcTransaction ssrcTransaction = new SsrcTransaction(); ssrcTransaction.setDeviceId(deviceId); ssrcTransaction.setChannelId(channelId); @@ -50,6 +56,7 @@ ssrcTransaction.setCallId(callId); ssrcTransaction.setSsrc(ssrc); ssrcTransaction.setMediaServerId(mediaServerId); + ssrcTransaction.setType(type); redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index 409eedb..9cd89e0 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -115,7 +115,9 @@ * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss * @param downloadSpeed 涓嬭浇鍊嶉�熷弬鏁� */ - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event, SipSubscribe.Event errorEvent); + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, + SipSubscribe.Event errorEvent); /** * 瑙嗛娴佸仠姝� diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 48bffd7..0f2242c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -428,7 +428,7 @@ errorEvent.response(e); }), e ->{ // 杩欓噷涓轰緥閬垮厤涓�涓�氶亾鐨勭偣鎾彧鏈変竴涓猚allID杩欎釜鍙傛暟浣跨敤涓�涓浐瀹氬�� - streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction()); + streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play); streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog); }); @@ -537,7 +537,7 @@ transmitRequest(device, request, errorEvent, okEvent -> { ResponseEvent responseEvent = (ResponseEvent) okEvent.event; - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction()); + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback); streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog); }); if (inviteStreamCallback != null) { @@ -558,8 +558,9 @@ * @param downloadSpeed 涓嬭浇鍊嶉�熷弬鏁� */ @Override - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event - , SipSubscribe.Event errorEvent) { + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, + SipSubscribe.Event errorEvent) { try { logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); @@ -571,8 +572,6 @@ content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" " +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n"); - - String streamMode = device.getStreamMode().toUpperCase(); @@ -639,15 +638,20 @@ logger.debug("褰曞儚鍥炴斁娣诲姞璁㈤槄锛岃闃呭唴瀹癸細" + subscribeKey.toString()); subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ - event.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); + hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); }); Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc()); + if (inviteStreamCallback != null) { + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); + } + transmitRequest(device, request, errorEvent, okEvent->{ + ResponseEvent responseEvent = (ResponseEvent) okEvent.event; + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.download); + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog); + }); - ClientTransaction transaction = transmitRequest(device, request, errorEvent); - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction); - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction); } catch ( SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java index f21dfc0..9550266 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java @@ -104,6 +104,7 @@ DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); deviceChannel.setParental(0); deviceChannel.setParentId(channelReduce.getCatalogId()); + deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6)); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); // 闃叉鍙戦�佽繃蹇� Thread.sleep(100); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java index 8235ade..e36a705 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -62,7 +62,12 @@ if (NotifyType.equals("121")){ logger.info("濯掍綋鎾斁瀹屾瘯锛岄�氱煡鍏虫祦"); String channelId =getText(rootElement, "DeviceID"); - redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); +// redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); +// redisCatchStorage.stopDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); + StreamInfo streamInfo = redisCatchStorage.queryDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); + // 璁剧疆杩涘害100% + streamInfo.setProgress(1); + redisCatchStorage.startDownload(streamInfo, callIdHeader.getCallId()); cmder.streamByeCmd(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); // TODO 濡傛灉绾ц仈鎾斁锛岄渶瑕佺粰涓婄骇鍙戦�佹閫氱煡 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java index d8c7250..959432c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java @@ -107,6 +107,7 @@ DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); deviceChannel.setParental(0); deviceChannel.setParentId(channelReduce.getCatalogId()); + deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6)); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); // 闃叉鍙戦�佽繃蹇� Thread.sleep(100); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java new file mode 100644 index 0000000..249ec03 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java @@ -0,0 +1,139 @@ +package com.genersoft.iot.vmp.media.zlm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import okhttp3.*; +import okhttp3.logging.HttpLoggingInterceptor; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +@Component +public class AssistRESTfulUtils { + + private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class); + + public interface RequestCallback{ + void run(JSONObject response); + } + + private OkHttpClient getClient(){ + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); + if (logger.isDebugEnabled()) { + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> { + logger.debug("http璇锋眰鍙傛暟锛�" + message); + }); + logging.setLevel(HttpLoggingInterceptor.Level.BASIC); + // OkHttp閫茶娣诲姞鏀旀埅鍣╨oggingInterceptor + httpClientBuilder.addInterceptor(logging); + } + return httpClientBuilder.build(); + } + + + public JSONObject sendGet(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) { + OkHttpClient client = getClient(); + + if (mediaServerItem == null) { + return null; + } + if (StringUtils.isEmpty(mediaServerItem.getRecordAssistPort())) { + logger.warn("鏈惎鐢ˋssist鏈嶅姟"); + return null; + } + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append(String.format("http://%s:%s/%s", mediaServerItem.getIp(), mediaServerItem.getRecordAssistPort(), api)); + JSONObject responseJSON = null; + + if (param != null && param.keySet().size() > 0) { + stringBuffer.append("?"); + int index = 1; + for (String key : param.keySet()){ + if (param.get(key) != null) { + stringBuffer.append(key + "=" + param.get(key)); + if (index < param.size()) { + stringBuffer.append("&"); + } + } + index++; + } + } + + String url = stringBuffer.toString(); + Request request = new Request.Builder() + .get() + .url(url) + .build(); + if (callback == null) { + try { + Response response = client.newCall(request).execute(); + if (response.isSuccessful()) { + ResponseBody responseBody = response.body(); + if (responseBody != null) { + String responseStr = responseBody.string(); + responseJSON = JSON.parseObject(responseStr); + } + }else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + } catch (ConnectException e) { + logger.error(String.format("杩炴帴Assist澶辫触: %s, %s", e.getCause().getMessage(), e.getMessage())); + logger.info("璇锋鏌edia閰嶇疆骞剁‘璁ssist宸插惎鍔�..."); + }catch (IOException e) { + logger.error(String.format("[ %s ]璇锋眰澶辫触: %s", url, e.getMessage())); + } + }else { + client.newCall(request).enqueue(new Callback(){ + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response){ + if (response.isSuccessful()) { + try { + String responseStr = Objects.requireNonNull(response.body()).string(); + callback.run(JSON.parseObject(responseStr)); + } catch (IOException e) { + logger.error(String.format("[ %s ]璇锋眰澶辫触: %s", url, e.getMessage())); + } + + }else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + logger.error(String.format("杩炴帴Assist澶辫触: %s, %s", e.getCause().getMessage(), e.getMessage())); + logger.info("璇锋鏌edia閰嶇疆骞剁‘璁ssist宸插惎鍔�..."); + } + }); + } + + + + return responseJSON; + } + + + public JSONObject fileDuration(MediaServerItem mediaServerItem, String app, String stream, RequestCallback callback){ + Map<String, Object> param = new HashMap<>(); + param.put("app",app); + param.put("stream",stream); + param.put("recordIng",true); + return sendGet(mediaServerItem, "api/record/file/duration",param, callback); + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index bd39a0c..c3c30a6 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -215,7 +215,16 @@ if (deviceChannel != null) { ret.put("enable_audio", deviceChannel.isHasAudio()); } + // 濡傛灉鏄綍鍍忎笅杞藉氨璁剧疆瑙嗛闂撮殧鍗佺 + if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.download) { + ret.put("mp4_max_second", 10); + ret.put("enable_mp4", true); + ret.put("enable_audio", true); + } + } + + return new ResponseEntity<String>(ret.toString(), HttpStatus.OK); } @@ -324,7 +333,6 @@ if (mediaInfo != null) { subscribe.response(mediaInfo, json); } - } // 娴佹秷澶辩Щ闄edis play String app = item.getApp(); @@ -441,6 +449,7 @@ if ("rtp".equals(app)){ ret.put("close", true); StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, null, streamId); if (streamInfoForPlayCatch != null) { // 濡傛灉鍦ㄧ粰涓婄骇鎺ㄦ祦锛屼篃涓嶅仠姝€�� if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) { diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java index 84b36e3..3505225 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java @@ -31,6 +31,7 @@ on_server_keepalive } + @FunctionalInterface public interface Event{ void response(MediaServerItem mediaServerItem, JSONObject response); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java index 4cff4a6..9e76493 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.service; import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback; import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; @@ -34,4 +35,9 @@ DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); void zlmServerOffline(String mediaServerId); + + DeferredResult<ResponseEntity<String>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); + DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); + + StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index 9ee5867..7334184 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -12,6 +12,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.gb28181.utils.DateUtil; +import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; @@ -28,7 +30,6 @@ import com.genersoft.iot.vmp.service.IMediaService; import com.genersoft.iot.vmp.service.IPlayService; import gov.nist.javax.sip.stack.SIPDialog; -import jdk.nashorn.internal.ir.RuntimeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -38,10 +39,8 @@ import org.springframework.util.ResourceUtils; import org.springframework.web.context.request.async.DeferredResult; -import javax.sip.header.CallIdHeader; -import javax.sip.header.Header; -import javax.sip.message.Request; import java.io.FileNotFoundException; +import java.math.BigDecimal; import java.util.*; @SuppressWarnings(value = {"rawtypes", "unchecked"}) @@ -70,6 +69,9 @@ @Autowired private ZLMRESTfulUtils zlmresTfulUtils; + + @Autowired + private AssistRESTfulUtils assistRESTfulUtils; @Autowired private IMediaService mediaService; @@ -344,7 +346,7 @@ return result; } - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result); + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid, result); RequestMessage msg = new RequestMessage(); msg.setId(uuid); msg.setKey(key); @@ -406,6 +408,136 @@ } @Override + public DeferredResult<ResponseEntity<String>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) { + Device device = storager.queryVideoDevice(deviceId); + if (device == null) return null; + MediaServerItem newMediaServerItem = getNewMediaServerItem(device); + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); + + return download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed,infoCallBack, hookCallBack); + } + + @Override + public DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) { + if (mediaServerItem == null || ssrcInfo == null) return null; + String uuid = UUID.randomUUID().toString(); + String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; + DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L); + Device device = storager.queryVideoDevice(deviceId); + if (device == null) { + result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST)); + return result; + } + + resultHolder.put(key, uuid, result); + RequestMessage msg = new RequestMessage(); + msg.setId(uuid); + msg.setKey(key); + WVPResult<StreamInfo> wvpResult = new WVPResult<>(); + msg.setData(wvpResult); + PlayBackResult<RequestMessage> downloadResult = new PlayBackResult<>(); + downloadResult.setData(msg); + + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + logger.warn(String.format("褰曞儚涓嬭浇璇锋眰瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId)); + wvpResult.setCode(-1); + wvpResult.setMsg("褰曞儚涓嬭浇璇锋眰瓒呮椂"); + downloadResult.setCode(-1); + hookCallBack.call(downloadResult); + SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); + // 鐐规挱瓒呮椂鍥炲BYE 鍚屾椂閲婃斁ssrc浠ュ強姝ゆ鐐规挱鐨勮祫婧� + if (dialog != null) { + // 鐐规挱瓒呮椂鍥炲BYE 鍚屾椂閲婃斁ssrc浠ュ強姝ゆ鐐规挱鐨勮祫婧� + cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); + }else { + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); + mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream()); + streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); + } + cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); + // 鍥炲涔嬪墠鎵�鏈夌殑鐐规挱璇锋眰 + hookCallBack.call(downloadResult); + } + }, userSetup.getPlayTimeout()); + cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack, + inviteStreamInfo -> { + logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + inviteStreamInfo.getResponse().toJSONString()); + timer.cancel(); + StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); + streamInfo.setStartTime(startTime); + streamInfo.setEndTime(endTime); + if (streamInfo == null) { + logger.warn("褰曞儚涓嬭浇API璋冪敤澶辫触锛�"); + wvpResult.setCode(-1); + wvpResult.setMsg("褰曞儚涓嬭浇API璋冪敤澶辫触"); + downloadResult.setCode(-1); + hookCallBack.call(downloadResult); + return ; + } + redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId()); + wvpResult.setCode(0); + wvpResult.setMsg("success"); + wvpResult.setData(streamInfo); + downloadResult.setCode(0); + downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem()); + downloadResult.setResponse(inviteStreamInfo.getResponse()); + hookCallBack.call(downloadResult); + }, event -> { + timer.cancel(); + downloadResult.setCode(-1); + wvpResult.setCode(-1); + wvpResult.setMsg(String.format("褰曞儚涓嬭浇澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg)); + downloadResult.setEvent(event); + hookCallBack.call(downloadResult); + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); + }); + return result; + } + + @Override + public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) { + StreamInfo streamInfo = redisCatchStorage.queryDownload(deviceId, channelId, stream, null); + if (streamInfo != null) { + if (streamInfo.getProgress() == 1) { + return streamInfo; + } + + // 鑾峰彇褰撳墠宸蹭笅杞芥椂闀� + String mediaServerId = streamInfo.getMediaServerId(); + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); + if (mediaServerItem == null) { + logger.warn("鏌ヨ褰曞儚淇℃伅鏃跺彂鐜拌妭鐐瑰凡绂荤嚎"); + return null; + } + if (mediaServerItem.getRecordAssistPort() != 0) { + JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, streamInfo.getApp(), streamInfo.getStream(), null); + if (jsonObject != null && jsonObject.getInteger("code") == 0) { + long duration = jsonObject.getLong("data"); + + if (duration == 0) { + streamInfo.setProgress(0); + }else { + String startTime = streamInfo.getStartTime(); + String endTime = streamInfo.getEndTime(); + long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); + long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); + + BigDecimal currentCount = new BigDecimal(duration/1000); + BigDecimal totalCount = new BigDecimal(end-start); + BigDecimal divide = currentCount.divide(totalCount,2, BigDecimal.ROUND_HALF_UP); + double process = divide.doubleValue(); + streamInfo.setProgress(process); + } + } + } + } + return streamInfo; + } + + @Override public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) { RequestMessage msg = new RequestMessage(); msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java index 564deb5..3e82e8d 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java @@ -91,7 +91,7 @@ MediaServerItem mediaInfo; WVPResult<StreamInfo> wvpResult = new WVPResult<>(); wvpResult.setCode(0); - if ("auto".equals(param.getMediaServerId())){ + if (param.getMediaServerId() == null || "auto".equals(param.getMediaServerId())){ mediaInfo = mediaServerService.getMediaServerForMinimumLoad(); }else { mediaInfo = mediaServerService.getOne(param.getMediaServerId()); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 5094853..e669ab4 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -169,6 +169,8 @@ StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId); + boolean stopDownload(String deviceId, String channelId, String stream, String callId); + /** * 鏌ユ壘绗笁鏂圭郴缁熺暀涓嬬殑鍥芥爣棰勮鍊� * @param queryKey diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java index 6ad654e..4840446 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -166,8 +166,42 @@ @Override public boolean startDownload(StreamInfo stream, String callId) { - return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, - userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream); + boolean result; + if (stream.getProgress() == 1) { + result = redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, + userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream); + }else { + result = redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, + userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream, 60*60); + } + return result; + } + @Override + public boolean stopDownload(String deviceId, String channelId, String stream, String callId) { + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId); + if (deviceChannel != null) { + deviceChannel.setStreamId(null); + deviceChannel.setDeviceId(deviceId); + deviceChannelMapper.update(deviceChannel); + } + if (deviceId == null) deviceId = "*"; + if (channelId == null) channelId = "*"; + if (stream == null) stream = "*"; + if (callId == null) callId = "*"; + String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, + userSetup.getServerId(), + deviceId, + channelId, + stream, + callId + ); + List<Object> scan = redis.scan(key); + if (scan.size() > 0) { + for (Object keyObj : scan) { + redis.del((String) keyObj); + } + } + return true; } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/DownloadController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/DownloadController.java deleted file mode 100644 index 4ffbd4b..0000000 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/DownloadController.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.genersoft.iot.vmp.vmanager.gb28181.playback; - -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; -import com.genersoft.iot.vmp.service.IMediaServerService; -import com.genersoft.iot.vmp.service.bean.SSRCInfo; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.service.IPlayService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import com.alibaba.fastjson.JSONObject; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import org.springframework.web.context.request.async.DeferredResult; - -import javax.sip.message.Response; -import java.util.UUID; - -@Api(tags = "鍘嗗彶濯掍綋涓嬭浇") -@CrossOrigin -@RestController -@RequestMapping("/api/download") -public class DownloadController { - - private final static Logger logger = LoggerFactory.getLogger(DownloadController.class); - - @Autowired - private SIPCommander cmder; - - @Autowired - private IVideoManagerStorager storager; - - @Autowired - private IRedisCatchStorage redisCatchStorage; - - // @Autowired - // private ZLMRESTfulUtils zlmresTfulUtils; - - @Autowired - private IPlayService playService; - - @Autowired - private DeferredResultHolder resultHolder; - - @Autowired - private IMediaServerService mediaServerService; - - @ApiOperation("寮�濮嬪巻鍙插獟浣撲笅杞�") - @ApiImplicitParams({ - @ApiImplicitParam(name = "deviceId", value = "璁惧ID", dataTypeClass = String.class), - @ApiImplicitParam(name = "channelId", value = "閫氶亾ID", dataTypeClass = String.class), - @ApiImplicitParam(name = "startTime", value = "寮�濮嬫椂闂�", dataTypeClass = String.class), - @ApiImplicitParam(name = "endTime", value = "缁撴潫鏃堕棿", dataTypeClass = String.class), - @ApiImplicitParam(name = "downloadSpeed", value = "涓嬭浇鍊嶉��", dataTypeClass = String.class), - }) - @GetMapping("/start/{deviceId}/{channelId}") - public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, @PathVariable String channelId, - String startTime, String endTime, String downloadSpeed) { - - if (logger.isDebugEnabled()) { - logger.debug(String.format("鍘嗗彶濯掍綋涓嬭浇 API璋冪敤锛宒eviceId锛�%s锛宑hannelId锛�%s锛宒ownloadSpeed锛�%s", deviceId, channelId, downloadSpeed)); - } - String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; - String uuid = UUID.randomUUID().toString(); - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L); - // 瓒呮椂澶勭悊 - result.onTimeout(()->{ - logger.warn(String.format("璁惧涓嬭浇鍝嶅簲瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId)); - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData("Timeout"); - resultHolder.invokeAllResult(msg); - }); - if(resultHolder.exist(key, null)) { - return result; - } - resultHolder.put(key, uuid, result); - Device device = storager.queryVideoDevice(deviceId); - - MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); - if (newMediaServerItem == null) { - logger.warn(String.format("璁惧涓嬭浇鍝嶅簲瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId)); - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData("Timeout"); - resultHolder.invokeAllResult(msg); - return result; - } - - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); - - cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> { - logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + inviteStreamInfo.getResponse().toJSONString()); - playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid); - }, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg)); - resultHolder.invokeAllResult(msg); - }); - - return result; - } - - @ApiOperation("鍋滄鍘嗗彶濯掍綋涓嬭浇") - @ApiImplicitParams({ - @ApiImplicitParam(name = "deviceId", value = "璁惧ID", dataTypeClass = String.class), - @ApiImplicitParam(name = "channelId", value = "閫氶亾ID", dataTypeClass = String.class), - @ApiImplicitParam(name = "stream", value = "娴両D", dataTypeClass = String.class), - }) - @GetMapping("/stop/{deviceId}/{channelId}/{stream}") - public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { - - cmder.streamByeCmd(deviceId, channelId, stream, null); - - if (logger.isDebugEnabled()) { - logger.debug(String.format("璁惧鍘嗗彶濯掍綋涓嬭浇鍋滄 API璋冪敤锛宒eviceId/channelId锛�%s_%s", deviceId, channelId)); - } - - if (deviceId != null && channelId != null) { - JSONObject json = new JSONObject(); - json.put("deviceId", deviceId); - json.put("channelId", channelId); - return new ResponseEntity<String>(json.toString(), HttpStatus.OK); - } else { - logger.warn("璁惧鍘嗗彶濯掍綋涓嬭浇鍋滄API璋冪敤澶辫触锛�"); - return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); - } - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java index e565981..d33dd2a 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java @@ -1,6 +1,13 @@ package com.genersoft.iot.vmp.vmanager.gb28181.record; +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.service.IMediaServerService; +import com.genersoft.iot.vmp.service.IPlayService; +import com.genersoft.iot.vmp.service.bean.SSRCInfo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -8,6 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; @@ -40,6 +48,12 @@ @Autowired private DeferredResultHolder resultHolder; + + @Autowired + private IPlayService playService; + + @Autowired + private IMediaServerService mediaServerService; @ApiOperation("褰曞儚鏌ヨ") @ApiImplicitParams({ @@ -77,4 +91,111 @@ }); return result; } + + @ApiOperation("寮�濮嬪巻鍙插獟浣撲笅杞�") + @ApiImplicitParams({ + @ApiImplicitParam(name = "deviceId", value = "璁惧ID", dataTypeClass = String.class), + @ApiImplicitParam(name = "channelId", value = "閫氶亾ID", dataTypeClass = String.class), + @ApiImplicitParam(name = "startTime", value = "寮�濮嬫椂闂�", dataTypeClass = String.class), + @ApiImplicitParam(name = "endTime", value = "缁撴潫鏃堕棿", dataTypeClass = String.class), + @ApiImplicitParam(name = "downloadSpeed", value = "涓嬭浇鍊嶉��", dataTypeClass = String.class), + }) + @GetMapping("/download/start/{deviceId}/{channelId}") + public DeferredResult<ResponseEntity<String>> download(@PathVariable String deviceId, @PathVariable String channelId, + String startTime, String endTime, String downloadSpeed) { + + if (logger.isDebugEnabled()) { + logger.debug(String.format("鍘嗗彶濯掍綋涓嬭浇 API璋冪敤锛宒eviceId锛�%s锛宑hannelId锛�%s锛宒ownloadSpeed锛�%s", deviceId, channelId, downloadSpeed)); + } +// String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; +// String uuid = UUID.randomUUID().toString(); +// DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L); +// // 瓒呮椂澶勭悊 +// result.onTimeout(()->{ +// logger.warn(String.format("璁惧涓嬭浇鍝嶅簲瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId)); +// RequestMessage msg = new RequestMessage(); +// msg.setId(uuid); +// msg.setKey(key); +// msg.setData("Timeout"); +// resultHolder.invokeAllResult(msg); +// }); +// if(resultHolder.exist(key, null)) { +// return result; +// } +// resultHolder.put(key, uuid, result); +// Device device = storager.queryVideoDevice(deviceId); +// +// MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); +// if (newMediaServerItem == null) { +// logger.warn(String.format("璁惧涓嬭浇鍝嶅簲瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId)); +// RequestMessage msg = new RequestMessage(); +// msg.setId(uuid); +// msg.setKey(key); +// msg.setData("Timeout"); +// resultHolder.invokeAllResult(msg); +// return result; +// } +// +// SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); +// +// cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> { +// logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + inviteStreamInfo.getResponse().toJSONString()); +// playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid); +// }, event -> { +// RequestMessage msg = new RequestMessage(); +// msg.setId(uuid); +// msg.setKey(key); +// msg.setData(String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg)); +// resultHolder.invokeAllResult(msg); +// }); + + if (logger.isDebugEnabled()) { + logger.debug(String.format("璁惧鍥炴斁 API璋冪敤锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId)); + } + + DeferredResult<ResponseEntity<String>> result = playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, hookCallBack->{ + resultHolder.invokeResult(hookCallBack.getData()); + }); + + return result; + } + + @ApiOperation("鍋滄鍘嗗彶濯掍綋涓嬭浇") + @ApiImplicitParams({ + @ApiImplicitParam(name = "deviceId", value = "璁惧ID", dataTypeClass = String.class), + @ApiImplicitParam(name = "channelId", value = "閫氶亾ID", dataTypeClass = String.class), + @ApiImplicitParam(name = "stream", value = "娴両D", dataTypeClass = String.class), + }) + @GetMapping("/download/stop/{deviceId}/{channelId}/{stream}") + public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { + + cmder.streamByeCmd(deviceId, channelId, stream, null); + + if (logger.isDebugEnabled()) { + logger.debug(String.format("璁惧鍘嗗彶濯掍綋涓嬭浇鍋滄 API璋冪敤锛宒eviceId/channelId锛�%s_%s", deviceId, channelId)); + } + + if (deviceId != null && channelId != null) { + JSONObject json = new JSONObject(); + json.put("deviceId", deviceId); + json.put("channelId", channelId); + return new ResponseEntity<String>(json.toString(), HttpStatus.OK); + } else { + logger.warn("璁惧鍘嗗彶濯掍綋涓嬭浇鍋滄API璋冪敤澶辫触锛�"); + return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @ApiOperation("鑾峰彇鍘嗗彶濯掍綋涓嬭浇杩涘害") + @ApiImplicitParams({ + @ApiImplicitParam(name = "deviceId", value = "璁惧ID", dataTypeClass = String.class), + @ApiImplicitParam(name = "channelId", value = "閫氶亾ID", dataTypeClass = String.class), + @ApiImplicitParam(name = "stream", value = "娴両D", dataTypeClass = String.class), + }) + @GetMapping("/download/progress/{deviceId}/{channelId}/{stream}") + public ResponseEntity<StreamInfo> getProgress(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { + + StreamInfo streamInfo = playService.getDownLoadInfo(deviceId, channelId, stream); + return new ResponseEntity<>(streamInfo, HttpStatus.OK); + } } diff --git a/web_src/build/webpack.dev.conf.js b/web_src/build/webpack.dev.conf.js index 070ae22..55efd30 100755 --- a/web_src/build/webpack.dev.conf.js +++ b/web_src/build/webpack.dev.conf.js @@ -32,6 +32,7 @@ contentBase: false, // since we use CopyWebpackPlugin. compress: true, host: HOST || config.dev.host, + // host:'127.0.0.1', port: PORT || config.dev.port, open: config.dev.autoOpenBrowser, overlay: config.dev.errorOverlay diff --git a/web_src/config/index.js b/web_src/config/index.js index cec91b8..b1e1cbe 100644 --- a/web_src/config/index.js +++ b/web_src/config/index.js @@ -29,11 +29,13 @@ }, // Various Dev Server settings - host: 'localhost', // can be overwritten by process.env.HOST + host:"127.0.0.1", + useLocalIp: false, // can be overwritten by process.env.HOST port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined autoOpenBrowser: false, errorOverlay: true, notifyOnErrors: true, + hot: true,//鑷姩淇濆瓨 poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- diff --git a/web_src/package-lock.json b/web_src/package-lock.json index 356bbcc..b1da39e 100644 --- a/web_src/package-lock.json +++ b/web_src/package-lock.json @@ -57,7 +57,7 @@ "vue-template-compiler": "^2.5.2", "webpack": "^3.6.0", "webpack-bundle-analyzer": "^2.9.0", - "webpack-dev-server": "^2.9.1", + "webpack-dev-server": "^2.11.5", "webpack-merge": "^4.1.0" }, "engines": { @@ -13382,7 +13382,7 @@ }, "node_modules/webpack-dev-server": { "version": "2.11.5", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz", + "resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz", "integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==", "dev": true, "dependencies": { @@ -25569,7 +25569,7 @@ }, "webpack-dev-server": { "version": "2.11.5", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz", + "resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz", "integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==", "dev": true, "requires": { diff --git a/web_src/src/components/dialog/devicePlayer.vue b/web_src/src/components/dialog/devicePlayer.vue index 5a08006..effd389 100644 --- a/web_src/src/components/dialog/devicePlayer.vue +++ b/web_src/src/components/dialog/devicePlayer.vue @@ -175,6 +175,7 @@ </el-tabs> </div> </el-dialog> + <recordDownload ref="recordDownload"></recordDownload> </div> </template> @@ -183,15 +184,15 @@ // import LivePlayer from '@liveqing/liveplayer' // import player from '../dialog/easyPlayer.vue' import player from '../dialog/jessibuca.vue' +import recordDownload from '../dialog/recordDownload.vue' export default { name: 'devicePlayer', props: {}, components: { - player, + player,recordDownload, }, computed: { getPlayerShared: function () { - return { sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl), sharedIframe: '<iframe src="' + window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl) + '"></iframe>', @@ -250,7 +251,7 @@ that.tracks = []; that.tracksLoading = true; that.tracksNotLoaded = false; - if (tab.name == "codec") { + if (tab.name === "codec") { this.$axios({ method: 'get', url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId @@ -340,7 +341,7 @@ this.$refs.videoPlayer.pause() that.$axios({ method: 'post', - url: '/api/play/convert/' + that.streamId + url: '/api/gb_record/convert/' + that.streamId }).then(function (res) { if (res.data.code == 0) { that.convertKey = res.data.key; @@ -474,8 +475,8 @@ console.log(this.seekTime) if (that.streamId != "") { that.stopPlayRecord(function () { - that.streamId = "", - that.playRecord(row); + that.streamId = ""; + that.playRecord(row); }) } else { this.$axios({ @@ -506,22 +507,36 @@ downloadRecord: function (row) { let that = this; if (that.streamId != "") { - that.stopDownloadRecord(function () { - that.streamId = "", - that.downloadRecord(row); + that.stopDownloadRecord(function (res) { + if (res.code == 0) { + that.streamId = ""; + that.downloadRecord(row); + }else { + this.$message({ + showClose: true, + message: res.data.msg, + type: "error", + }); + } + }) } else { this.$axios({ method: 'get', - url: '/api/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' + + url: '/api/gb_record/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' + row.endTime + '&downloadSpeed=4' }).then(function (res) { - var streamInfo = res.data; - that.app = streamInfo.app; - that.streamId = streamInfo.stream; - that.mediaServerId = streamInfo.mediaServerId; - that.videoUrl = that.getUrlByStreamInfo(streamInfo); - that.recordPlay = true; + if (res.data.code == 0) { + let streamInfo = res.data.data; + that.recordPlay = false; + that.$refs.recordDownload.openDialog(that.deviceId, that.channelId, streamInfo.app, streamInfo.stream, streamInfo.mediaServerId); + }else { + that.$message({ + showClose: true, + message: res.data.msg, + type: "error", + }); + } }); } }, @@ -530,9 +545,9 @@ this.videoUrl = ''; this.$axios({ method: 'get', - url: '/api/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId - }).then(function (res) { - if (callback) callback() + url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId + }).then((res)=> { + if (callback) callback(res) }); }, ptzCamera: function (command) { diff --git a/web_src/src/components/dialog/recordDownload.vue b/web_src/src/components/dialog/recordDownload.vue new file mode 100644 index 0000000..6b7ca1f --- /dev/null +++ b/web_src/src/components/dialog/recordDownload.vue @@ -0,0 +1,195 @@ +<template> +<div id="recordDownload" > + <el-dialog :title="title" v-if="showDialog" width="45rem" :append-to-body="true" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()" center> + <el-row> + <el-col :span="18" style="padding-top: 7px;"> + <el-progress :percentage="percentage"></el-progress> + </el-col> + <el-col :span="6" > +<!-- <el-dropdown size="mini" title="鎾斁鍊嶉��" style="margin-left: 1px;" @command="gbScale">--> +<!-- <el-button-group>--> +<!-- <el-button size="mini" style="width: 100%">--> +<!-- {{scale}}鍊嶉�� <i class="el-icon-arrow-down el-icon--right"></i>--> +<!-- </el-button>--> +<!-- </el-button-group>--> +<!-- <el-dropdown-menu slot="dropdown">--> +<!-- <el-dropdown-item command="1">1鍊嶉��</el-dropdown-item>--> +<!-- <el-dropdown-item command="2">2鍊嶉��</el-dropdown-item>--> +<!-- <el-dropdown-item command="4">4鍊嶉��</el-dropdown-item>--> +<!-- </el-dropdown-menu>--> +<!-- </el-dropdown>--> + <el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="鐐瑰嚮涓嬭浇鍙皢浠ョ紦瀛橀儴鍒嗕笅杞藉埌鏈湴" @click="download()">鍋滄缂撳瓨骞朵笅杞�</el-button> + </el-col> + </el-row> + </el-dialog> +</div> +</template> + + +<script> + +import moment from "moment"; + +export default { + name: 'recordDownload', + created() { + + + }, + data() { + return { + title: "鍥涘�嶉�熶笅杞戒腑...", + deviceId: "", + channelId: "", + app: "", + stream: "", + mediaServerId: "", + showDialog: false, + scale: 1, + percentage: 0.00, + streamInfo: null, + taskId: null, + getProgressRun: false, + getProgressForFileRun: false, + + }; + }, + methods: { + openDialog: function (deviceId, channelId, app, stream, mediaServerId) { + this.deviceId = deviceId; + this.channelId = channelId; + this.app = app; + this.stream = stream; + this.mediaServerId = mediaServerId; + this.showDialog = true; + this.getProgressRun = true; + this.percentage = 0.0; + this.getProgressTimer() + }, + getProgressTimer(){ + if (!this.getProgressRun) { + return; + } + if (this.percentage == 100 ) { + this.getFileDownload(); + return; + } + setTimeout( ()=>{ + if (!this.showDialog) return; + this.getProgress(this.getProgressTimer()) + }, 5000) + }, + getProgress: function (callback){ + this.$axios({ + method: 'get', + url: `/api/gb_record/download/progress/${this.deviceId}/${this.channelId}/${this.stream}` + }).then((res)=> { + console.log(res) + console.log(res.data.progress) + this.streamInfo = res.data; + if (parseFloat(res.data.progress) == 1) { + this.percentage = 100; + }else { + this.percentage = (res.data.progress*100).toFixed(1); + } + if (callback)callback(); + }).catch((e) =>{ + + }); + }, + close: function (){ + if (this.streamInfo.progress < 100) { + this.stopDownloadRecord(); + } + this.showDialog=false; + this.getProgressRun = false; + this.getProgressForFileRun = false; + }, + gbScale: function (scale){ + this.scale = scale; + }, + download: function (){ + this.getProgressRun = false; + if (this.streamInfo != null ) { + if (this.streamInfo.progress < 1) { + // 鍙戦�佸仠姝㈢紦瀛� + this.stopDownloadRecord((res)=>{ + this.getFileDownload() + }) + }else { + this.getFileDownload() + } + } + }, + stopDownloadRecord: function (callback) { + this.$axios({ + method: 'get', + url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.stream + }).then((res)=> { + if (callback) callback(res) + }); + }, + getFileDownload: function (){ + this.$axios({ + method: 'get', + url:`/record_proxy/${this.mediaServerId}/api/record/file/download/task/add`, + params: { + app: this.app, + stream: this.stream, + startTime: null, + endTime: null, + } + }).then((res) =>{ + if (res.data.code === 0 && res.data.msg === "success") { + // 鏌ヨ杩涘害 + this.title = "褰曞儚鏂囦欢澶勭悊涓�..." + this.taskId = res.data.data; + this.percentage = 0.0; + this.getProgressForFileRun = true; + this.getProgressForFileTimer(); + } + }).catch(function (error) { + console.log(error); + }); + }, + getProgressForFileTimer: function (){ + if (!this.getProgressForFileRun || this.percentage == 100) { + return; + } + setTimeout( ()=>{ + if (!this.showDialog) return; + this.getProgressForFile(this.getProgressForFileTimer()) + }, 1000) + }, + getProgressForFile: function (callback){ + this.$axios({ + method: 'get', + url:`/record_proxy/${this.mediaServerId}/api/record/file/download/task/list`, + params: { + app: this.app, + stream: this.stream, + taskId: this.taskId, + isEnd: true, + } + }).then((res) => { + if (res.data.code == 0) { + this.percentage = parseFloat(res.data.data.percentage)*100 + if (res.data.data[0].percentage === '1') { + this.getProgressForFileRun = false; + window.open(res.data.data[0].downloadFile) + this.close(); + }else { + if (callback)callback() + } + } + }).catch(function (error) { + console.log(error); + }); + } + } +}; +</script> + +<style> + +</style> diff --git a/web_src/src/components/test.vue b/web_src/src/components/test.vue deleted file mode 100644 index d780125..0000000 --- a/web_src/src/components/test.vue +++ /dev/null @@ -1,198 +0,0 @@ -<template> -<div id="test"> - <div class="timeQuery" id="timeQuery"> - <div class="timeQuery-background" ></div> - <div class="timeQuery-pointer"> - <div class="timeQuery-pointer-content" id="timeQueryPointer"> - <div class="timeQuery-pointer-handle" @mousedown.left="mousedownHandler" ></div> - </div> - </div> - - <div class="timeQuery-data" > - - <div class="timeQuery-data-cell" v-for="item of recordData" :style="'width:' + getDataWidth(item) + '%; left:' + getDataLeft(item) + '%'" ></div> - <!-- <div class="timeQuery-data-cell" style="width: 30%; left: 20%" @click="timeChoose"></div>--> - <!-- <div class="timeQuery-data-cell" style="width: 60%; left: 20%" @click="timeChoose"></div>--> - </div> - - <div class="timeQuery-label" > - <div class="timeQuery-label-cell" style="left: 0%"> - <div class="timeQuery-label-cell-label">0</div> - </div> - <div v-for="index of timeNode" class="timeQuery-label-cell" :style="'left:' + (100.0/timeNode*index).toFixed(4) + '%'"> - <div class="timeQuery-label-cell-label">{{24/timeNode * index}}</div> - </div> - </div> - </div> - -</div> -</template> - -<script> -export default { - name: "test", - data() { - return { - mouseDown: false, - timeNode: 24, - recordData:[ - { - startTime: "2021-04-18 00:00:00", - endTime: "2021-04-18 00:00:09", - }, - { - startTime: "2021-04-18 00:00:09", - endTime: "2021-04-18 01:00:05", - }, - { - startTime: "2021-04-18 02:00:01", - endTime: "2021-04-18 04:25:05", - }, - { - startTime: "2021-04-18 05:00:01", - endTime: "2021-04-18 20:00:05", - }, - ] - }; - }, - mounted() { - document.body.addEventListener("mouseup", this.mouseupHandler, false) - document.body.addEventListener("mousemove", this.mousemoveHandler, false) - }, - methods:{ - getTimeNode(){ - let mine = 20 - let width = document.getElementById("timeQuery").offsetWidth - if (width/20 > 24){ - return 24 - }else if (width/20 > 12) { - return 12 - }else if (width/20 > 6) { - return 6 - } - }, - timeChoose(event){ - console.log(event) - }, - getDataWidth(item){ - let startTime = new Date(item.startTime); - let endTime = new Date(item.endTime); - let result = parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10)) - // console.log(result) - return parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10)) - }, - getDataLeft(item){ - let startTime = new Date(item.startTime); - let differenceTime = startTime.getTime() - new Date(item.startTime.substr(0,10) + " 00:00:00").getTime() - let result = differenceTime/(24*60*60*10) - console.log(differenceTime) - console.log(result) - return parseFloat(differenceTime/(24*60*60*10)); - }, - mousedownHandler(event){ - this.mouseDown = true - }, - mousemoveHandler(event){ - if (this.mouseDown){ - document.getElementById("timeQueryPointer").style.left = (event.clientX - 20)+ "px" - } - }, - mouseupHandler(event){ - this.mouseDown = false - } - } -} -</script> - -<style scoped> - .timeQuery{ - width: 96%; - margin-left: 2%; - margin-right: 2%; - margin-top: 20%; - position: absolute; - } - .timeQuery-background{ - height: 16px; - width: 100%; - background-color: #ececec; - position: absolute; - left: 0; - top: 0; - z-index: 10; - box-shadow: #9d9d9d 0px 0px 10px inset; - } - .timeQuery-data{ - height: 16px; - width: 100%; - position: absolute; - left: 0; - top: 0; - z-index: 11; - } - .timeQuery-data-cell{ - height: 10px; - background-color: #888787; - position: absolute; - z-index: 11; - -webkit-box-shadow: #9d9d9d 0px 0px 10px inset; - margin-top: 3px; - top: 100%; - } - .timeQuery-label{ - height: 16px; - width: 100%; - position: absolute; - pointer-events: none; - left: 0; - top: 0; - z-index: 11; - } - .timeQuery-label-cell{ - height: 16px; - position: absolute; - z-index: 12; - width: 0px; - border-right: 1px solid #b7b7b7; - } - .timeQuery-label-cell-label { - width: 23px; - text-align: center; - height: 18px; - margin-left: -10px; - margin-top: -30px; - color: #444; - } - .timeQuery-pointer{ - width: 0px; - height: 18px; - position: absolute; - left: 0; - } - .timeQuery-pointer-content{ - width: 0px; - height: 70px; - position: absolute; - border-right: 2px solid #f60303; - z-index: 14; - top: -30px; - } - .timeQuery-pointer-handle { - width: 0; - height: 0; - border-top: 12px solid transparent; - border-right: 12px solid transparent; - border-bottom: 20px solid #ff0909; - border-left: 12px solid transparent; - cursor: no-drop; - position: absolute; - left: -11px; - top: 50px; - } - /*.timeQuery-cell:after{*/ - /* content: "";*/ - /* height: 14px;*/ - /* border: 1px solid #e70303;*/ - /* position: absolute;*/ - /*}*/ -</style> diff --git a/web_src/src/components/test2.vue b/web_src/src/components/test2.vue deleted file mode 100644 index 75f182e..0000000 --- a/web_src/src/components/test2.vue +++ /dev/null @@ -1,190 +0,0 @@ -<template> -<div id="test2"> - <div class="timeQuery" style="width: 100%; height: 300px" id="timeQuery"> - </div> -</div> -</template> - -<script> - -import * as echarts from 'echarts'; - -export default { - name: "test2", - data() { - return { - }; - }, - mounted() { - var base = +new Date("2021-02-02 00:00:00"); - var oneDay = 24 * 3600 * 1000; - - var data = [[base, 10]]; - - for (var i = 1; i < 24; i++) { - var now = new Date(base += oneDay); - data.push([ - new Date("2021-02-02 " + i+":00:00"), 10 - ]); - } - // 鍩轰簬鍑嗗濂界殑dom锛屽垵濮嬪寲echarts瀹炰緥 - var myChart = echarts.init(document.getElementById('timeQuery')); - let option = { - - toolbox: { - feature: { - dataZoom: { - yAxisIndex: 'none' - }, - restore: {}, - saveAsImage: {} - } - }, - xAxis: { - type: 'time', - boundaryGap: false - }, - yAxis: { - type: 'value', - show: false, - splitLine:{show: false}, //鍘婚櫎缃戞牸绾� - boundaryGap: [0, '100%'] - }, - dataZoom: [{ - type: 'inside', - start: 0, - end: 20 - }, { - start: 0, - end: 20 - }], - series: [ - { - name: '妯℃嫙鏁版嵁', - type: 'line', - smooth: false, - symbol: 'none', - areaStyle: {}, - data: data - } - ] - }; - // 缁樺埗鍥捐〃 - myChart.setOption(option); - }, - methods:{ - getTimeNode(){ - let mine = 20 - let width = document.getElementById("timeQuery").offsetWidth - if (width/20 > 24){ - return 24 - }else if (width/20 > 12) { - return 12 - }else if (width/20 > 6) { - return 6 - } - }, - hoveEvent(event){ - console.log(2222222) - console.log(event) - }, - timeChoose(event){ - console.log(event) - }, - getDataWidth(item){ - let startTime = new Date(item.startTime); - let endTime = new Date(item.endTime); - let result = parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10)) - // console.log(result) - return parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10)) - }, - getDataLeft(item){ - let startTime = new Date(item.startTime); - let differenceTime = startTime.getTime() - new Date(item.startTime.substr(0,10) + " 00:00:00").getTime() - let result = differenceTime/(24*60*60*10) - console.log(differenceTime) - console.log(result) - return parseFloat(differenceTime/(24*60*60*10)); - } - } -} -</script> - -<style scoped> - .timeQuery{ - width: 96%; - margin-left: 2%; - margin-right: 2%; - margin-top: 20%; - position: absolute; - } - .timeQuery-background{ - height: 16px; - width: 100%; - background-color: #ececec; - position: absolute; - left: 0; - top: 0; - z-index: 10; - box-shadow: #9d9d9d 0px 0px 10px inset; - } - .timeQuery-data{ - height: 16px; - width: 100%; - position: absolute; - left: 0; - top: 0; - z-index: 11; - } - .timeQuery-data-cell{ - height: 10px; - background-color: #888787; - position: absolute; - z-index: 11; - -webkit-box-shadow: #9d9d9d 0px 0px 10px inset; - margin-top: 3px; - } - .timeQuery-label{ - height: 16px; - width: 100%; - position: absolute; - pointer-events: none; - left: 0; - top: 0; - z-index: 11; - } - .timeQuery-label-cell{ - height: 16px; - position: absolute; - z-index: 12; - width: 0px; - border-right: 1px solid #b7b7b7; - } - .timeQuery-label-cell-label { - width: 23px; - text-align: center; - height: 18px; - margin-left: -10px; - margin-top: -30px; - color: #444; - } - .timeQuery-pointer{ - width: 0px; - height: 18px; - position: absolute; - left: 0; - } - .timeQuery-pointer-content{ - width: 0px; - height: 16px; - position: absolute; - border-right: 3px solid #f60303; - z-index: 14; - } - /*.timeQuery-cell:after{*/ - /* content: "";*/ - /* height: 14px;*/ - /* border: 1px solid #e70303;*/ - /* position: absolute;*/ - /*}*/ -</style> diff --git a/web_src/src/router/index.js b/web_src/src/router/index.js index ad573cf..05bb1ae 100644 --- a/web_src/src/router/index.js +++ b/web_src/src/router/index.js @@ -11,7 +11,6 @@ import parentPlatformList from '../components/ParentPlatformList.vue' import cloudRecord from '../components/CloudRecord.vue' import mediaServerManger from '../components/MediaServerManger.vue' -import test from '../components/test.vue' import web from '../components/setting/Web.vue' import sip from '../components/setting/Sip.vue' import media from '../components/setting/Media.vue' @@ -95,11 +94,6 @@ path: '/setting/media', name: 'media', component: media, - }, - { - path: '/test', - name: 'test', - component: test, }, { path: '/play/wasm/:url', -- Gitblit v1.8.0