From 9df7a2898eb76dc4ee52c43fb3a3ef2fa6992d92 Mon Sep 17 00:00:00 2001 From: qiwei Date: Thu, 18 Jan 2024 11:58:47 +0800 Subject: [PATCH] =?UTF-8?q?video-layer=20=E4=BC=98=E5=8C=96=E6=8B=89?= =?UTF-8?q?=E4=BC=B8=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../overlay/video/VideoLayerRenderer.js | 2 +- src/mapboxgl/overlay/VideoLayer.js | 84 +++++++++++++++++-- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/common/overlay/video/VideoLayerRenderer.js b/src/common/overlay/video/VideoLayerRenderer.js index 91b61c0d0..08a005419 100644 --- a/src/common/overlay/video/VideoLayerRenderer.js +++ b/src/common/overlay/video/VideoLayerRenderer.js @@ -29,7 +29,7 @@ export class VideoLayerRenderer { video.id = this.layerId; video.className = 'video-js'; video.style.position = 'fixed'; - video.style.left = '-200%'; + video.style.left = '-300%'; video.setAttribute('crossorigin', 'anonymous'); document.body.appendChild(video); } diff --git a/src/mapboxgl/overlay/VideoLayer.js b/src/mapboxgl/overlay/VideoLayer.js index 65e25daf6..a980d920b 100644 --- a/src/mapboxgl/overlay/VideoLayer.js +++ b/src/mapboxgl/overlay/VideoLayer.js @@ -4,15 +4,16 @@ import mapboxgl from 'mapbox-gl'; import { Util as CommonUtil } from '@supermap/iclient-common/commontypes/Util'; import { VideoLayerRenderer } from '@supermap/iclient-common/overlay/video/VideoLayerRenderer'; +import { bbox, polygon } from '@turf/turf'; /** * @class VideoLayer * @category Visualization Video * @modulecategory Overlay * @param {Object} options - 构造参数。 - * @param {string} [options.id] - 专题图层 ID。默认使用 CommonUtil.createUniqueID("VideoLayer_") 创建专题图层 ID。 - * @param {string} [options.url] - 视频 或 流链接。支持 flv, m3u8 流格式。 - * @param {string} [options.extent] - 视频范围。 + * @param {string} options.url - 视频 或 流链接。支持 flv, m3u8 流格式。 + * @param {Array} options.extent - 视频范围。 + * @param {string} [options.id] - 视频图层 ID。默认使用 CommonUtil.createUniqueID("VideoLayer_") 创建专题图层 ID。 * @extends {mapboxgl.Evented} * @usage */ @@ -24,8 +25,12 @@ export class VideoLayer extends mapboxgl.Evented { this.options = _options; this.url = this.options.url; this.extent = this.options.extent; + this.cv = this.options.opencv || window.cv; + if (!this.cv) { + throw new Error('opencv.js is not existed!'); + } this.id = _options.id ? _options.id : CommonUtil.createUniqueID("VideoLayer_"); - this.layerId = this.id + 'outer'; + this.layerId = this.id + '_outer'; this.type = 'custom'; this.renderingMode = '3d'; this.overlay = true; @@ -44,7 +49,11 @@ export class VideoLayer extends mapboxgl.Evented { this.video.play(); }); this.video.one('ready', () => { + setTimeout(() => { + this.videoWidth = this.video.videoWidth(); + this.videoHeight = this.video.videoHeight(); this._addVideoLayer(this.map); + }, 1000); }); this.video.one('canplay', () => { setTimeout(() => { @@ -53,14 +62,77 @@ export class VideoLayer extends mapboxgl.Evented { }); } - render() { } + render() {} + + getPixelBbox(map) { + let res = []; + let minX = 0; + let minY = 0; + this.extent.forEach((item) => { + let result = map.project(item); + if (!minX || result.x < minX) { + minX = result.x; + } + if (!minY || result.y < minY) { + minY = result.y; + } + res.push(result.x); + res.push(result.y); + }); + res = res.map((item, index) => { + if (index % 2 === 0) { + return item - minX; + } else { + return item - minY; + } + }); + return res; + } _addVideoLayer(map) { let url = this.videoDomId || this.url; + this.pixelBBox = this.getPixelBbox(map); + const result = bbox(polygon([ + this.extent.concat(this.extent[0]) + ])); + let br = map.project([result[2], result[3]]); + let tl = map.project([result[0], result[1]]); + let size = [Math.abs(br.x - tl.x), Math.abs(br.y - tl.y)]; + let ratio = size[0] / size[1]; + let realX = this.videoHeight * ratio; + let realY = this.videoHeight; + let ratioX = realX / size[0]; + let ratioY = realY / size[1]; + this.pixelBBox = this.pixelBBox.map((item, index) => { + if (index % 2 === 0) { + return item * ratioX; + } else { + return item * ratioY; + } + }); + this.dsize = new this.cv.Size(this.videoHeight * ratio, this.videoHeight); + let that = this; + let srcTri = this.cv.matFromArray(4, 1, this.cv.CV_32FC2, [0, 0, that.videoWidth, 0, that.videoWidth, that.videoHeight, 0, that.videoHeight]); + let dstTri = this.cv.matFromArray(4, 1, this.cv.CV_32FC2, this.pixelBBox); map.addSource(this.layerId, { type: 'video', urls: [url], - coordinates: this.extent + drawImageCallback(frame) { + let src = that.cv.matFromImageData(frame); + let dst = new that.cv.Mat(); + let M = that.cv.findHomography(srcTri, dstTri); + that.cv.warpPerspective(src, dst, M, that.dsize); + let newFrame = new ImageData(new Uint8ClampedArray(dst.data), dst.cols, dst.rows); + src.delete(); + dst.delete(); + return newFrame; + }, + coordinates: [ + [result[0], result[3]], + [result[2], result[3]], + [result[2], result[1]], + [result[0], result[1]] + ] }); map.addLayer(