js/Mobilizing/renderer/3D/three/texture/VideoTexture.js
import * as THREE from 'three';
import Component from '../../../../core/Component';
export default class VideoTexture extends Component {
/**
* VideoTexture Class give the possibility to use a movie file directly as a texture. Therefore, this class contains some movie media fonctions to manage time (play, pause, stop, etc). The texture must be mapped on an Mesh via a Material (setTexture()).
*
* @param {Object} params Parameters object, given by the constructor.
* @param {Video} params.video the html5 video object to use for this VideoTexture
* @param {Boolean} [params.loop = false] whether the video should loop after playback end
* @param {Boolean} [params.autoPlay = false] whether the video should play at construction
*
* @example
* //TODO
*/
constructor({
video = undefined,
loop = true,
autoPlay = true,
fps = 30,
} = {}) {
super(...arguments);
this.video = video;
this.loop = loop;
this.autoPlay = autoPlay;
this.fps = fps;
if (this.video) {
this.video.muted = true;
this.video.setAttribute("playsinline", "");//to activate rendering on iOS
}
this.isPlaying = false;
this._bufferedPourcent = { start: 0, end: 0 };
this._texture = new THREE.VideoTexture(this.video);
this._texture.generateMipmaps = false;
this._texture.minFilter = THREE.NearestFilter;
this._texture.magFilter = THREE.NearestFilter;
}
/**
* @return the Three.js native object used in this class
*/
getNativeObject() {
return this._texture;
}
setup() {
super.setup();
//to have some events to work with
this.video.addEventListener("progress", this.onLoadProgess.bind(this));
this.video.addEventListener("ended", this.onVideoEnded.bind(this));
}
on() {
super.on();
if (this.autoPlay) {
this.play();
}
}
/**
* Defines a "load progress" behavior. User can access the result of the progress through the bufferedPourcent property (videoTexture.bufferedPourcent) which is an object constructed like this : this._bufferedPourcent = {start:<Number>, end: <Number>}. FIXME : should map to the orginal list produced by HTML5 TimeRange object
* @private
* @param {Event} e
*/
onLoadProgess() {
const timeRange = this.getBuffered();
if (timeRange) {
if (timeRange.length >= 1) {
this._bufferedPourcent = {
"start": this.getBuffered().start(0) * 100 / this.getDuration(),
"end": this.getBuffered().end(0) * 100 / this.getDuration()
};
}
}
}
/**
* Ended event to manage loop playback
* @private
* @param {Event} e
*/
onVideoEnded() {
if (this.loop) {
this.play();
}
else {
this.stop();
}
}
/**
* Set Loop on or off for this video
* @param {Boolean} val
*/
setLoop(val) {
this.loop = val;
}
/**
* updates the video texture, should be done everytime an update is desired (i.e. every frame)
*/
update() {
if (this.video.readyState >= this.video.HAVE_FUTURE_DATA) {
this._texture.needsUpdate = true;
}
}
/**
* Play the video
*/
play() {
const playPromise = this.video.play();
if (playPromise !== undefined) {
playPromise.then(() => {
}).catch((error) => {
console.error(error);
alert(error);
});
}
else {
this.video.play();
}
this.isPlaying = true;
}
/**
* Pause the video
*/
pause() {
this.video.pause();
this.isPlaying = false;
}
/**
* Stop the video
*/
stop() {
this.video.pause();
this.video.currentTime = 0;
this.isPlaying = false;
}
/**
* Get playing state
* @return {Boolean} playing state
*/
getIsPlaying() {
return this.isPlaying;
}
/**
* Gets the current time of this video
* @return {Number} the current time of this video in seconds
*/
getCurrentTime() {
return this.video.currentTime;
}
/**
* Gets the current buffered part of this video
* @return {Object} the current buffered part as a TimeRange Object {length:Number, start:Number, end:Number}
*/
getBuffered() {
return this.video.buffered;
}
/**
* Set the current time of this video
* @param {Number} t the current time (in second) to
*/
setCurrentTime(time) {
if (this.video.currentTime < this.video.duration) {
this.video.currentTime = time;
}
else {
this.video.currentTime = this.video.duration;
}
}
/**
* Get the duration of the video file in seconds
* @return {Number} duration
*/
getDuration() {
return this.video.duration;
}
/**
* Set the playback rate of the video. See https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/playbackRate for more details
* @param {Number} rate the playback rate
*/
setPlaybackRate(rate) {
this.video.playbackRate = rate;
}
/**
* Get the current playback rate
* @return {Number} the playback rate
*/
getPlaybackRate() {
return this.video.playbackRate;
}
/**
* Get the current video width
* @return {Number} the video width
*/
getWidth() {
return this.video.videoWidth;
}
/**
* Get the current video height
* @return {Number} the video height
*/
getHeight() {
return this.video.videoHeight;
}
}