From 7e136c9ac7265bedfdb79b4bca465965486e0541 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: 星期三, 06 十二月 2023 15:11:21 +0800 Subject: [PATCH] 完成下载文件的前后调试 --- src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java | 9 + src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java | 91 +++++------------ web_src/src/components/dialog/recordDownload.vue | 108 ++++---------------- src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java | 16 +++ src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java | 28 ----- web_src/build/webpack.dev.conf.js | 6 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java | 1 7 files changed, 77 insertions(+), 182 deletions(-) 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 3bf9505..67fea3e 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -761,7 +761,7 @@ taskExecutor.execute(() -> { JSONObject json = (JSONObject) JSON.toJSON(param); List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); - if (subscribes != null && subscribes.size() > 0) { + if (subscribes != null && !subscribes.isEmpty()) { for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { subscribe.response(null, param); } @@ -780,7 +780,14 @@ logger.info("[ZLM HOOK] 褰曞儚瀹屾垚浜嬩欢锛歿}->{}", param.getMediaServerId(), param.getFile_path()); taskExecutor.execute(() -> { + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_record_mp4); + if (subscribes != null && !subscribes.isEmpty()) { + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { + subscribe.response(null, param); + } + } cloudRecordService.addRecord(param); + }); return HookResult.SUCCESS(); 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 bee7f1e..e8def54 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java @@ -45,5 +45,4 @@ void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback); - void getFilePath(String deviceId, String channelId, String stream, ErrorCallback<DownloadFileInfo> callback); } 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 1e8dee7..7ca07ee 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -49,9 +49,11 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.text.ParseException; +import java.time.Instant; import java.util.List; import java.util.UUID; import java.util.Vector; +import java.util.concurrent.TimeUnit; @SuppressWarnings(value = {"rawtypes", "unchecked"}) @Service @@ -718,6 +720,28 @@ // 澶勭悊鏀跺埌200ok鍚庣殑TCP涓诲姩杩炴帴浠ュ強SSRC涓嶄竴鑷寸殑闂 InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD); + + // 娉ㄥ唽褰曞儚鍥炶皟浜嬩欢锛屽綍鍍忎笅杞界粨鏉熷悗鍐欏叆涓嬭浇鍦板潃 + ZlmHttpHookSubscribe.Event hookEventForRecord = (mediaServerItemInuse, hookParam) -> { + logger.info("[褰曞儚涓嬭浇] 鏀跺埌褰曞儚鍐欏叆纾佺洏娑堟伅锛� 锛� {}/{}-{}", + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), ssrcInfo.getStream()); + logger.info("[褰曞儚涓嬭浇] 鏀跺埌褰曞儚鍐欏叆纾佺洏娑堟伅鍐呭锛� " + hookParam); + OnRecordMp4HookParam recordMp4HookParam = (OnRecordMp4HookParam)hookParam; + String filePath = recordMp4HookParam.getFile_path(); + DownloadFileInfo downloadFileInfo = getDownloadFilePath(mediaServerItem, filePath); + InviteInfo inviteInfoForNew = inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId() + , inviteInfo.getChannelId(), inviteInfo.getStream()); + inviteInfoForNew.getStreamInfo().setDownLoadFilePath(downloadFileInfo); + inviteStreamService.updateInviteInfo(inviteInfoForNew); + }; + HookSubscribeForRecordMp4 hookSubscribe = HookSubscribeFactory.on_record_mp4( + mediaServerItem.getId(), "rtp", ssrcInfo.getStream()); + + // 璁剧疆杩囨湡鏃堕棿锛屼笅杞藉け璐ユ椂鑷姩澶勭悊璁㈤槄鏁版嵁 +// long difference = DateUtil.getDifference(startTime, endTime)/1000; +// Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(difference * 2)); +// hookSubscribe.setExpires(expiresInstant); + subscribe.addSubscribe(hookSubscribe, hookEventForRecord); }); } catch (InvalidArgumentException | SipException | ParseException e) { logger.error("[鍛戒护鍙戦�佸け璐 褰曞儚涓嬭浇: {}", e.getMessage()); @@ -791,74 +815,13 @@ BigDecimal totalCount = new BigDecimal((end - start) * 1000); BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); double process = divide.doubleValue(); + if (process > 0.999) { + process = 1.0; + } inviteInfo.getStreamInfo().setProgress(process); } inviteStreamService.updateInviteInfo(inviteInfo); return inviteInfo.getStreamInfo(); - } - - @Override - public void getFilePath(String deviceId, String channelId, String stream, ErrorCallback<DownloadFileInfo> callback) { - InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream); - if (inviteInfo == null || inviteInfo.getStreamInfo() == null) { - logger.warn("[鑾峰彇褰曞儚涓嬭浇鏂囦欢鍦板潃] 鏈煡璇㈠埌褰曞儚涓嬭浇鐨勪俊鎭紝 {}/{}-{}", deviceId, channelId, stream); - callback.run(ErrorCode.ERROR100.getCode(), "鏈煡璇㈠埌褰曞儚涓嬭浇鐨勪俊鎭�", null); - return ; - } - - if (!ObjectUtils.isEmpty(inviteInfo.getStreamInfo().getDownLoadFilePath())) { - callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), - inviteInfo.getStreamInfo().getDownLoadFilePath()); - return; - } - - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo("rtp", stream); - if (streamAuthorityInfo == null) { - logger.warn("[鑾峰彇褰曞儚涓嬭浇鏂囦欢鍦板潃] 鏈煡璇㈠埌褰曞儚鐨勮棰戜俊鎭紝 {}/{}-{}", deviceId, channelId, stream); - callback.run(ErrorCode.ERROR100.getCode(), "鏈煡璇㈠埌褰曞儚鐨勮棰戜俊鎭�", null); - return ; - } - - // 鑾峰彇褰撳墠宸蹭笅杞芥椂闀� - String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId(); - MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); - if (mediaServerItem == null) { - logger.warn("[鑾峰彇褰曞儚涓嬭浇鏂囦欢鍦板潃] 鏌ヨ褰曞儚淇℃伅鏃跺彂鐜拌妭鐐逛笉瀛樺湪锛� {}/{}-{}", deviceId, channelId, stream); - callback.run(ErrorCode.ERROR100.getCode(), "鏌ヨ褰曞儚淇℃伅鏃跺彂鐜拌妭鐐逛笉瀛樺湪", null); - return ; - } - - List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getListByCallId(streamAuthorityInfo.getCallId()); - if (!cloudRecordItemList.isEmpty()) { - String filePath = cloudRecordItemList.get(0).getFilePath(); - - DownloadFileInfo downloadFileInfo = getDownloadFilePath(mediaServerItem, filePath); - inviteInfo.getStreamInfo().setDownLoadFilePath(downloadFileInfo); - inviteStreamService.updateInviteInfo(inviteInfo); - callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), downloadFileInfo); - }else { - // 鍙兘灏氭湭鐢熸垚锛岄偅灏辩洃鍚琱ook绛夌潃鏀跺埌瀵瑰簲鐨勫綍鍍忛�氱煡 - ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, hookParam) -> { - logger.info("[褰曞儚涓嬭浇]鏀跺埌璁㈤槄娑堟伅锛� 锛� {}/{}-{}", deviceId, channelId, stream); - logger.info("[褰曞儚涓嬭浇]鏀跺埌璁㈤槄娑堟伅鍐呭锛� " + hookParam); - dynamicTask.stop(streamAuthorityInfo.getCallId()); - OnRecordMp4HookParam recordMp4HookParam = (OnRecordMp4HookParam)hookParam; - String filePath = recordMp4HookParam.getFile_path(); - DownloadFileInfo downloadFileInfo = getDownloadFilePath(mediaServerItem, filePath); - inviteInfo.getStreamInfo().setDownLoadFilePath(downloadFileInfo); - inviteStreamService.updateInviteInfo(inviteInfo); - callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), downloadFileInfo); - }; - HookSubscribeForRecordMp4 hookSubscribe = HookSubscribeFactory.on_record_mp4(mediaServerId, "rtp", stream); - subscribe.addSubscribe(hookSubscribe, hookEvent); - - // 璁剧疆瓒呮椂锛岃秴鏃剁粨鏉熺洃鍚� - dynamicTask.startDelay(streamAuthorityInfo.getCallId(), ()->{ - logger.info("[褰曞儚涓嬭浇] 鎺ユ敹hook瓒呮椂锛� {}/{}-{}", deviceId, channelId, stream); - subscribe.removeSubscribe(hookSubscribe); - callback.run(ErrorCode.ERROR100.getCode(), "鎺ユ敹hook瓒呮椂", null); - }, 10000); - } } private DownloadFileInfo getDownloadFilePath(MediaServerItem mediaServerItem, String filePath) { diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java index abf6df4..4974209 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.vmanager.bean; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "娴佷俊鎭�") @@ -93,6 +94,9 @@ @Schema(description = "缁撴潫鏃堕棿") private String endTime; + @Schema(description = "鏂囦欢涓嬭浇鍦板潃锛堝綍鍍忎笅杞戒娇鐢級") + private DownloadFileInfo downLoadFilePath; + private double progress; public StreamContent(StreamInfo streamInfo) { @@ -170,6 +174,10 @@ this.startTime = streamInfo.getStartTime(); this.endTime = streamInfo.getEndTime(); this.progress = streamInfo.getProgress(); + + if (streamInfo.getDownLoadFilePath() != null) { + this.downLoadFilePath = streamInfo.getDownLoadFilePath(); + } } public String getApp() { @@ -411,4 +419,12 @@ public void setProgress(double progress) { this.progress = progress; } + + public DownloadFileInfo getDownLoadFilePath() { + return downLoadFilePath; + } + + public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) { + this.downLoadFilePath = downLoadFilePath; + } } 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 bf8f78b..7c33708 100755 --- 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 @@ -212,32 +212,4 @@ } return new StreamContent(downLoadInfo); } - - @Operation(summary = "鑾峰彇鍘嗗彶濯掍綋涓嬭浇鏂囦欢鍦板潃") - @Parameter(name = "deviceId", description = "璁惧鍥芥爣缂栧彿", required = true) - @Parameter(name = "channelId", description = "閫氶亾鍥芥爣缂栧彿", required = true) - @Parameter(name = "stream", description = "娴両D", required = true) - @GetMapping("/download/file/path/{deviceId}/{channelId}/{stream}") - public DeferredResult<WVPResult<DownloadFileInfo>> getDownloadFilePath(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { - - DeferredResult<WVPResult<DownloadFileInfo>> result = new DeferredResult<>(); - - result.onTimeout(()->{ - WVPResult<DownloadFileInfo> wvpResult = new WVPResult<>(); - wvpResult.setCode(ErrorCode.ERROR100.getCode()); - wvpResult.setMsg("timeout"); - result.setResult(wvpResult); - }); - - playService.getFilePath(deviceId, channelId, stream, (code, msg, data)->{ - WVPResult<DownloadFileInfo> wvpResult = new WVPResult<>(); - wvpResult.setCode(code); - wvpResult.setMsg(msg); - wvpResult.setData(data); - result.setResult(wvpResult); - }); - - - return result; - } } diff --git a/web_src/build/webpack.dev.conf.js b/web_src/build/webpack.dev.conf.js index ad7c530..1bebcce 100755 --- a/web_src/build/webpack.dev.conf.js +++ b/web_src/build/webpack.dev.conf.js @@ -10,7 +10,6 @@ const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') const portfinder = require('portfinder') -const HOST = process.env.HOST const PORT = process.env.PORT && Number(process.env.PORT) const devWebpackConfig = merge(baseWebpackConfig, { @@ -31,9 +30,8 @@ hot: true, contentBase: false, // since we use CopyWebpackPlugin. compress: true, - host: HOST || config.dev.host, - // host:'127.0.0.1', - port: PORT || config.dev.port, + host: config.dev.host, + port: config.dev.port, open: config.dev.autoOpenBrowser, overlay: config.dev.errorOverlay ? { warnings: false, errors: true } diff --git a/web_src/src/components/dialog/recordDownload.vue b/web_src/src/components/dialog/recordDownload.vue index dcecc28..c78cd1c 100755 --- a/web_src/src/components/dialog/recordDownload.vue +++ b/web_src/src/components/dialog/recordDownload.vue @@ -38,7 +38,6 @@ streamInfo: null, taskId: null, getProgressRun: false, - getProgressForFileRun: false, timer: null, downloadFile: null, @@ -61,7 +60,7 @@ return; } if (this.percentage == 100 ) { - this.getFileDownload(); + return; } setTimeout( ()=>{ @@ -74,13 +73,21 @@ method: 'get', url: `/api/gb_record/download/progress/${this.deviceId}/${this.channelId}/${this.stream}` }).then((res)=> { - console.log(res) if (res.data.code === 0) { this.streamInfo = res.data.data; if (parseFloat(res.data.progress) == 1) { this.percentage = 100; }else { this.percentage = (parseFloat(res.data.data.progress)*100).toFixed(1); + } + if (this.streamInfo.downLoadFilePath) { + if (location.protocol === "https:") { + this.downloadFile = this.streamInfo.downLoadFilePath.httpsPath; + }else { + this.downloadFile = this.streamInfo.downLoadFilePath.httpPath; + } + this.getProgressRun = false; + this.downloadFileClientEvent() } if (callback)callback(); }else { @@ -107,24 +114,11 @@ } 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', @@ -133,74 +127,20 @@ if (callback) callback(res) }); }, - getFileDownload: function (){ - this.$axios({ - method: 'get', - url:`/api/cloud/record/task/add`, - params: { - app: this.app, - stream: this.stream, - mediaServerId: this.mediaServerId, - startTime: null, - endTime: null, - } - }).then((res) =>{ - if (res.data.code === 0 ) { - // 鏌ヨ杩涘害 - 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:`/api/cloud/record/task/list`, - params: { - mediaServerId: this.mediaServerId, - taskId: this.taskId, - isEnd: true, - } - }).then((res) => { - console.log(res) - if (res.data.code === 0) { - if (res.data.data.length === 0){ - this.percentage = 0 - // 寰�寰�鍦ㄥ娆¤姹傚悗锛堝疄楠屼簲鍒嗛挓鐨勮棰戞槸涓夋璇锋眰锛夛紝鎵嶄細杩斿洖鏁版嵁锛岀涓�娆¤姹傞�氬父鏄繑鍥炵┖鏁扮粍 - if (callback)callback() - return - } - // res.data.data搴旀槸鏁扮粍绫诲瀷 - this.percentage = parseFloat(res.data.data[0].percentage)*100 - if (res.data.data[0].percentage === '1') { - this.getProgressForFileRun = false; - this.downloadFile = res.data.data[0].downloadFile - this.title = "鏂囦欢澶勭悊瀹屾垚锛岀偣鍑绘寜鎵笅杞�" - // window.open(res.data.data[0].downloadFile) - }else { - if (callback)callback() - } - } - }).catch(function (error) { - console.log(error); - }); - }, downloadFileClientEvent: function (){ - window.open(this.downloadFile ) + // window.open(this.downloadFile ) + + let x = new XMLHttpRequest(); + x.open("GET", this.downloadFile, true); + x.responseType = 'blob'; + x.onload=(e)=> { + let url = window.URL.createObjectURL(x.response) + let a = document.createElement('a'); + a.href = url + a.download = this.deviceId + "-" + this.channelId + ".mp4"; + a.click() + } + x.send(); } }, destroyed() { -- Gitblit v1.8.0