icy3dw/src/client/object/other/video-player.ts

106 lines
2.3 KiB
TypeScript

import Hls from 'hls.js';
import {
FrontSide,
Mesh,
MeshBasicMaterial,
PlaneGeometry,
VideoTexture,
} from 'three';
import { clamp } from 'three/src/math/MathUtils';
export class VideoPlayer {
public video = document.createElement('video');
public material!: MeshBasicMaterial;
public texture!: VideoTexture;
public mesh!: Mesh;
public hls?: Hls;
public playable: boolean;
public geometry!: PlaneGeometry;
constructor(public width: number, public height: number) {}
initialize() {
this.texture = new VideoTexture(this.video);
this.material = new MeshBasicMaterial({
map: this.texture,
side: FrontSide,
toneMapped: false,
});
this.geometry = new PlaneGeometry(this.width, this.height);
this.mesh = new Mesh(this.geometry, this.material);
this.video.addEventListener('canplay', () => {
this.playable = true;
});
this.video.addEventListener('error', () => {
this.playable = false;
this.video.pause();
this.video.src = undefined;
});
this.video.volume = 0.8;
}
public setSource(source: string, autoplay = false) {
this.video.pause();
if (this.hls) {
this.hls.stopLoad();
this.hls.destroy();
}
if (source.endsWith('m3u8')) {
if (Hls.isSupported()) {
this.hls = new Hls();
this.hls.loadSource(source);
this.hls.attachMedia(this.video);
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
this.playable = true;
if (autoplay) {
this.video.play();
} else {
this.hls.stopLoad();
}
});
this.hls.on(Hls.Events.ERROR, (e, d) => {
if (d.fatal) {
this.playable = false;
this.video.pause();
this.hls.stopLoad();
}
});
return;
}
}
this.video.src = source;
if (autoplay) {
this.video.play();
}
}
public play() {
if (this.playable) {
if (this.hls) {
this.hls.startLoad(-1);
}
this.video.play();
}
}
public stop() {
this.video.pause();
if (this.hls) {
this.hls.stopLoad();
}
}
public setVolume(percent: number) {
const setter = clamp(percent, 0, 100) / 100;
this.video.volume = setter;
}
}