@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
195 lines (179 loc) • 6.91 kB
text/typescript
import {VideoTexture, LoadingManager, Loader} from 'three';
// import {BaseNodeType} from '../../../engine/nodes/_Base';
import {CoreLoaderTexture} from '../Texture';
import {CoreBaseLoader} from './../_Base';
// import {BaseTextureLoader,} from './_BaseTextureLoader';
// import {TextureLoadOptions} from './_BaseImageLoader';
import {Poly} from '../../../engine/Poly';
interface VideoSourceTypeByExt {
ogg: string;
ogv: string;
mp4: string;
}
const VIDEO_SOURCE_TYPE_BY_EXT: VideoSourceTypeByExt = {
ogg: 'video/ogg; codecs="theora, vorbis"',
ogv: 'video/ogg; codecs="theora, vorbis"',
mp4: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
};
type OnLoad = (texture: VideoTexture) => void;
type OnProgress = (progress: number) => void;
type OnError = (error: Error) => void;
class VideoTextureLoader extends Loader<VideoTexture> {
constructor(manager: LoadingManager, protected originalUrls: string[]) {
super(manager);
}
loadMultipleUrls(urls: string[], onLoad: OnLoad, onProgress?: OnProgress, onError?: OnError) {
const video = document.createElement('video');
video.setAttribute('crossOrigin', 'anonymous');
video.setAttribute('playinline', `${true}`);
video.setAttribute('muted', `${true}`);
video.setAttribute('autoplay', `${true}`); // to ensure it loads
video.style.display = 'none';
// DO NOT WAIT FOR onloadedmetadata event
// to create the VideoTexture
// as this breaks loading
// when using a texture that has both mp4 and ogv
const texture = new VideoTexture(video);
video.onloadedmetadata = () => {
// video.pause();
// const texture = new VideoTexture(video);
// video.setAttribute('controls', true)
// video.style="display:none"
onLoad(texture);
};
video.onprogress = (ev) => {
if (onProgress) {
onProgress(ev.loaded / ev.total);
}
};
const _onError = (error: string | Event) => {
if (onError) {
onError(new Error('failed to load video'));
}
};
video.onerror = _onError;
// video.addEventListener('abort', _onError);
// video.addEventListener('suspend', _onError);
// video.addEventListener('stalled', _onError);
const urlsCount = urls.length;
for (let i = 0; i < urlsCount; i++) {
const blobUrl = urls[i];
const originalUrl = this.originalUrls[i];
const ext = CoreBaseLoader.extension(originalUrl) as keyof VideoSourceTypeByExt;
const type = VIDEO_SOURCE_TYPE_BY_EXT[ext] || `video/${ext}`;
const source = document.createElement('source');
source.src = blobUrl;
source.type = type;
video.append(source);
}
}
}
export class CoreVideoTextureLoader extends CoreBaseLoader<string[]> {
async loadVideo(): Promise<VideoTexture> {
const urls = this._urlToLoad();
return new Promise(async (resolve, reject) => {
const loader = await this._getLoader();
urls.forEach((url) => CoreLoaderTexture.incrementInProgressLoadsCount());
await CoreLoaderTexture.waitForMaxConcurrentLoadsQueueFreed();
loader.loadMultipleUrls(
urls,
(texture: VideoTexture) => {
urls.forEach((url, i) => {
const isLast = i == urls.length - 1;
CoreLoaderTexture.decrementInProgressLoadsCount(url, isLast ? texture : undefined);
});
resolve(texture);
},
undefined,
(error: any) => {
urls.forEach((url) => CoreLoaderTexture.decrementInProgressLoadsCount(url));
Poly.warn('error', error);
reject();
}
);
});
}
protected async _getLoader() {
const loader = new VideoTextureLoader(this.loadingManager, this._url);
return loader;
}
// constructor(protected override _url: string, protected override _node: BaseNodeType) {
// super(_url, _node);
// }
// loadVideo(): Promise<VideoTexture> {
// // if (1 + 1) {
// // return this._loadVideoFull();
// // } else {
// return this._loadVideoDefault();
// // }
// }
// // private _loadVideoFull(): Promise<VideoTexture> {
// // return new Promise(async (resolve) => {
// // const url = await this._urlToLoad();
// // console.log(url);
// // fetch(url, {mode: 'no-cors'}).then(async (response) => {
// // console.log({response});
// // const blob = await response.blob();
// // console.log({blob});
// // const source = URL.createObjectURL(blob);
// // console.log(source);
// // const video = document.createElement('video');
// // video.src = source;
// // const texture = new VideoTexture(video);
// // // document.body.append(video)
// // resolve(texture);
// // });
// // });
// // }
// private _loadVideoDefault(): Promise<VideoTexture> {
// return new Promise(async (resolve, reject) => {
// const url = await this._urlToLoad();
// CoreLoaderTexture.incrementInProgressLoadsCount();
// await CoreLoaderTexture.waitForMaxConcurrentLoadsQueueFreed();
// const video = document.createElement('video');
// video.setAttribute('crossOrigin', 'anonymous');
// video.setAttribute('autoplay', `${true}`); // to ensure it loads
// video.setAttribute('loop', `${true}`);
// // wait for onloadedmetadata to ensure that we have a duration
// // video.onloadeddata = function (e) {
// // console.log('onloadeddata', e);
// // };
// video.onloadedmetadata = function () {
// video.pause();
// const texture = new VideoTexture(video);
// // video.setAttribute('controls', true)
// // video.style="display:none"
// CoreLoaderTexture.decrementInProgressLoadsCount(url, texture);
// resolve(texture);
// };
// // add source as is
// const originalSource = document.createElement('source');
// const originalExt = CoreBaseLoader.extension(url) as keyof VideoSourceTypeByExt;
// let type: string = VideoTextureLoader.VIDEO_SOURCE_TYPE_BY_EXT[originalExt];
// type = type || VideoTextureLoader._default_video_source_type(url);
// originalSource.setAttribute('type', type);
// originalSource.setAttribute('src', url);
// video.appendChild(originalSource);
// // add secondary source, either mp4 or ogv depending on the first url
// let secondaryUrl: string | undefined;
// if (originalExt == 'mp4') {
// // add ogv
// secondaryUrl = CoreLoaderTexture.replaceExtension(url, 'ogv');
// } else {
// // add mp4
// secondaryUrl = CoreLoaderTexture.replaceExtension(url, 'mp4');
// }
// const secondary_source = document.createElement('source');
// const secondary_ext = CoreBaseLoader.extension(secondaryUrl) as keyof VideoSourceTypeByExt;
// type = VideoTextureLoader.VIDEO_SOURCE_TYPE_BY_EXT[secondary_ext];
// type = type || VideoTextureLoader._default_video_source_type(url);
// secondary_source.setAttribute('type', type);
// secondary_source.setAttribute('src', url);
// video.appendChild(secondary_source);
// });
// }
// static _default_video_source_type(url: string) {
// const ext = CoreBaseLoader.extension(url);
// return `video/${ext}`;
// }
}