let EZUIKitPlayerClass = null let loadPromise = null // scaleMode: 0=拉伸 1=等比完整显示 2=等比填满(会超出容器裁切) const DEFAULT_SCALE_MODE = 1 function pickEZUIKitPlayer(mod) { if (!mod) { return null } const candidates = [ mod.EZUIKitPlayer, mod.default?.EZUIKitPlayer, mod.default?.default?.EZUIKitPlayer, typeof mod.default === 'function' ? mod.default : null ] for (const item of candidates) { if (typeof item === 'function') { return item } } return null } export async function loadEZUIKitPlayer() { if (EZUIKitPlayerClass) { return EZUIKitPlayerClass } if (!loadPromise) { loadPromise = import('ezuikit-js').then((mod) => { EZUIKitPlayerClass = pickEZUIKitPlayer(mod) if (!EZUIKitPlayerClass) { throw new Error('EZUIKitPlayer 加载失败') } return EZUIKitPlayerClass }) } return loadPromise } export function resolveEzopenUrl(camera, playerConfig = {}) { if (!camera) { return '' } if (camera.ezopenUrl) { return camera.ezopenUrl } const priority = playerConfig.urlPriority || ['hdPlayUrl', 'playUrl', 'ezopenUrl'] for (const key of priority) { const value = camera[key] if (value && String(value).startsWith('ezopen://')) { return value } } const serial = camera.serialNumber || camera.serial_number const channel = camera.channelNumber ?? camera.channel_number ?? 1 if (serial) { const quality = playerConfig.ezviz?.defaultQuality || 'hd.live' return `ezopen://open.ys7.com/${serial}/${channel}.${quality}` } for (const key of priority) { const value = camera[key] if (value) { return value } } return '' } export function buildEzvizDomId(playerId) { return `ezviz-player-${String(playerId).replace(/[^a-zA-Z0-9_-]/g, '_')}` } export function getPlayerMeasureTarget(containerEl) { return containerEl?.closest?.('.screen-body') || containerEl } export function getPlayerMeasureSize(containerEl) { const target = getPlayerMeasureTarget(containerEl) const width = Math.floor(target.clientWidth || target.getBoundingClientRect().width) const height = Math.floor(target.clientHeight || target.getBoundingClientRect().height) return { width: width > 0 ? width : 640, height: height > 0 ? height : 360 } } export function syncPlayerContainer(containerEl) { if (!containerEl) { return { width: 0, height: 0 } } const measureTarget = getPlayerMeasureTarget(containerEl) const { width, height } = getPlayerMeasureSize(containerEl) measureTarget.style.overflow = 'hidden' containerEl.style.width = `${width}px` containerEl.style.height = `${height}px` containerEl.style.maxWidth = `${width}px` containerEl.style.maxHeight = `${height}px` return { width, height } } function resolveScaleMode(playerConfig = {}) { const mode = playerConfig.ezviz?.scaleMode return mode === 0 || mode === 1 || mode === 2 ? mode : DEFAULT_SCALE_MODE } export function applyPlayerLayout(player, containerEl, playerConfig = {}) { if (!player || !containerEl) { return { width: 0, height: 0 } } const scaleMode = resolveScaleMode(playerConfig) const { width, height } = syncPlayerContainer(containerEl) if (typeof player.setScaleMode === 'function') { player.setScaleMode(scaleMode) } if (width > 0 && height > 0) { if (typeof player.reSize === 'function') { player.reSize(width, height) } else if (typeof player.resize === 'function') { player.resize(width, height) } } return { width, height } } export async function createEzvizPlayer(containerEl, { url, accessToken, playerConfig = {} }) { if (!containerEl || !url || !accessToken) { return null } const EZUIKitPlayer = await loadEZUIKitPlayer() const scaleMode = resolveScaleMode(playerConfig) const { width, height } = syncPlayerContainer(containerEl) const player = new EZUIKitPlayer({ id: containerEl.id, accessToken, url, width, height, staticPath: playerConfig.staticPath || '/ezuikit_static', template: playerConfig.ezviz?.template || 'simple', scaleMode, audio: playerConfig.ezviz?.audio ?? false }) const relayout = () => applyPlayerLayout(player, containerEl, playerConfig) requestAnimationFrame(relayout) window.setTimeout(relayout, 100) if (player?.eventEmitter?.on) { player.eventEmitter.on('firstFrameDisplay', relayout) player.eventEmitter.on('decoderLoaded', relayout) player.eventEmitter.on('resize', relayout) } return player } export async function destroyEzvizPlayer(player) { if (!player) { return } try { if (typeof player.stop === 'function') { await player.stop() } } catch (_) { // ignore stop errors during teardown } try { if (typeof player.destroy === 'function') { player.destroy() } } catch (_) { // ignore destroy errors during teardown } } export async function resizeEzvizPlayer(player, containerEl, playerConfig = {}) { applyPlayerLayout(player, containerEl, playerConfig) }