From 170ee55bd1f0858fdbad3147a72c0f185d49a9a6 Mon Sep 17 00:00:00 2001 From: zhangzengfei <zhangzengfei@smartai.com> Date: 星期四, 10 三月 2022 11:02:01 +0800 Subject: [PATCH] cameraPlayer 添加h265b播放功能 --- src/components/wasmPlayer/wasm/player.js | 108 ++-- src/pages/cameraPlayer/index/App.vue | 24 src/components/wasmPlayer/wasm/pcm-player.js | 412 ++++++++--------- src/components/wasmPlayer/wasm/webgl.js | 114 +--- src/components/wasmPlayer/index.vue | 435 ++++++++++-------- src/components/player/index.vue | 251 +++++----- 6 files changed, 663 insertions(+), 681 deletions(-) diff --git a/src/components/player/index.vue b/src/components/player/index.vue index a1757a3..5962311 100644 --- a/src/components/player/index.vue +++ b/src/components/player/index.vue @@ -9,11 +9,11 @@ </div> </template> <script> -import Wfs from "./wfs"; -import VideoRuleData from "@/Pool/VideoRuleData"; -import TreeDataPool from "@/Pool/TreeData"; -import { getAllPolygon } from "@/api/polygon"; -import polygonCanvas from "@/components/canvas"; +import Wfs from "./wfs" +import VideoRuleData from "@/Pool/VideoRuleData" +import TreeDataPool from "@/Pool/TreeData" +import { getAllPolygon } from "@/api/polygon" +import polygonCanvas from "@/components/canvas" export default { name: "CameraPlayer", props: { @@ -76,35 +76,33 @@ canvasWidth: 0, canvasHeight: 0, algoDataSocket: null - }; + } }, watch: { - rtspUrl: function (newVal, oldVal) { + rtspUrl: function(newVal, oldVal) { if (newVal !== oldVal) { if (this.wfs.config) { - this.wfs.destroy(); + this.wfs.destroy() !!this.algoDataSocket && this.algoDataSocket.close() } this.$nextTick(() => { - this.clickStart(); - }); + this.clickStart() + }) } } }, mounted() { - this.clickStart(); + this.clickStart() this.$nextTick(() => { - this.canvas = this.$refs.areaCanvas; - this.ctx = this.canvas.getContext("2d"); - this.ctx.lineWidth = 1; - this.initArea(); - + this.canvas = this.$refs.areaCanvas + this.ctx = this.canvas.getContext("2d") + this.ctx.lineWidth = 1 + this.initArea() }) }, beforeDestroy() { - this.wfs.destroy(); - this.wfsId = ""; - + !!this.wfs && this.wfs.destroy() + this.wfsId = "" !!this.algoDataSocket && this.algoDataSocket.close() }, methods: { @@ -116,87 +114,86 @@ if (this.wfs.websocketLoader && this.wfs.websocketLoader.client) { if (this.wfs.websocketLoader.client.disconnected) { - this.clickStart(); + this.clickStart() console.log("瀹炴椂瑙嗛宸叉柇寮�锛屾鍦ㄩ噸杩�") return } } - let _this = this; + let _this = this setTimeout(() => { _this.checkConnect(id) }, 10000) }, clickStart() { if (this.rtspUrl == "") { - return; + return } - let cameraId = this.cameraID; + let cameraId = this.cameraID if (cameraId == "") { - cameraId = this.getUuid(); + cameraId = this.getUuid() } if (Wfs.isSupported()) { - let wsAddr = this.wsAddr; + let wsAddr = this.wsAddr let cameraInfo = { cameraID: cameraId, rtspUrl: this.rtspUrl, isRunning: this.isRunning, isGb28181: this.isGb - }; + } // let camera = document.getElementById(this.cameraID); - let camera = this.$refs.videoPlayer; - this.wfs = new Wfs(); - let randomId = this.getUuid(); - this.wfsId = randomId; - this.wfs.attachMedia(camera, "chX", "H264Raw", wsAddr, cameraInfo); + let camera = this.$refs.videoPlayer + this.wfs = new Wfs() + let randomId = this.getUuid() + this.wfsId = randomId + this.wfs.attachMedia(camera, "chX", "H264Raw", wsAddr, cameraInfo) this.checkConnect(randomId) } }, getUuid() { - var s = []; - var hexDigits = "0123456789abcdefghijkopqrst"; + var s = [] + var hexDigits = "0123456789abcdefghijkopqrst" for (var i = 0; i < 36; i++) { - s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1) } - s[14] = "4"; //聽bits聽12-15聽of聽the聽time_hi_and_version聽field聽to聽0010 - s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); //聽bits聽6-7聽of聽the聽clock_seq_hi_and_reserved聽to聽01 - s[8] = s[13] = s[18] = s[23] = "-"; - var uuid = s.join(""); - return uuid; + s[14] = "4" //聽bits聽12-15聽of聽the聽time_hi_and_version聽field聽to聽0010 + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1) //聽bits聽6-7聽of聽the聽clock_seq_hi_and_reserved聽to聽01 + s[8] = s[13] = s[18] = s[23] = "-" + var uuid = s.join("") + return uuid }, fullScreen() { - this.$refs.videoPlayer.webkitRequestFullScreen(); + this.$refs.videoPlayer.webkitRequestFullScreen() }, // 鍥炴樉cavas鏁版嵁 // 鐐瑰嚮閫変腑鍙樿壊 灏嗗綋鍓嶉〉闈㈡墍鏈夎矾寰勯噸缁樺垽鏂綋鍓嶉紶鏍囩殑鍧愭爣鍦ㄥ摢涓浘褰㈠唴 濡傛灉涓嶄紶鍧愭爣鍙傛暟灏辨槸鍥炴樉鐨勬柟娉� clickSelect(e) { - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); - let _this = this; // 闆嗗悎涓亶鍘嗛渶瑕佸皢this杞瓨涓�涓嬩娇鐢� - _this.canvasData.line.forEach(function (v, i) { - _this.ctx.strokeStyle = "yellow"; - _this.ctx.beginPath(); - _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion); - _this.ctx.lineTo(v.location[1].x / _this.showProportion, v.location[1].y / _this.showProportion); - _this.ctx.stroke(); - _this.canvas.style.cursor = "default"; - }); - _this.canvasData.rect.forEach(function (v, i) { - _this.ctx.strokeStyle = "yellow"; - _this.ctx.beginPath(); - _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion); - _this.ctx.lineTo(v.location[1].x / _this.showProportion, v.location[1].y / _this.showProportion); - _this.ctx.lineTo(v.location[2].x / _this.showProportion, v.location[2].y / _this.showProportion); - _this.ctx.lineTo(v.location[3].x / _this.showProportion, v.location[3].y / _this.showProportion); - _this.ctx.lineTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion); - _this.ctx.stroke(); - _this.canvas.style.cursor = "default"; - - }); - _this.canvasData.arrow.forEach(function (v, i) { - _this.ctx.strokeStyle = "yellow"; + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + let _this = this // 闆嗗悎涓亶鍘嗛渶瑕佸皢this杞瓨涓�涓嬩娇鐢� + _this.canvasData.line.forEach(function(v, i) { + _this.ctx.strokeStyle = "yellow" + _this.ctx.beginPath() + _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion) + _this.ctx.lineTo(v.location[1].x / _this.showProportion, v.location[1].y / _this.showProportion) + _this.ctx.stroke() + _this.canvas.style.cursor = "default" + }) + _this.canvasData.rect.forEach(function(v, i) { + _this.ctx.strokeStyle = "yellow" + _this.ctx.beginPath() + _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion) + _this.ctx.lineTo(v.location[1].x / _this.showProportion, v.location[1].y / _this.showProportion) + _this.ctx.lineTo(v.location[2].x / _this.showProportion, v.location[2].y / _this.showProportion) + _this.ctx.lineTo(v.location[3].x / _this.showProportion, v.location[3].y / _this.showProportion) + _this.ctx.lineTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion) + _this.ctx.stroke() + _this.canvas.style.cursor = "default" + }) + _this.canvasData.arrow.forEach(function(v, i) { + _this.ctx.strokeStyle = "yellow" _this.drawArrow( _this.ctx, v.location[0].x / _this.showProportion, @@ -206,25 +203,23 @@ 20, 30, "yellow" - ); - _this.canvas.style.cursor = "default"; - - }); - _this.canvasData.polygon.forEach(function (v, i) { + ) + _this.canvas.style.cursor = "default" + }) + _this.canvasData.polygon.forEach(function(v, i) { if (v.location.length === 0) { - return; + return } - _this.ctx.strokeStyle = "yellow"; - _this.ctx.beginPath(); - _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportionY); + _this.ctx.strokeStyle = "yellow" + _this.ctx.beginPath() + _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportionY) for (let i = 1; i < v.location.length; i++) { - _this.ctx.lineTo(v.location[i].x / _this.showProportion, v.location[i].y / _this.showProportionY); + _this.ctx.lineTo(v.location[i].x / _this.showProportion, v.location[i].y / _this.showProportionY) } - _this.ctx.closePath(); - _this.ctx.stroke(); - _this.canvas.style.cursor = "default"; - - }); + _this.ctx.closePath() + _this.ctx.stroke() + _this.canvas.style.cursor = "default" + }) }, // 绠ご缁樺埗鍑芥暟 @@ -241,68 +236,68 @@ // width = typeof width !== "undefined" ? width : 1; // color = typeof color !== "undefined" ? color : "yellow"; // 璁$畻鍚勮搴﹀拰瀵瑰簲鐨凱2,P3鍧愭爣 - let angle = (Math.atan2(fromY - toY, fromX - toX) * 180) / Math.PI; - let angle1 = ((angle + theta) * Math.PI) / 180; - let angle2 = ((angle - theta) * Math.PI) / 180; - let topX = headlen * Math.cos(angle1); - let topY = headlen * Math.sin(angle1); - let botX = headlen * Math.cos(angle2); - let botY = headlen * Math.sin(angle2); + let angle = (Math.atan2(fromY - toY, fromX - toX) * 180) / Math.PI + let angle1 = ((angle + theta) * Math.PI) / 180 + let angle2 = ((angle - theta) * Math.PI) / 180 + let topX = headlen * Math.cos(angle1) + let topY = headlen * Math.sin(angle1) + let botX = headlen * Math.cos(angle2) + let botY = headlen * Math.sin(angle2) - ctx.save(); - ctx.beginPath(); - let arrowX = fromX - topX; - let arrowY = fromY - topY; - ctx.moveTo(arrowX, arrowY); - ctx.moveTo(fromX, fromY); - ctx.lineTo(toX, toY); - arrowX = toX + topX; - arrowY = toY + topY; - ctx.moveTo(arrowX, arrowY); - ctx.lineTo(toX, toY); - arrowX = toX + botX; - arrowY = toY + botY; - ctx.lineTo(arrowX, arrowY); - ctx.strokeStyle = color; - ctx.lineWidth = width; - ctx.stroke(); - ctx.restore(); + ctx.save() + ctx.beginPath() + let arrowX = fromX - topX + let arrowY = fromY - topY + ctx.moveTo(arrowX, arrowY) + ctx.moveTo(fromX, fromY) + ctx.lineTo(toX, toY) + arrowX = toX + topX + arrowY = toY + topY + ctx.moveTo(arrowX, arrowY) + ctx.lineTo(toX, toY) + arrowX = toX + botX + arrowY = toY + botY + ctx.lineTo(arrowX, arrowY) + ctx.strokeStyle = color + ctx.lineWidth = width + ctx.stroke() + ctx.restore() }, // 鍥炴樉鍥惧舰澶囨敞 showRemarks(x, y, remarks) { - this.ctx.moveTo(x, y - 10); // 鍥犱负鏀惧ぇ涔嬪悗鏄痽-20锛屾墍浠ョ缉灏忕増鐨勪负y-10 - this.ctx.fillStyle = "green"; // 璁剧疆濉厖棰滆壊涓虹豢鑹� - this.ctx.font = '10px "寰蒋闆呴粦"'; // 璁剧疆瀛椾綋 - this.ctx.textBaseline = "bottom"; // 璁剧疆瀛椾綋搴曠嚎瀵归綈缁樺埗鍩虹嚎 - this.ctx.textAlign = "left"; // 璁剧疆瀛椾綋瀵归綈鐨勬柟寮� - this.ctx.fillText(remarks, x, y - 10); // 濉厖鏂囧瓧 + this.ctx.moveTo(x, y - 10) // 鍥犱负鏀惧ぇ涔嬪悗鏄痽-20锛屾墍浠ョ缉灏忕増鐨勪负y-10 + this.ctx.fillStyle = "green" // 璁剧疆濉厖棰滆壊涓虹豢鑹� + this.ctx.font = '10px "寰蒋闆呴粦"' // 璁剧疆瀛椾綋 + this.ctx.textBaseline = "bottom" // 璁剧疆瀛椾綋搴曠嚎瀵归綈缁樺埗鍩虹嚎 + this.ctx.textAlign = "left" // 璁剧疆瀛椾綋瀵归綈鐨勬柟寮� + this.ctx.fillText(remarks, x, y - 10) // 濉厖鏂囧瓧 }, getCanvasData(data) { - let polyon = { ...data }; - polyon.camera_id = this.Camera.cameraId; - savePolygon(polyon).then(rsp => { - this.Camera.getPolygon(); - this.Camera.getCameraTask(); - }); + let polyon = { ...data } + polyon.camera_id = this.Camera.cameraId + savePolygon(polyon).then((rsp) => { + this.Camera.getPolygon() + this.Camera.getCameraTask() + }) }, setWidthHeight() { - this.canvasWidth = this.$refs.videoPlayer.offsetWidth; - this.canvasHeight = this.$refs.videoPlayer.offsetHeight; + this.canvasWidth = this.$refs.videoPlayer.offsetWidth + this.canvasHeight = this.$refs.videoPlayer.offsetHeight console.log(this.canvasWidth, this.canvasHeight) }, async initArea() { - console.log('init') - const res = await getAllPolygon({ cameraId: this.TreeDataPool.selectedNode.id }); - this.canvasData.line = res.data.line; - this.canvasData.rect = res.data.rect; - this.canvasData.arrow = res.data.arrow; - this.canvasData.polygon = res.data.polygon; + console.log("init") + const res = await getAllPolygon({ cameraId: this.TreeDataPool.selectedNode.id }) + this.canvasData.line = res.data.line + this.canvasData.rect = res.data.rect + this.canvasData.arrow = res.data.arrow + this.canvasData.polygon = res.data.polygon console.log(this.canvasData) - this.clickSelect(this.canvasData); + this.clickSelect(this.canvasData) }, initAlgoDataWebScoket() { - if (typeof (WebSocket) === "undefined") { + if (typeof WebSocket === "undefined") { console.log("error,鎮ㄧ殑娴忚鍣ㄤ笉鏀寔socket") } else { this.algoDataSocket = new WebSocket() @@ -312,13 +307,13 @@ this.algoDataSocket.onerror = () => { console.log("杩炴帴閿欒") } - this.algoDataSocket.onmessage = msg => { + this.algoDataSocket.onmessage = (msg) => { console.log(msg) } } } } -}; +} </script> <style lang="scss"> diff --git a/src/components/wasmPlayer/index.vue b/src/components/wasmPlayer/index.vue index 447a4a5..9c0e2c7 100644 --- a/src/components/wasmPlayer/index.vue +++ b/src/components/wasmPlayer/index.vue @@ -1,58 +1,31 @@ <template> <div class="video-player"> - <canvas - v-show="showArea" - id="area-canvas" - ref="areaCanvas" - width="960" - height="540" - ></canvas> + <canvas v-show="showArea" id="area-canvas" ref="areaCanvas" width="960" height="540"></canvas> <div class="container" id="videoPlayer"> <div class="canvasDiv"> - <div class="loadEffect" id="loading" style="display:none;"> - <span></span> - <span></span> - <span></span> - <span></span> - <span></span> - <span></span> - <span></span> - <span></span> - </div> - <canvas - ref="playCanvas" - id="paly-canvas" - width="960" - height="540" - ></canvas> + <div + v-loading="videoLoading" + element-loading-background="rgba(0, 0, 0, 0.8)" + style="position: unset !important" + ></div> + <canvas ref="playCanvas" id="paly-canvas" width="960" height="540"></canvas> </div> + <transition name="fade"> + <div class="popuptext" id="myPopup" v-if="fullScreenNotice">璧勬簮涓嬭浇涓�,璇风◢鍚�...</div> + </transition> + <!-- 鎺у埗鏉� --> - <section - class="jsmodern-video-panel" - :style="{ display: isStream ? 'none' : 'block' }" - > + <section class="jsmodern-video-panel" :style="{ display: isStream ? 'none' : 'block' }"> <!-- 鎾斁/鏆傚仠 --> - <b - :class=" - playerStatus == 0 ? 'jsmodern-video-play' : 'jsmodern-video-pause' - " - @click="playVideo" - ></b> + <b :class="playerStatus == 0 ? 'jsmodern-video-play' : 'jsmodern-video-pause'" @click="playVideo"></b> <!-- 鏃堕棿 --> - <span class="jsmodern-video-start" ref="timeLabel" - >00:00:00/00:00:00</span - > + <span class="jsmodern-video-start" ref="timeLabel">00:00:00/00:00:00</span> <!-- 杩涘害鏉� --> <div> - <input - class="jsmodern-video-linebox" - ref="timeTrack" - type="range" - value="0" - /> + <input class="jsmodern-video-linebox" ref="timeTrack" type="range" value="0" /> </div> <!-- 澹伴煶 --> @@ -63,18 +36,15 @@ </div> --> <!-- 鍏ㄥ睆 --> - <b - class="jsmodern-video-fullin" - @click="fullScreen" - :disable="false" - ></b> + <b class="jsmodern-video-fullin" @click="fullScreen" :disable="false"></b> + + <!-- 涓嬭浇 --> + <i class="el-icon-download jsmodern-video-download" @click="downLoad"></i> </section> <!-- 澶ф挱鏀炬寜閽� --> <div v-show="!isStream"> - <span class="video-btn" v-show="playerStatus == 0" @click="playVideo" - ><img src="./wasm/img/bo1.png" - /></span> + <span class="video-btn" v-show="playerStatus == 0" @click="playVideo"><img src="./wasm/img/bo1.png"/></span> <!-- 涓婁竴涓� --> <span class="video-prve" v-show="showPrev"> @@ -85,6 +55,13 @@ <span class="video-next" v-show="showNext"> <i class="el-icon-arrow-right" @click="playNext"></i> </span> + + <!-- 鎾斁澶辫触 --> + <span class="video-error" v-show="playerStatus == -1"> + <i class="el-icon-warning-outline" style="font-size:40px"></i> + <br /> + 瑙嗛鍔犺浇澶辫触 鏃犳晥鐨勮棰戝湴鍧� + </span> </div> </div> </div> @@ -94,72 +71,74 @@ /* 2021.09.22 娣诲姞澶氫釜褰曞儚鍦板潃鐨勫鐞�, 涓庡綍鍍忔ā鍧楃害瀹�, 鐢� || 鍒嗗壊澶氫釜瑙嗛鍦板潃, 鍓嶇澶勭悊鎾斁. */ -import { Player } from './wasm/player' -import VideoRuleData from '@/Pool/VideoRuleData' -import { getAllPolygon } from '@/api/polygon' +import { Player } from "./wasm/player" +import { getAllPolygon } from "@/api/polygon" export default { - name: 'CameraPlayer', + name: "CameraPlayer", props: { videoUrl: { type: String, // default: "ws://192.168.1.182:10101/ws" - default: `${location.protocol === 'https' ? 'wss' : 'ws'}://${ - location.host - }/ws`, + default: `${location.protocol === "https" ? "wss" : "ws"}://${location.host}/ws` }, cameraName: { type: String, - default: '', + default: "" }, cameraID: { type: String, - default: 'C4668FD0-3CAE-C31F-C21E-28B7001243C4', + default: "C4668FD0-3CAE-C31F-C21E-28B7001243C4" }, rtspUrl: { type: String, - default: - 'rtsp://admin:a1234567@192.168.1.201:554/h264/ch1/main/av_stream', + default: "rtsp://admin:a1234567@192.168.1.201:554/h264/ch1/main/av_stream" }, isRunning: { type: Boolean, - default: false, + default: false }, isGb: { type: Boolean, - default: false, + default: false }, showArea: { type: Boolean, - default: false, + default: false }, isStream: { type: Boolean, - default: true, + default: true }, + autoPlay: { + type: Boolean, + default: false + }, + preload: { + type: Boolean, + default: true + } }, computed: { poster() { - return '/images/player/player_poster.gif?t=' + Math.random() + return "/images/player/player_poster.gif?t=" + Math.random() }, showPrev() { return this.playerIndex - 1 >= 0 }, showNext() { return this.playerIndex + 1 < this.videoUrls.length - }, + } }, data() { return { player: null, playerId: 0, - Camera: new VideoRuleData(), - showCanvas: true, canvasData: { line: [], rect: [], // {id:'uuid', name: '鐭╁舰1', location: [{ x: 20, y: 30 }, { x: 20, y: 60 }, { x: 100, y: 60 }, { x: 100, y: 30 }] } arrow: [], - polygon: [], + polygon: [] }, //showProportion: 3.2, //showProportionY: 3.58, @@ -175,6 +154,11 @@ playerStatus: 0, videoUrls: [], playerIndex: 0, + isEmptyUrl: false, + videoLoading: false, + loadUrl: "", + isFullScreen: false, + fullScreenNotice: false } }, watch: { @@ -188,107 +172,65 @@ this.playVideo() }) } - }, + } }, mounted() { this.player = new Player() - - // 褰曞儚URL澶勭悊, 鍙兘瀛樺湪澶氫釜褰曞儚鍦板潃 - if (!this.isStream) { - this.videoUrls = this.videoUrl.split('||') - } + this.player.preload = this.preload + this.player.statusCallback = this.setPlayerStatus if (this.isStream) { this.playVideo() this.$nextTick(() => { this.canvas = this.$refs.areaCanvas - this.ctx = this.canvas.getContext('2d') + this.ctx = this.canvas.getContext("2d") this.ctx.lineWidth = 1 this.initArea() }) + } else { + // 褰曞儚URL澶勭悊, 鍙兘瀛樺湪澶氫釜褰曞儚鍦板潃 + if (this.videoUrl === "") { + this.playerStatus = -1 + return + } + + this.videoUrls = this.videoUrl.split("||") + + if (this.autoPlay || this.preload) { + this.playVideo() + } } }, beforeDestroy() { this.player.stop() }, methods: { - checkConnect(id) { - if (id !== this.playerId) { - return - } - - if (this.wfs.websocketLoader && this.wfs.websocketLoader.client) { - if (this.wfs.websocketLoader.client.disconnected) { - this.playVideo() - console.log('瀹炴椂瑙嗛宸叉柇寮�锛屾鍦ㄩ噸杩�') - return - } - } - - let _this = this - setTimeout(() => { - _this.checkConnect(id) - }, 10000) - }, - getUuid() { - var s = [] - var hexDigits = '0123456789abcdefghijkopqrst' - for (var i = 0; i < 36; i++) { - s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1) - } - s[14] = '4' //聽bits聽12-15聽of聽the聽time_hi_and_version聽field聽to聽0010 - s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1) //聽bits聽6-7聽of聽the聽clock_seq_hi_and_reserved聽to聽01 - s[8] = s[13] = s[18] = s[23] = '-' - var uuid = s.join('') - return uuid - }, // 鍥炴樉cavas鏁版嵁 // 鐐瑰嚮閫変腑鍙樿壊 灏嗗綋鍓嶉〉闈㈡墍鏈夎矾寰勯噸缁樺垽鏂綋鍓嶉紶鏍囩殑鍧愭爣鍦ㄥ摢涓浘褰㈠唴 濡傛灉涓嶄紶鍧愭爣鍙傛暟灏辨槸鍥炴樉鐨勬柟娉� clickSelect(e) { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) let _this = this // 闆嗗悎涓亶鍘嗛渶瑕佸皢this杞瓨涓�涓嬩娇鐢� _this.canvasData.line.forEach(function(v, i) { - _this.ctx.strokeStyle = 'yellow' + _this.ctx.strokeStyle = "yellow" _this.ctx.beginPath() - _this.ctx.moveTo( - v.location[0].x / _this.showProportion, - v.location[0].y / _this.showProportion - ) - _this.ctx.lineTo( - v.location[1].x / _this.showProportion, - v.location[1].y / _this.showProportion - ) + _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion) + _this.ctx.lineTo(v.location[1].x / _this.showProportion, v.location[1].y / _this.showProportion) _this.ctx.stroke() - _this.canvas.style.cursor = 'default' + _this.canvas.style.cursor = "default" }) _this.canvasData.rect.forEach(function(v, i) { - _this.ctx.strokeStyle = 'yellow' + _this.ctx.strokeStyle = "yellow" _this.ctx.beginPath() - _this.ctx.moveTo( - v.location[0].x / _this.showProportion, - v.location[0].y / _this.showProportion - ) - _this.ctx.lineTo( - v.location[1].x / _this.showProportion, - v.location[1].y / _this.showProportion - ) - _this.ctx.lineTo( - v.location[2].x / _this.showProportion, - v.location[2].y / _this.showProportion - ) - _this.ctx.lineTo( - v.location[3].x / _this.showProportion, - v.location[3].y / _this.showProportion - ) - _this.ctx.lineTo( - v.location[0].x / _this.showProportion, - v.location[0].y / _this.showProportion - ) + _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion) + _this.ctx.lineTo(v.location[1].x / _this.showProportion, v.location[1].y / _this.showProportion) + _this.ctx.lineTo(v.location[2].x / _this.showProportion, v.location[2].y / _this.showProportion) + _this.ctx.lineTo(v.location[3].x / _this.showProportion, v.location[3].y / _this.showProportion) + _this.ctx.lineTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportion) _this.ctx.stroke() - _this.canvas.style.cursor = 'default' + _this.canvas.style.cursor = "default" }) _this.canvasData.arrow.forEach(function(v, i) { - _this.ctx.strokeStyle = 'yellow' + _this.ctx.strokeStyle = "yellow" _this.drawArrow( _this.ctx, v.location[0].x / _this.showProportion, @@ -297,44 +239,28 @@ v.location[1].y / _this.showProportion, 20, 30, - 'yellow' + "yellow" ) - _this.canvas.style.cursor = 'default' + _this.canvas.style.cursor = "default" }) _this.canvasData.polygon.forEach(function(v, i) { if (v.location.length === 0) { return } - _this.ctx.strokeStyle = 'yellow' + _this.ctx.strokeStyle = "yellow" _this.ctx.beginPath() - _this.ctx.moveTo( - v.location[0].x / _this.showProportion, - v.location[0].y / _this.showProportionY - ) + _this.ctx.moveTo(v.location[0].x / _this.showProportion, v.location[0].y / _this.showProportionY) for (let i = 1; i < v.location.length; i++) { - _this.ctx.lineTo( - v.location[i].x / _this.showProportion, - v.location[i].y / _this.showProportionY - ) + _this.ctx.lineTo(v.location[i].x / _this.showProportion, v.location[i].y / _this.showProportionY) } _this.ctx.closePath() _this.ctx.stroke() - _this.canvas.style.cursor = 'default' + _this.canvas.style.cursor = "default" }) }, // 绠ご缁樺埗鍑芥暟 - drawArrow( - ctx, - fromX, - fromY, - toX, - toY, - theta = 30, - headlen = 10, - width = 1, - color = 'yellow' - ) { + drawArrow(ctx, fromX, fromY, toX, toY, theta = 30, headlen = 10, width = 1, color = "yellow") { // ctx锛欳anvas缁樺浘鐜 // fromX, fromY锛氳捣鐐瑰潗鏍囷紙涔熷彲浠ユ崲鎴恜1锛屽彧涓嶈繃瀹冩槸涓�涓暟缁勶級 // toX, toY锛氱粓鐐瑰潗鏍� (涔熷彲浠ユ崲鎴恜2锛屽彧涓嶈繃瀹冩槸涓�涓暟缁�) @@ -378,32 +304,25 @@ // 鍥炴樉鍥惧舰澶囨敞 showRemarks(x, y, remarks) { this.ctx.moveTo(x, y - 10) // 鍥犱负鏀惧ぇ涔嬪悗鏄痽-20锛屾墍浠ョ缉灏忕増鐨勪负y-10 - this.ctx.fillStyle = 'green' // 璁剧疆濉厖棰滆壊涓虹豢鑹� + this.ctx.fillStyle = "green" // 璁剧疆濉厖棰滆壊涓虹豢鑹� this.ctx.font = '10px "寰蒋闆呴粦"' // 璁剧疆瀛椾綋 - this.ctx.textBaseline = 'bottom' // 璁剧疆瀛椾綋搴曠嚎瀵归綈缁樺埗鍩虹嚎 - this.ctx.textAlign = 'left' // 璁剧疆瀛椾綋瀵归綈鐨勬柟寮� + this.ctx.textBaseline = "bottom" // 璁剧疆瀛椾綋搴曠嚎瀵归綈缁樺埗鍩虹嚎 + this.ctx.textAlign = "left" // 璁剧疆瀛椾綋瀵归綈鐨勬柟寮� this.ctx.fillText(remarks, x, y - 10) // 濉厖鏂囧瓧 }, - getCanvasData(data) { - let polyon = { ...data } - polyon.camera_id = this.Camera.cameraId - savePolygon(polyon).then((rsp) => { - this.Camera.getPolygon() - this.Camera.getCameraTask() - }) - }, + setWidthHeight() { this.canvasWidth = this.$refs.videoPlayer.offsetWidth this.canvasHeight = this.$refs.videoPlayer.offsetHeight console.log(this.canvasWidth, this.canvasHeight) }, async initArea() { - if (!this.showCanvas) { + if (!this.showArea) { return } const res = await getAllPolygon({ - cameraId: this.TreeDataPool.selectedNode.id, + cameraId: this.TreeDataPool.selectedNode.id }) this.canvasData.line = res.data.line this.canvasData.rect = res.data.rect @@ -412,15 +331,15 @@ this.clickSelect(this.canvasData) }, initAlgoDataWebScoket() { - if (typeof WebSocket === 'undefined') { - console.log('error,鎮ㄧ殑娴忚鍣ㄤ笉鏀寔socket') + if (typeof WebSocket === "undefined") { + console.log("error,鎮ㄧ殑娴忚鍣ㄤ笉鏀寔socket") } else { this.algoDataSocket = new WebSocket() this.algoDataSocket.onopen = () => { - console.log('socket杩炴帴鎴愬姛') + console.log("socket杩炴帴鎴愬姛") } this.algoDataSocket.onerror = () => { - console.log('杩炴帴閿欒') + console.log("杩炴帴閿欒") } this.algoDataSocket.onmessage = (msg) => { console.log(msg) @@ -428,14 +347,14 @@ } }, playVideo() { - if (this.isStream && this.rtspUrl == '') { + if (this.isStream && this.rtspUrl == "") { return } - let payload = '' - let url = '' + let payload = "" + let url = "" if (this.isStream) { - if (this.cameraID == '') { + if (this.cameraID == "") { this.cameraID = this.getUuid() } @@ -443,18 +362,15 @@ cameraID: this.cameraID, rtspUrl: this.rtspUrl, isRunning: this.isRunning, - isGb28181: this.isGb, + isGb28181: this.isGb }) url = this.videoUrl } else { - url = '/httpImage/' + this.videoUrls[this.playerIndex] + url = "/httpImage/" + this.videoUrls[this.playerIndex] } - if (url == '') { - return - } - + this.videoLoading = true if (this.player.hPlayer == 0) { this.player.play( url, @@ -462,19 +378,27 @@ this.isStream, this.$refs.timeTrack, this.$refs.timeLabel, - payload + payload, + () => { + this.videoLoading = false + } ) } else if (this.player.PlayOrPause == 0) { this.player.resume() + this.videoLoading = false } else { this.player.pause() + this.videoLoading = false } this.playerStatus = this.player.PlayOrPause - let randomId = this.getUuid() - this.checkConnect(randomId) - }, + this.loadUrl = url + }, + setPlayerStatus(stat) { + this.videoLoading = false + this.playerStatus = stat + }, stopVideo() { if (this.player.hPlayer == 0) return @@ -482,7 +406,61 @@ }, fullScreen() { - this.player.fullscreen() + if (!this.isFullScreen) { + this.player.fullscreen() + } else { + this.player.exitfullscreen() + } + this.isFullScreen = !this.isFullScreen + }, + + async downLoad() { + if (!this.loadUrl) { + this.$notify.info({ + title: "娑堟伅", + message: "涓嬭浇澶辫触锛屾棤鏁堢殑瑙嗛鍦板潃" + }) + return + } + + if (this.isFullScreen) { + /* const screen = this.player.webglPlayer.canvas.parentNode + var p = document.createElement("p"); + var txt = document.createTextNode("璧勬簮涓嬭浇涓�,璇风◢鍚�..."); + p.appendChild(txt); + p.classList.add("downloadNotice"); + screen.appendChild(p); */ + this.fullScreenNotice = true + setTimeout(() => { + this.fullScreenNotice = false + }, 2000) + } else { + this.$notify.info({ + title: "娑堟伅", + message: `璧勬簮涓嬭浇涓�,璇风◢鍚�...` + }) + } + + let url = "http://" + window.location.host + this.loadUrl + + // let url = "http://localhost:8080/httpImage/192.168.20.189:6700/283,2f49bf283ad7?collection=2021-09-28-DSVAD010120190703-video" + let name = url.substring(url.lastIndexOf("/") + 1) + let responsePromise = await fetch(url) + let blob = await responsePromise.blob() + let objectURL = window.URL.createObjectURL(blob) + let a = document.createElement("a") + a.href = objectURL + a.download = name + a.click() + a.remove() + /* let url = 'http:/'+this.loadUrl.substring(10) + let link = document.createElement("a"); //鍒涘缓a鏍囩 + let name = url.substring(url.lastIndexOf("/") + 1) + link.style.display = "none"; //浣垮叾闅愯棌 + link.href = url; //璧嬩簣鏂囦欢涓嬭浇鍦板潃 + link.setAttribute("download", name); //璁剧疆涓嬭浇灞炴�� 浠ュ強鏂囦欢鍚� + document.body.appendChild(link); //a鏍囩鎻掕嚦椤甸潰涓� + link.click(); //寮哄埗瑙﹀彂a鏍囩浜嬩欢 */ }, playPrev() { @@ -495,9 +473,8 @@ this.playerIndex++ this.player.stop() this.playVideo() - console.log(this.playerIndex, this.videoUrls.length) - }, - }, + } + } } </script> @@ -529,7 +506,7 @@ position: absolute; bottom: 0; left: 0; - z-index: 2147483648; + z-index: 100; width: 100%; height: 40px; line-height: 40px; @@ -554,9 +531,9 @@ background: rgba(255, 255, 255, 0.25); border-radius: 3px; width: 460px; - width: -webkit-calc(100% - 220px); - width: -moz-calc(100% - 220px); - width: calc(100% - 220px); + width: -webkit-calc(100% - 260px); + width: -moz-calc(100% - 260px); + width: calc(100% - 260px); float: left; margin: 19px 0 0 65px; position: relative; @@ -700,6 +677,14 @@ opacity: 0.5; cursor: default; } + + .el-icon-download { + font-size: 24px; + width: 18px; + height: 18px; + margin-top: 7px; + margin-left: -12px; + } } .video-player:hover { @@ -737,4 +722,50 @@ .video-next { right: 0px; } + +.video-error { + position: absolute; + top: 35%; + left: 30%; + font-size: 14px; + color: #fff; +} + +.downloadNotice { + position: absolute; + height: 200px; + width: 200px; + background-color: pink; +} + +.popuptext { + /* display:none; */ + height: 50px; + line-height: 50px; + font-size: 20px; + background-color: #555; + opacity: 0.8; + color: #fff; + text-align: center; + border-radius: 25px; + position: relative; + top: 30px; + z-index: 1; +} + +.fade-enter { + opacity: 0; +} +.fade-enter-active { + transition: opacity 0.5s; +} +.fade-leave-to { + opacity: 0; +} +.fade-leave-active { + transition: opacity 3s; +} +.canvasDiv .el-loading-mask { + z-index: 1000 !important; +} </style> diff --git a/src/components/wasmPlayer/wasm/pcm-player.js b/src/components/wasmPlayer/wasm/pcm-player.js index 2e71f7f..663cf62 100644 --- a/src/components/wasmPlayer/wasm/pcm-player.js +++ b/src/components/wasmPlayer/wasm/pcm-player.js @@ -1,227 +1,193 @@ -export function PCMPlayer(option) -{ - this.init(option); +export function PCMPlayer(option) { + this.init(option) } -PCMPlayer.prototype.init=function(option) -{ - var defaults={ - encoding: '16bitInt', - channels:1, - sampleRate:8000, - flushingTime:1000 - }; - this.option=Object.assign({},defaults,option); - this.samples=new Float32Array(); - this.flush=this.flush.bind(this); - this.interval=setInterval(this.flush,this.option.flushingTime); - this.maxValue=this.getMaxValue(); - this.typedArray=this.getTypedArray(); - this.createContext(); -}; - -PCMPlayer.prototype.getMaxValue=function() -{ - var encodings={ - '8bitInt': 128, - '16bitInt':32768, - '32bitInt':2147483648, - '32bitFloat':1 - } - - return encodings[this.option.encoding]?encodings[this.option.encoding]:encodings['16bitInt']; -}; - -PCMPlayer.prototype.getTypedArray=function() -{ - var typedArrays={ - '8bitInt': Int8Array, - '16bitInt':Int16Array, - '32bitInt':Int32Array, - '32bitFloat':Float32Array - } - - return typedArrays[this.option.encoding]?typedArrays[this.option.encoding]:typedArrays['16bitInt']; -}; - -PCMPlayer.prototype.createContext=function() -{ - this.audioCtx=new (window.AudioContext||window.webkitAudioContext)(); - this.gainNode=this.audioCtx.createGain(); - this.gainNode.gain.value=1; - this.gainNode.connect(this.audioCtx.destination); - this.startTime=this.audioCtx.currentTime; -}; - -PCMPlayer.prototype.isTypedArray=function(data) -{ - return (data.byteLength&&data.buffer&&data.buffer.constructor==ArrayBuffer); -}; - -PCMPlayer.prototype.feed=function(data) -{ - if(!this.isTypedArray(data)) return; - data=this.getFormatedValue(data); - var tmp=new Float32Array(this.samples.length+data.length); - tmp.set(this.samples,0); - tmp.set(data,this.samples.length); - this.samples=tmp; -}; - -PCMPlayer.prototype.getFormatedValue=function(data) -{ - var data=new this.typedArray(data.buffer), - float32=new Float32Array(data.length), - i; - - for(i=0; i<data.length; i++) - { - float32[i]=data[i]/this.maxValue; - } - return float32; -}; - -PCMPlayer.prototype.volume=function(volume) -{ - this.gainNode.gain.value=volume; -}; - -PCMPlayer.prototype.destroy=function() -{ - if(this.interval) - { - clearInterval(this.interval); - } - this.samples=null; - this.audioCtx.close(); - this.audioCtx=null; -}; - -PCMPlayer.prototype.flush=function() -{ - if(!this.samples.length) return; - var bufferSource=this.audioCtx.createBufferSource(), - length=this.samples.length/this.option.channels, - audioBuffer=this.audioCtx.createBuffer(this.option.channels,length,this.option.sampleRate), - audioData, - channel, - offset, - i, - decrement; - - for(channel=0; channel<this.option.channels; channel++) - { - audioData=audioBuffer.getChannelData(channel); - offset=channel; - decrement=50; - for(i=0; i<length; i++) - { - audioData[i]=this.samples[offset]; - /* fadein */ - if(i<50) - { - audioData[i]=(audioData[i]*i)/50; - } - /* fadeout*/ - if(i>=(length-51)) - { - audioData[i]=(audioData[i]*decrement--)/50; - } - offset+=this.option.channels; - } - } - - if(this.startTime<this.audioCtx.currentTime) - { - this.startTime=this.audioCtx.currentTime; - } - //console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration); - bufferSource.buffer=audioBuffer; - bufferSource.connect(this.gainNode); - bufferSource.start(this.startTime); - this.startTime+=audioBuffer.duration; - this.samples=new Float32Array(); -}; - -PCMPlayer.prototype.getTimestamp=function() -{ - if(this.audioCtx) - { - return this.audioCtx.currentTime; - } - else - { - return 0; - } -}; - -PCMPlayer.prototype.play=function(data) -{ - if(!this.isTypedArray(data)) - { - return; - } - - data=this.getFormatedValue(data); - if(!data.length) - { - return; - } - - var bufferSource=this.audioCtx.createBufferSource(), - length=data.length/this.option.channels, - audioBuffer=this.audioCtx.createBuffer(this.option.channels,length,this.option.sampleRate), - audioData, - channel, - offset, - i, - decrement; - - for(channel=0; channel<this.option.channels; channel++) - { - audioData=audioBuffer.getChannelData(channel); - offset=channel; - decrement=50; - for(i=0; i<length; i++) - { - audioData[i]=data[offset]; - /* fadein */ - if(i<50) - { - audioData[i]=(audioData[i]*i)/50; - } - /* fadeout*/ - if(i>=(length-51)) - { - audioData[i]=(audioData[i]*decrement--)/50; - } - offset+=this.option.channels; - } - } - - if(this.startTime<this.audioCtx.currentTime) - { - this.startTime=this.audioCtx.currentTime; - } - //console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration); - bufferSource.buffer=audioBuffer; - bufferSource.connect(this.gainNode); - bufferSource.start(this.startTime); - this.startTime+=audioBuffer.duration; -}; - -PCMPlayer.prototype.pause=function() -{ - if(this.audioCtx.state==='running') - { - this.audioCtx.suspend() - } +PCMPlayer.prototype.init = function(option) { + var defaults = { + encoding: "16bitInt", + channels: 1, + sampleRate: 8000, + flushingTime: 1000 + } + this.option = Object.assign({}, defaults, option) + this.samples = new Float32Array() + this.flush = this.flush.bind(this) + this.interval = setInterval(this.flush, this.option.flushingTime) + this.maxValue = this.getMaxValue() + this.typedArray = this.getTypedArray() + this.createContext() } -PCMPlayer.prototype.resume=function() -{ - if(this.audioCtx.state==='suspended') - { - this.audioCtx.resume() - } -} \ No newline at end of file +PCMPlayer.prototype.getMaxValue = function() { + var encodings = { + "8bitInt": 128, + "16bitInt": 32768, + "32bitInt": 2147483648, + "32bitFloat": 1 + } + + return encodings[this.option.encoding] ? encodings[this.option.encoding] : encodings["16bitInt"] +} + +PCMPlayer.prototype.getTypedArray = function() { + var typedArrays = { + "8bitInt": Int8Array, + "16bitInt": Int16Array, + "32bitInt": Int32Array, + "32bitFloat": Float32Array + } + + return typedArrays[this.option.encoding] ? typedArrays[this.option.encoding] : typedArrays["16bitInt"] +} + +PCMPlayer.prototype.createContext = function() { + this.audioCtx = new (window.AudioContext || window.webkitAudioContext)() + this.gainNode = this.audioCtx.createGain() + this.gainNode.gain.value = 1 + this.gainNode.connect(this.audioCtx.destination) + this.startTime = this.audioCtx.currentTime +} + +PCMPlayer.prototype.isTypedArray = function(data) { + return data.byteLength && data.buffer && data.buffer.constructor == ArrayBuffer +} + +PCMPlayer.prototype.feed = function(data) { + if (!this.isTypedArray(data)) return + data = this.getFormatedValue(data) + var tmp = new Float32Array(this.samples.length + data.length) + tmp.set(this.samples, 0) + tmp.set(data, this.samples.length) + this.samples = tmp +} + +PCMPlayer.prototype.getFormatedValue = function(data) { + var data = new this.typedArray(data.buffer), + float32 = new Float32Array(data.length), + i + + for (i = 0; i < data.length; i++) { + float32[i] = data[i] / this.maxValue + } + return float32 +} + +PCMPlayer.prototype.volume = function(volume) { + this.gainNode.gain.value = volume +} + +PCMPlayer.prototype.destroy = function() { + if (this.interval) { + clearInterval(this.interval) + } + this.samples = null + this.audioCtx.close() + this.audioCtx = null +} + +PCMPlayer.prototype.flush = function() { + if (!this.samples.length) return + var bufferSource = this.audioCtx.createBufferSource(), + length = this.samples.length / this.option.channels, + audioBuffer = this.audioCtx.createBuffer(this.option.channels, length, this.option.sampleRate), + audioData, + channel, + offset, + i, + decrement + + for (channel = 0; channel < this.option.channels; channel++) { + audioData = audioBuffer.getChannelData(channel) + offset = channel + decrement = 50 + for (i = 0; i < length; i++) { + audioData[i] = this.samples[offset] + /* fadein */ + if (i < 50) { + audioData[i] = (audioData[i] * i) / 50 + } + /* fadeout*/ + if (i >= length - 51) { + audioData[i] = (audioData[i] * decrement--) / 50 + } + offset += this.option.channels + } + } + + if (this.startTime < this.audioCtx.currentTime) { + this.startTime = this.audioCtx.currentTime + } + //console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration); + bufferSource.buffer = audioBuffer + bufferSource.connect(this.gainNode) + bufferSource.start(this.startTime) + this.startTime += audioBuffer.duration + this.samples = new Float32Array() +} + +PCMPlayer.prototype.getTimestamp = function() { + if (this.audioCtx) { + return this.audioCtx.currentTime + } else { + return 0 + } +} + +PCMPlayer.prototype.play = function(data) { + if (!this.isTypedArray(data)) { + return + } + + data = this.getFormatedValue(data) + if (!data.length) { + return + } + + var bufferSource = this.audioCtx.createBufferSource(), + length = data.length / this.option.channels, + audioBuffer = this.audioCtx.createBuffer(this.option.channels, length, this.option.sampleRate), + audioData, + channel, + offset, + i, + decrement + + for (channel = 0; channel < this.option.channels; channel++) { + audioData = audioBuffer.getChannelData(channel) + offset = channel + decrement = 50 + for (i = 0; i < length; i++) { + audioData[i] = data[offset] + /* fadein */ + if (i < 50) { + audioData[i] = (audioData[i] * i) / 50 + } + /* fadeout*/ + if (i >= length - 51) { + audioData[i] = (audioData[i] * decrement--) / 50 + } + offset += this.option.channels + } + } + + if (this.startTime < this.audioCtx.currentTime) { + this.startTime = this.audioCtx.currentTime + } + //console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration); + bufferSource.buffer = audioBuffer + bufferSource.connect(this.gainNode) + bufferSource.start(this.startTime) + this.startTime += audioBuffer.duration +} + +PCMPlayer.prototype.pause = function() { + if (this.audioCtx.state === "running") { + this.audioCtx.suspend() + } +} + +PCMPlayer.prototype.resume = function() { + if (this.audioCtx.state === "suspended") { + this.audioCtx.resume() + } +} diff --git a/src/components/wasmPlayer/wasm/player.js b/src/components/wasmPlayer/wasm/player.js index eff828d..787e02c 100644 --- a/src/components/wasmPlayer/wasm/player.js +++ b/src/components/wasmPlayer/wasm/player.js @@ -1,5 +1,5 @@ -import { PCMPlayer } from './pcm-player' -import { WebGLPlayer } from './webgl' +import { PCMPlayer } from "./pcm-player" +import { WebGLPlayer } from "./webgl" export function Player() { this.hPlayer = 0 @@ -10,22 +10,21 @@ this.timeLabel = null this.timeTrack = null this.CurPos = 0 - this.displayDuration = '00:00:00' + this.displayDuration = "00:00:00" this.pcmPlayer = null this.webglPlayer = null this.trackTimer = null + this.loop = false + this.preload = true + this.preloadFlag = 0 + this.statusCallback = (stat) => { + console.log(stat) + } } -Player.prototype.play = function( - url, - canvas, - isStream, - timeTrack, - timeLabel, - payload -) { +Player.prototype.play = function(url, canvas, isStream, timeTrack, timeLabel, payload) { if (this.hPlayer != 0) return this.MediaName = url @@ -42,60 +41,76 @@ This.seek(This.timeTrack.value) } - this.TurboWorker = new Worker('/libs/wasmPlayer/turbo.js') + this.TurboWorker = new Worker("/libs/wasmPlayer/turbo.js") this.hPlayer = 1 this.PlayOrPause = 1 this.TurboWorker.onmessage = function(evt) { switch (evt.data.command) { - case 'initialized': { + case "initialized": { This.TurboWorker.postMessage({ - command: 'play', + command: "play", media_name: url, other: isStream, - payload: payload, + payload: payload }) break } - case 'create_video': { + case "create_video": { This.VideoParam = evt.data.param //{duration:xxx,width:xxx,height:xxx} This.webglPlayer = new WebGLPlayer(This.canvas) if (This.timeTrack) { This.timeTrack.min = 0 This.timeTrack.max = This.VideoParam.duration This.timeTrack.value = 0 - This.displayDuration = This.formatTime( - This.VideoParam.duration / 1000 - ) + This.displayDuration = This.formatTime(This.VideoParam.duration / 1000) } This.startTrackTimer() + + This.statusCallback(0) break } - case 'create_audio': { + case "create_audio": { This.AudioParam = evt.data.param //{channel:Channel,sample_rate:SampleRate} This.pcmPlayer = new PCMPlayer({ - encoding: '16bitInt', + encoding: "16bitInt", channels: This.AudioParam.channel, sampleRate: This.AudioParam.sample_rate, - flushingTime: 5000, + flushingTime: 5000 }) + + This.statusCallback(1) break } - case 'deliver_video': { + case "deliver_video": { + if (!This.isStream && This.preload && This.preloadFlag == 0) { + This.preloadFlag = 1 + This.pause() + This.statusCallback(0) + } + //sample:{time_stamp:xxx,data:xxx} This.CurPos = evt.data.sample.time_stamp - This.webglPlayer.renderFrame( - evt.data.sample.buf, - This.VideoParam.width, - This.VideoParam.height - ) + This.webglPlayer.renderFrame(evt.data.sample.buf, This.VideoParam.width, This.VideoParam.height) break } - case 'deliver_audio': { + case "deliver_audio": { //sample:{time_stamp:xxx,data:xxx} This.pcmPlayer.play(evt.data.sample.buf) break } + case "play_failed": { + This.statusCallback(-1) + This.stop() + break + } + case "play_end": { + if (This.loop) { + This.seek(0) + } + break + } + default: return } @@ -105,19 +120,19 @@ Player.prototype.pause = function() { if (this.hPlayer == 0 || this.PlayOrPause == 0) return this.PlayOrPause = 0 - this.TurboWorker.postMessage({ command: 'pause' }) + this.TurboWorker.postMessage({ command: "pause" }) } Player.prototype.resume = function() { if (this.hPlayer == 0 || this.PlayOrPause == 1) return this.PlayOrPause = 1 - this.TurboWorker.postMessage({ command: 'resume' }) + this.TurboWorker.postMessage({ command: "resume" }) } Player.prototype.stop = function() { if (this.hPlayer == 0) return this.hPlayer = 0 - this.TurboWorker.postMessage({ command: 'stop' }) + this.TurboWorker.postMessage({ command: "stop" }) this.stopTrackTimer() if (this.pcmPlayer) { this.pcmPlayer.destroy() @@ -128,15 +143,15 @@ Player.prototype.seek = function(ms) { if (this.hPlayer == 0) return - this.TurboWorker.postMessage({ command: 'seek', pos: ms }) + this.TurboWorker.postMessage({ command: "seek", pos: ms }) if (this.pcmPlayer != null) { this.pcmPlayer.destroy() this.pcmPlayer = new PCMPlayer({ - encoding: '16bitInt', + encoding: "16bitInt", channels: this.AudioParam.channel, sampleRate: this.AudioParam.sample_rate, - flushingTime: 5000, + flushingTime: 5000 }) } } @@ -145,14 +160,16 @@ if (this.webglPlayer) this.webglPlayer.fullscreen() } +Player.prototype.exitfullscreen = function() { + if (this.webglPlayer) this.webglPlayer.exitfullscreen() +} + Player.prototype.startTrackTimer = function() { var This = this this.trackTimer = setInterval(function() { if (This.timeTrack) This.timeTrack.value = This.CurPos - if (This.timeLabel) - This.timeLabel.innerHTML = - This.formatTime(This.CurPos / 1000) + '/' + This.displayDuration + if (This.timeLabel) This.timeLabel.innerHTML = This.formatTime(This.CurPos / 1000) + "/" + This.displayDuration }, 500) } @@ -164,16 +181,9 @@ } Player.prototype.formatTime = function(s) { - var h = - Math.floor(s / 3600) < 10 - ? '0' + Math.floor(s / 3600) - : Math.floor(s / 3600) - var m = - Math.floor((s / 60) % 60) < 10 - ? '0' + Math.floor((s / 60) % 60) - : Math.floor((s / 60) % 60) - var s = - Math.floor(s % 60) < 10 ? '0' + Math.floor(s % 60) : Math.floor(s % 60) + var h = Math.floor(s / 3600) < 10 ? "0" + Math.floor(s / 3600) : Math.floor(s / 3600) + var m = Math.floor((s / 60) % 60) < 10 ? "0" + Math.floor((s / 60) % 60) : Math.floor((s / 60) % 60) + var s = Math.floor(s % 60) < 10 ? "0" + Math.floor(s % 60) : Math.floor(s % 60) - return h + ':' + m + ':' + s + return h + ":" + m + ":" + s } diff --git a/src/components/wasmPlayer/wasm/webgl.js b/src/components/wasmPlayer/wasm/webgl.js index 7d2c0cf..820a6c9 100644 --- a/src/components/wasmPlayer/wasm/webgl.js +++ b/src/components/wasmPlayer/wasm/webgl.js @@ -20,29 +20,18 @@ Texture.prototype.fill = function(width, height, data) { var gl = this.gl gl.bindTexture(gl.TEXTURE_2D, this.texture) - gl.texImage2D( - gl.TEXTURE_2D, - 0, - gl.LUMINANCE, - width, - height, - 0, - gl.LUMINANCE, - gl.UNSIGNED_BYTE, - data - ) + gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data) } export function WebGLPlayer(canvas) { this.canvas = canvas - this.gl = - canvas.getContext('webgl') || canvas.getContext('experimental-webgl') + this.gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl") this.initGL() } WebGLPlayer.prototype.initGL = function() { if (!this.gl) { - console.log('[ER] WebGL not supported.') + console.log("[ER] WebGL not supported.") return } @@ -50,34 +39,34 @@ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1) var program = gl.createProgram() var vertexShaderSource = [ - 'attribute highp vec4 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'varying highp vec2 vTextureCoord;', - 'void main(void) {', - ' gl_Position = aVertexPosition;', - ' vTextureCoord = aTextureCoord;', - '}', - ].join('\n') + "attribute highp vec4 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "varying highp vec2 vTextureCoord;", + "void main(void) {", + " gl_Position = aVertexPosition;", + " vTextureCoord = aTextureCoord;", + "}" + ].join("\n") var vertexShader = gl.createShader(gl.VERTEX_SHADER) gl.shaderSource(vertexShader, vertexShaderSource) gl.compileShader(vertexShader) var fragmentShaderSource = [ - 'precision highp float;', - 'varying lowp vec2 vTextureCoord;', - 'uniform sampler2D YTexture;', - 'uniform sampler2D UTexture;', - 'uniform sampler2D VTexture;', - 'const mat4 YUV2RGB = mat4', - '(', - ' 1.1643828125, 0, 1.59602734375, -.87078515625,', - ' 1.1643828125, -.39176171875, -.81296875, .52959375,', - ' 1.1643828125, 2.017234375, 0, -1.081390625,', - ' 0, 0, 0, 1', - ');', - 'void main(void) {', - ' gl_FragColor = vec4( texture2D(YTexture, vTextureCoord).x, texture2D(UTexture, vTextureCoord).x, texture2D(VTexture, vTextureCoord).x, 1) * YUV2RGB;', - '}', - ].join('\n') + "precision highp float;", + "varying lowp vec2 vTextureCoord;", + "uniform sampler2D YTexture;", + "uniform sampler2D UTexture;", + "uniform sampler2D VTexture;", + "const mat4 YUV2RGB = mat4", + "(", + " 1.1643828125, 0, 1.59602734375, -.87078515625,", + " 1.1643828125, -.39176171875, -.81296875, .52959375,", + " 1.1643828125, 2.017234375, 0, -1.081390625,", + " 0, 0, 0, 1", + ");", + "void main(void) {", + " gl_FragColor = vec4( texture2D(YTexture, vTextureCoord).x, texture2D(UTexture, vTextureCoord).x, texture2D(VTexture, vTextureCoord).x, 1) * YUV2RGB;", + "}" + ].join("\n") var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) gl.shaderSource(fragmentShader, fragmentShaderSource) @@ -87,54 +76,37 @@ gl.linkProgram(program) gl.useProgram(program) if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - console.log('[ER] Shader link failed.') + console.log("[ER] Shader link failed.") } - var vertexPositionAttribute = gl.getAttribLocation(program, 'aVertexPosition') + var vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition") gl.enableVertexAttribArray(vertexPositionAttribute) - var textureCoordAttribute = gl.getAttribLocation(program, 'aTextureCoord') + var textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord") gl.enableVertexAttribArray(textureCoordAttribute) var verticesBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer) gl.bufferData( gl.ARRAY_BUFFER, - new Float32Array([ - 1.0, - 1.0, - 0.0, - -1.0, - 1.0, - 0.0, - 1.0, - -1.0, - 0.0, - -1.0, - -1.0, - 0.0, - ]), + new Float32Array([1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0]), gl.STATIC_DRAW ) gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0) var texCoordBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer) - gl.bufferData( - gl.ARRAY_BUFFER, - new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0]), - gl.STATIC_DRAW - ) + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0]), gl.STATIC_DRAW) gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0) gl.y = new Texture(gl) gl.u = new Texture(gl) gl.v = new Texture(gl) - gl.y.bind(0, program, 'YTexture') - gl.u.bind(1, program, 'UTexture') - gl.v.bind(2, program, 'VTexture') + gl.y.bind(0, program, "YTexture") + gl.u.bind(1, program, "UTexture") + gl.v.bind(2, program, "VTexture") } WebGLPlayer.prototype.renderFrame = function(videoFrame, width, height) { if (!this.gl) { - console.log('[ER] Render frame failed due to WebGL not supported.') + console.log("[ER] Render frame failed due to WebGL not supported.") return } @@ -144,22 +116,14 @@ gl.clear(gl.COLOR_BUFFER_BIT) gl.y.fill(width, height, videoFrame.subarray(0, width * height)) - gl.u.fill( - width >> 1, - height >> 1, - videoFrame.subarray(width * height, (width * height * 5) / 4) - ) - gl.v.fill( - width >> 1, - height >> 1, - videoFrame.subarray((width * height * 5) / 4, (width * height * 3) / 2) - ) + gl.u.fill(width >> 1, height >> 1, videoFrame.subarray(width * height, (width * height * 5) / 4)) + gl.v.fill(width >> 1, height >> 1, videoFrame.subarray((width * height * 5) / 4, (width * height * 3) / 2)) gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4) } WebGLPlayer.prototype.fullscreen = function() { - var canvas = this.canvas + let canvas = this.canvas.parentNode.parentNode.parentNode if (canvas.RequestFullScreen) { canvas.RequestFullScreen() } else if (canvas.webkitRequestFullScreen) { diff --git a/src/pages/cameraPlayer/index/App.vue b/src/pages/cameraPlayer/index/App.vue index 45d0e10..de71805 100644 --- a/src/pages/cameraPlayer/index/App.vue +++ b/src/pages/cameraPlayer/index/App.vue @@ -1,6 +1,12 @@ <template> <div style="width:100%; height: 100%;"> - <camera-player :cameraID="query.cameraId" :rtspUrl="query.rtspUrl" :isGb="query.gb28181 === '1'"></camera-player> + <camera-player + :cameraID="query.cameraId" + :rtspUrl="query.rtspUrl" + :isGb="query.gb28181 === '1'" + v-if="!enableWasm" + ></camera-player> + <wasm-player :cameraID="query.cameraId" :rtspUrl="query.rtspUrl" :isGb="query.gb28181 === '1'" v-else></wasm-player> </div> </template> @@ -10,11 +16,13 @@ // http://192.168.20.191:7003/view/cameraPlayer/index.html?cameraId=e7e6157a-5929-4e78-b390-e365141169c8&rtspUrl=rtsp://admin:a1234567@192.168.5.51:554/h264/ch1/main/av_stream import CameraPlayer from "../components/player" +import WasmPlayer from "@/components/wasmPlayer" export default { name: "BasicCameraPlayer", components: { - CameraPlayer + CameraPlayer, + WasmPlayer }, data() { return { @@ -22,7 +30,8 @@ cameraId: "", rtspUrl: "", gb28181: "0" - } + }, + enableWasm: false } }, mounted() { @@ -43,6 +52,10 @@ if (key == "rtspUrl") { obj[key] = this.rtspParse(value) } + + if (key == "enableWasm" && value == "1") { + this.enableWasm = true + } }) } this.query = Object.assign({}, this.query, obj) @@ -50,14 +63,17 @@ }, // 瀵逛紶鍏ョ殑rtsp瀵嗙爜杩涜urlEncode澶勭悊 rtspParse(input) { + // 鏃犳晥鐨剅tsp鍦板潃 if (!input.length || input.indexOf("rtsp://") != 0) { return } let userinfoSplitPos = input.indexOf(":", 7) let userinfoEndPos = input.lastIndexOf("@") + + // 鏈寘鍚櫥褰曚俊鎭殑rtsp鍦板潃, 鐩存帴杩斿洖鍘焨rl if (userinfoSplitPos == -1 || userinfoEndPos == -1 || userinfoEndPos < userinfoSplitPos) { - return + return input } let usrPassword = input.slice(userinfoSplitPos + 1, userinfoEndPos) -- Gitblit v1.8.0