{"version":3,"sources":["src/index.ts","src/EquirectangularVideoAdapter.ts","../shared/AbstractVideoAdapter.ts","../shared/video-utils.ts"],"sourcesContent":["export { EquirectangularVideoAdapter } from './EquirectangularVideoAdapter';\nexport * from './model';\n","import type { AdapterConstructor, PanoData, PanoramaPosition, Position, TextureData, Viewer } from '@photo-sphere-viewer/core';\nimport { EquirectangularAdapter, utils } from '@photo-sphere-viewer/core';\nimport { Mesh, MeshBasicMaterial, SphereGeometry, VideoTexture } from 'three';\nimport { AbstractVideoAdapter } from '../../shared/AbstractVideoAdapter';\nimport { EquirectangularVideoAdapterConfig, EquirectangularVideoPanorama } from './model';\n\ntype EquirectangularVideoMesh = Mesh<SphereGeometry, MeshBasicMaterial>;\ntype EquirectangularVideoTextureData = TextureData<VideoTexture, EquirectangularVideoPanorama, PanoData>;\n\nconst getConfig = utils.getConfigParser<EquirectangularVideoAdapterConfig>({\n    resolution: 64,\n    autoplay: false,\n    muted: false,\n});\n\n/**\n * Adapter for equirectangular videos\n */\nexport class EquirectangularVideoAdapter extends AbstractVideoAdapter<\n    EquirectangularVideoPanorama,\n    PanoData,\n    EquirectangularVideoMesh\n> {\n    static override readonly id = 'equirectangular-video';\n    static override readonly VERSION = PKG_VERSION;\n\n    protected override readonly config: EquirectangularVideoAdapterConfig;\n\n    private adapter: EquirectangularAdapter;\n\n    static withConfig(config: EquirectangularVideoAdapterConfig): [AdapterConstructor, any] {\n        return [EquirectangularVideoAdapter, config];\n    }\n\n    constructor(viewer: Viewer, config: EquirectangularVideoAdapterConfig) {\n        super(viewer);\n\n        this.config = getConfig(config);\n\n        this.adapter = new EquirectangularAdapter(this.viewer, {\n            resolution: this.config.resolution,\n        });\n    }\n\n    override destroy(): void {\n        this.adapter.destroy();\n\n        delete this.adapter;\n\n        super.destroy();\n    }\n\n    override textureCoordsToSphericalCoords(point: PanoramaPosition, data: PanoData): Position {\n        return this.adapter.textureCoordsToSphericalCoords(point, data);\n    }\n\n    override sphericalCoordsToTextureCoords(position: Position, data: PanoData): PanoramaPosition {\n        return this.adapter.sphericalCoordsToTextureCoords(position, data);\n    }\n\n    override async loadTexture(\n        panorama: EquirectangularVideoPanorama,\n        _?: boolean,\n        newPanoData?: any,\n    ): Promise<EquirectangularVideoTextureData> {\n        const { texture } = await super.loadTexture(panorama);\n        const video: HTMLVideoElement = texture.image;\n\n        if (panorama.data) {\n            newPanoData = panorama.data;\n        }\n        if (typeof newPanoData === 'function') {\n            newPanoData = newPanoData(video);\n        }\n\n        const panoData = utils.mergePanoData(video.videoWidth, video.videoHeight, newPanoData);\n\n        return { panorama, texture, panoData };\n    }\n\n    createMesh(panoData: PanoData): EquirectangularVideoMesh {\n        return this.adapter.createMesh(panoData);\n    }\n\n    setTexture(mesh: EquirectangularVideoMesh, { texture }: EquirectangularVideoTextureData) {\n        mesh.material.map = texture;\n\n        this.switchVideo(texture);\n    }\n}\n","import type { TextureData, Viewer } from '@photo-sphere-viewer/core';\nimport { AbstractAdapter, PSVError } from '@photo-sphere-viewer/core';\nimport { BufferGeometry, Material, Mesh, VideoTexture } from 'three';\nimport { createVideo } from './video-utils';\n\nexport type AbstractVideoPanorama = {\n    source: string | MediaStream | HTMLVideoElement;\n};\n\nexport type AbstractVideoAdapterConfig = {\n    /**\n     * automatically start the video\n     * @default false\n     */\n    autoplay?: boolean;\n    /**\n     * initially mute the video\n     * @default false\n     */\n    muted?: boolean;\n};\n\ntype AbstractVideoMesh = Mesh<BufferGeometry, Material>;\ntype AbstractVideoTextureData = TextureData<VideoTexture>;\n\n/**\n * Base video adapters class\n */\nexport abstract class AbstractVideoAdapter<\n    TPanorama extends AbstractVideoPanorama,\n    TData,\n    TMesh extends AbstractVideoMesh,\n> extends AbstractAdapter<TPanorama, TData, VideoTexture, TMesh> {\n    static override readonly supportsDownload = false;\n\n    protected abstract readonly config: AbstractVideoAdapterConfig;\n\n    private video: HTMLVideoElement;\n\n    constructor(viewer: Viewer) {\n        super(viewer);\n    }\n\n    override init() {\n        super.init();\n\n        this.viewer.needsContinuousUpdate(true);\n    }\n\n    override destroy() {\n        this.__removeVideo();\n\n        super.destroy();\n    }\n\n    override supportsPreload(): boolean {\n        return false;\n    }\n\n    override supportsTransition(): boolean {\n        return false;\n    }\n\n    async loadTexture(panorama: AbstractVideoPanorama): Promise<AbstractVideoTextureData> {\n        if (typeof panorama !== 'object' || !panorama.source) {\n            return Promise.reject(new PSVError('Invalid panorama configuration, are you using the right adapter?'));\n        }\n\n        if (!this.viewer.getPlugin('video')) {\n            return Promise.reject(new PSVError('Video adapters require VideoPlugin to be loaded too.'));\n        }\n\n        const video = panorama.source instanceof HTMLVideoElement\n            ? panorama.source\n            : createVideo({\n                    src: panorama.source,\n                    withCredentials: this.viewer.config.withCredentials(panorama.source as any),\n                    muted: true,\n                    autoplay: false,\n                });\n\n        await this.__videoLoadPromise(video);\n\n        const texture = new VideoTexture(video);\n        return { panorama, texture };\n    }\n\n    protected switchVideo(texture: VideoTexture) {\n        let currentTime;\n        let duration;\n        let paused = !this.config.autoplay;\n        let muted = this.config.muted;\n        let volume = 1;\n        if (this.video) {\n            ({ currentTime, duration, paused, muted, volume } = this.video);\n        }\n\n        this.__removeVideo();\n        this.video = texture.image;\n\n        // keep current time when switching resolution\n        if (this.video.duration === duration) {\n            this.video.currentTime = currentTime;\n        }\n\n        // keep volume\n        this.video.muted = muted;\n        this.video.volume = volume;\n\n        // play\n        if (!paused) {\n            this.video.play();\n        }\n    }\n\n    setTextureOpacity(mesh: TMesh, opacity: number) {\n        mesh.material.opacity = opacity;\n        mesh.material.transparent = opacity < 1;\n    }\n\n    disposeTexture({ texture }: AbstractVideoTextureData) {\n        texture.dispose();\n    }\n\n    disposeMesh(mesh: AbstractVideoMesh) {\n        mesh.geometry.dispose();\n        mesh.material.dispose();\n    }\n\n    private __removeVideo() {\n        if (this.video) {\n            this.video.pause();\n            this.video.remove();\n            delete this.video;\n        }\n    }\n\n    private __videoLoadPromise(video: HTMLVideoElement): Promise<void> {\n        return new Promise((resolve, reject) => {\n            const onLoaded = () => {\n                if (this.video && video.duration === this.video.duration) {\n                    video.currentTime = this.video.currentTime;\n                }\n                resolve();\n                video.removeEventListener('loadedmetadata', onLoaded);\n            };\n\n            const onError = (err: ErrorEvent) => {\n                reject(err);\n                video.removeEventListener('error', onError);\n            };\n\n            video.addEventListener('loadedmetadata', onLoaded);\n            video.addEventListener('error', onError);\n        });\n    }\n}\n","/**\n * Create a standard video element\n */\nexport function createVideo({\n    src,\n    withCredentials,\n    muted,\n    autoplay,\n}: {\n    src: string | MediaStream;\n    withCredentials: boolean;\n    muted: boolean;\n    autoplay: boolean;\n}): HTMLVideoElement {\n    const video = document.createElement('video');\n    video.crossOrigin = withCredentials ? 'use-credentials' : 'anonymous';\n    video.loop = true;\n    video.playsInline = true;\n    video.autoplay = autoplay;\n    video.muted = muted;\n    video.preload = 'metadata';\n    if (src instanceof MediaStream) {\n        video.srcObject = src;\n    } else {\n        video.src = src;\n    }\n    return video;\n}\n"],"mappings":"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","names":["import_core"]}