1 | import { Ticker } from '@pixi/ticker';
|
2 | import { BaseImageResource } from './BaseImageResource.mjs';
|
3 |
|
4 | const _VideoResource = class extends BaseImageResource {
|
5 | constructor(source, options) {
|
6 | options = options || {};
|
7 | if (!(source instanceof HTMLVideoElement)) {
|
8 | const videoElement = document.createElement("video");
|
9 | videoElement.setAttribute("preload", "auto");
|
10 | videoElement.setAttribute("webkit-playsinline", "");
|
11 | videoElement.setAttribute("playsinline", "");
|
12 | if (typeof source === "string") {
|
13 | source = [source];
|
14 | }
|
15 | const firstSrc = source[0].src || source[0];
|
16 | BaseImageResource.crossOrigin(videoElement, firstSrc, options.crossorigin);
|
17 | for (let i = 0; i < source.length; ++i) {
|
18 | const sourceElement = document.createElement("source");
|
19 | let { src, mime } = source[i];
|
20 | src = src || source[i];
|
21 | const baseSrc = src.split("?").shift().toLowerCase();
|
22 | const ext = baseSrc.slice(baseSrc.lastIndexOf(".") + 1);
|
23 | mime = mime || _VideoResource.MIME_TYPES[ext] || `video/${ext}`;
|
24 | sourceElement.src = src;
|
25 | sourceElement.type = mime;
|
26 | videoElement.appendChild(sourceElement);
|
27 | }
|
28 | source = videoElement;
|
29 | }
|
30 | super(source);
|
31 | this.noSubImage = true;
|
32 | this._autoUpdate = true;
|
33 | this._isConnectedToTicker = false;
|
34 | this._updateFPS = options.updateFPS || 0;
|
35 | this._msToNextUpdate = 0;
|
36 | this.autoPlay = options.autoPlay !== false;
|
37 | this._load = null;
|
38 | this._resolve = null;
|
39 | this._onCanPlay = this._onCanPlay.bind(this);
|
40 | this._onError = this._onError.bind(this);
|
41 | if (options.autoLoad !== false) {
|
42 | this.load();
|
43 | }
|
44 | }
|
45 | update(_deltaTime = 0) {
|
46 | if (!this.destroyed) {
|
47 | const elapsedMS = Ticker.shared.elapsedMS * this.source.playbackRate;
|
48 | this._msToNextUpdate = Math.floor(this._msToNextUpdate - elapsedMS);
|
49 | if (!this._updateFPS || this._msToNextUpdate <= 0) {
|
50 | super.update();
|
51 | this._msToNextUpdate = this._updateFPS ? Math.floor(1e3 / this._updateFPS) : 0;
|
52 | }
|
53 | }
|
54 | }
|
55 | load() {
|
56 | if (this._load) {
|
57 | return this._load;
|
58 | }
|
59 | const source = this.source;
|
60 | if ((source.readyState === source.HAVE_ENOUGH_DATA || source.readyState === source.HAVE_FUTURE_DATA) && source.width && source.height) {
|
61 | source.complete = true;
|
62 | }
|
63 | source.addEventListener("play", this._onPlayStart.bind(this));
|
64 | source.addEventListener("pause", this._onPlayStop.bind(this));
|
65 | if (!this._isSourceReady()) {
|
66 | source.addEventListener("canplay", this._onCanPlay);
|
67 | source.addEventListener("canplaythrough", this._onCanPlay);
|
68 | source.addEventListener("error", this._onError, true);
|
69 | } else {
|
70 | this._onCanPlay();
|
71 | }
|
72 | this._load = new Promise((resolve) => {
|
73 | if (this.valid) {
|
74 | resolve(this);
|
75 | } else {
|
76 | this._resolve = resolve;
|
77 | source.load();
|
78 | }
|
79 | });
|
80 | return this._load;
|
81 | }
|
82 | _onError(event) {
|
83 | this.source.removeEventListener("error", this._onError, true);
|
84 | this.onError.emit(event);
|
85 | }
|
86 | _isSourcePlaying() {
|
87 | const source = this.source;
|
88 | return !source.paused && !source.ended && this._isSourceReady();
|
89 | }
|
90 | _isSourceReady() {
|
91 | const source = this.source;
|
92 | return source.readyState > 2;
|
93 | }
|
94 | _onPlayStart() {
|
95 | if (!this.valid) {
|
96 | this._onCanPlay();
|
97 | }
|
98 | if (this.autoUpdate && !this._isConnectedToTicker) {
|
99 | Ticker.shared.add(this.update, this);
|
100 | this._isConnectedToTicker = true;
|
101 | }
|
102 | }
|
103 | _onPlayStop() {
|
104 | if (this._isConnectedToTicker) {
|
105 | Ticker.shared.remove(this.update, this);
|
106 | this._isConnectedToTicker = false;
|
107 | }
|
108 | }
|
109 | _onCanPlay() {
|
110 | const source = this.source;
|
111 | source.removeEventListener("canplay", this._onCanPlay);
|
112 | source.removeEventListener("canplaythrough", this._onCanPlay);
|
113 | const valid = this.valid;
|
114 | this.resize(source.videoWidth, source.videoHeight);
|
115 | if (!valid && this._resolve) {
|
116 | this._resolve(this);
|
117 | this._resolve = null;
|
118 | }
|
119 | if (this._isSourcePlaying()) {
|
120 | this._onPlayStart();
|
121 | } else if (this.autoPlay) {
|
122 | source.play();
|
123 | }
|
124 | }
|
125 | dispose() {
|
126 | if (this._isConnectedToTicker) {
|
127 | Ticker.shared.remove(this.update, this);
|
128 | this._isConnectedToTicker = false;
|
129 | }
|
130 | const source = this.source;
|
131 | if (source) {
|
132 | source.removeEventListener("error", this._onError, true);
|
133 | source.pause();
|
134 | source.src = "";
|
135 | source.load();
|
136 | }
|
137 | super.dispose();
|
138 | }
|
139 | get autoUpdate() {
|
140 | return this._autoUpdate;
|
141 | }
|
142 | set autoUpdate(value) {
|
143 | if (value !== this._autoUpdate) {
|
144 | this._autoUpdate = value;
|
145 | if (!this._autoUpdate && this._isConnectedToTicker) {
|
146 | Ticker.shared.remove(this.update, this);
|
147 | this._isConnectedToTicker = false;
|
148 | } else if (this._autoUpdate && !this._isConnectedToTicker && this._isSourcePlaying()) {
|
149 | Ticker.shared.add(this.update, this);
|
150 | this._isConnectedToTicker = true;
|
151 | }
|
152 | }
|
153 | }
|
154 | get updateFPS() {
|
155 | return this._updateFPS;
|
156 | }
|
157 | set updateFPS(value) {
|
158 | if (value !== this._updateFPS) {
|
159 | this._updateFPS = value;
|
160 | }
|
161 | }
|
162 | static test(source, extension) {
|
163 | return globalThis.HTMLVideoElement && source instanceof HTMLVideoElement || _VideoResource.TYPES.includes(extension);
|
164 | }
|
165 | };
|
166 | let VideoResource = _VideoResource;
|
167 | VideoResource.TYPES = ["mp4", "m4v", "webm", "ogg", "ogv", "h264", "avi", "mov"];
|
168 | VideoResource.MIME_TYPES = {
|
169 | ogv: "video/ogg",
|
170 | mov: "video/quicktime",
|
171 | m4v: "video/mp4"
|
172 | };
|
173 |
|
174 | export { VideoResource };
|
175 |
|