/* * MARTINS.js Free Edition * GPU-accelerated Augmented Reality for the web * Copyright (C) 2022 Alexandre Martins * https://github.com/alemart/martins-js * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * video-source.ts * HTMLVideoElement-based source of data */ import Speedy from 'speedy-vision'; import { SpeedyMedia } from 'speedy-vision/types/core/speedy-media'; import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise'; import { Utils, Nullable } from '../utils/utils'; import { IllegalOperationError, NotSupportedError, TimeoutError } from '../utils/errors'; import { Source } from './source'; /** A message to be displayed if a video can't autoplay and user interaction is required */ const ALERT_MESSAGE = 'Tap on the screen to start'; /** Whether or not we have displayed the ALERT_MESSAGE */ let displayedAlertMessage = false; /** * HTMLVideoElement-based source of data */ export class VideoSource implements Source { /** video element */ private _video: HTMLVideoElement; /** media source */ protected _media: Nullable; /** * Constructor */ constructor(video: HTMLVideoElement) { Utils.assert(video instanceof HTMLVideoElement, 'Expected a video element'); this._video = video; this._media = null; } /** * A type-identifier of the source of data * @internal */ get _type(): string { return 'video'; } /** * Get media * @internal */ get _data(): SpeedyMedia { if(this._media == null) throw new IllegalOperationError(`The media of the source of data isn't loaded`); return this._media; } /** * Stats related to this source of data * @internal */ get _stats(): string { const media = this._media; if(media != null) return `${media.width}x${media.height} video`; else return 'uninitialized video'; } /** * Initialize this source of data * @returns a promise that resolves as soon as this source of data is initialized * @internal */ _init(): SpeedyPromise { Utils.log(`Initializing ${this._type} source...`); // prepare the video before loading the SpeedyMedia! return this._prepareVideo(this._video).then(video => { Utils.log('The video is prepared'); return Speedy.load(video).then(media => { Utils.log(`Source of data is a ${media.width}x${media.height} ${this._type}`); this._media = media; }); }); } /** * Release this source of data * @returns a promise that resolves as soon as this source of data is released * @internal */ _release(): SpeedyPromise { if(this._media) this._media.release(); this._media = null; return Speedy.Promise.resolve(); } /** * Handle browser-specific quirks for