@video-editor/renderer 0.0.1-beta.30 → 0.0.1-beta.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,100 +1,100 @@
1
- import { createValidator as Gt, createResourceManager as Nt, getResourceKey as N } from "@video-editor/protocol";
2
- import { toRaw as zt, isRef as Kt, shallowRef as ut, unref as lt, ref as ft, computed as qt, effectScope as Bt, watch as W } from "@vue/reactivity";
3
- import { AudioClip as jt, renderTxt2ImgBitmap as _t, MP4Clip as G, Combinator as mt, OffscreenSprite as wt } from "@webav/av-cliper";
4
- import { file as Wt } from "opfs-tools";
5
- import { Application as yt, Sprite as O, Texture as V, Graphics as vt, Container as Yt } from "pixi.js";
6
- async function Xt(o) {
7
- const t = new yt();
8
- return await t.init({ resizeTo: window, backgroundAlpha: 0, ...o }), t;
1
+ import { createValidator as De, createResourceManager as Ne, getResourceKey as _ } from "@video-editor/protocol";
2
+ import { toRaw as Ge, isRef as Ke, shallowRef as pe, unref as he, ref as me, computed as qe, effectScope as Be, watch as Q } from "@vue/reactivity";
3
+ import { AudioClip as je, renderTxt2ImgBitmap as _e, MP4Clip as B, Combinator as ve, OffscreenSprite as Me } from "@webav/av-cliper";
4
+ import { file as We } from "opfs-tools";
5
+ import { Application as Se, Sprite as $, Texture as G, Graphics as ge, Container as Ye } from "pixi.js";
6
+ async function Xe(o) {
7
+ const e = new Se();
8
+ return await e.init({ resizeTo: window, backgroundAlpha: 0, ...o }), e;
9
9
  }
10
- function Jt(o, t, i, r, a) {
11
- const u = t || r, c = i || a;
12
- if (!u || !c)
13
- return { width: r, height: a };
14
- const d = u / c, l = r / a;
10
+ function Je(o, e, r, i, n) {
11
+ const d = e || i, c = r || n;
12
+ if (!d || !c)
13
+ return { width: i, height: n };
14
+ const s = d / c, l = i / n;
15
15
  switch (o) {
16
16
  case "none":
17
- return { width: u, height: c };
17
+ return { width: d, height: c };
18
18
  case "cover":
19
- return d > l ? { width: a * d, height: a } : { width: r, height: r / d };
19
+ return s > l ? { width: n * s, height: n } : { width: i, height: i / s };
20
20
  case "stretch":
21
- return { width: r, height: a };
21
+ return { width: i, height: n };
22
22
  default:
23
- return d > l ? { width: r, height: r / d } : { width: a * d, height: a };
23
+ return s > l ? { width: i, height: i / s } : { width: n * s, height: n };
24
24
  }
25
25
  }
26
- function Ht(o, t, i, r, a) {
27
- const u = "fillMode" in o ? o.fillMode : void 0, { width: c, height: d } = Jt(
28
- u,
29
- r,
30
- a,
31
- t,
32
- i
33
- ), l = "transform" in o ? o.transform : void 0, [p, h] = l?.position ?? [0, 0], [m, S] = l?.scale ?? [1, 1], M = l?.rotation?.[2] ?? 0, k = c * m, w = d * S, x = t / 2 + p * t / 2, R = i / 2 - h * i / 2;
26
+ function He(o, e, r, i, n) {
27
+ const d = "fillMode" in o ? o.fillMode : void 0, { width: c, height: s } = Je(
28
+ d,
29
+ i,
30
+ n,
31
+ e,
32
+ r
33
+ ), l = "transform" in o ? o.transform : void 0, [m, p] = l?.position ?? [0, 0], [w, T] = l?.scale ?? [1, 1], h = l?.rotation?.[2] ?? 0, v = c * w, y = s * T, g = e / 2 + m * e / 2, R = r / 2 - p * r / 2;
34
34
  return {
35
- width: k,
36
- height: w,
37
- centerX: x,
35
+ width: v,
36
+ height: y,
37
+ centerX: g,
38
38
  centerY: R,
39
- rotationRad: M / 180 * Math.PI
39
+ rotationRad: h / 180 * Math.PI
40
40
  };
41
41
  }
42
- function Qt(o) {
43
- const t = /* @__PURE__ */ new Set();
44
- for (const i of o.tracks)
45
- for (const r of i.children)
46
- r.url && t.add(r.url);
47
- return t;
42
+ function Qe(o) {
43
+ const e = /* @__PURE__ */ new Set();
44
+ for (const r of o.tracks)
45
+ for (const i of r.children)
46
+ i.url && e.add(i.url);
47
+ return e;
48
48
  }
49
- function Mt(o, t) {
50
- const i = [];
51
- return o.tracks.forEach((r, a) => {
52
- r.children.forEach((u, c) => {
53
- u.startTime <= t && t < u.endTime && i.push({ segment: u, trackIndex: a, childIndex: c });
49
+ function xe(o, e) {
50
+ const r = [];
51
+ return o.tracks.forEach((i, n) => {
52
+ i.children.forEach((d, c) => {
53
+ d.startTime <= e && e < d.endTime && r.push({ segment: d, trackIndex: n, childIndex: c });
54
54
  });
55
- }), i.sort((r, a) => {
56
- const u = o.tracks[r.trackIndex], c = o.tracks[a.trackIndex], d = u?.trackType === "frames" && u.isMain, l = c?.trackType === "frames" && c.isMain, p = o.tracks.length, h = d ? 0 : p - r.trackIndex, m = l ? 0 : p - a.trackIndex;
57
- return h !== m ? h - m : r.trackIndex === a.trackIndex ? r.childIndex - a.childIndex : r.trackIndex - a.trackIndex;
55
+ }), r.sort((i, n) => {
56
+ const d = o.tracks[i.trackIndex], c = o.tracks[n.trackIndex], s = d?.trackType === "frames" && d.isMain, l = c?.trackType === "frames" && c.isMain, m = o.tracks.length, p = s ? 0 : m - i.trackIndex, w = l ? 0 : m - n.trackIndex;
57
+ return p !== w ? p - w : i.trackIndex === n.trackIndex ? i.childIndex - n.childIndex : i.trackIndex - n.trackIndex;
58
58
  });
59
59
  }
60
- function Zt(o, t, i, r) {
61
- const a = ee(t), u = o instanceof O && o.texture.width || i, c = o instanceof O && o.texture.height || r, d = Ht(t, i, r, u, c);
62
- o instanceof O ? (o.anchor.set(0.5), o.width = d.width, o.height = d.height, o.position.set(d.centerX, d.centerY), o.rotation = d.rotationRad, o.texture.source?.addEventListener?.("error", () => {
63
- o.texture = V.from(te(i, r));
64
- }, { once: !0 })) : o instanceof vt && (o.clear(), o.rect(0, 0, d.width, d.height).fill({ color: gt("url" in t && typeof t.url == "string" ? t.url : t.segmentType), alpha: xt(t) ? a : 0.35 }), o.pivot.set(d.width / 2, d.height / 2), o.position.set(d.centerX, d.centerY), o.rotation = d.rotationRad), o.alpha = a;
60
+ function Ze(o, e, r, i) {
61
+ const n = tt(e), d = o instanceof $ && o.texture.width || r, c = o instanceof $ && o.texture.height || i, s = He(e, r, i, d, c);
62
+ o instanceof $ ? (o.anchor.set(0.5), o.width = s.width, o.height = s.height, o.position.set(s.centerX, s.centerY), o.rotation = s.rotationRad, o.texture.source?.addEventListener?.("error", () => {
63
+ o.texture = G.from(et(r, i));
64
+ }, { once: !0 })) : o instanceof ge && (o.clear(), o.rect(0, 0, s.width, s.height).fill({ color: Te("url" in e && typeof e.url == "string" ? e.url : e.segmentType), alpha: be(e) ? n : 0.35 }), o.pivot.set(s.width / 2, s.height / 2), o.position.set(s.centerX, s.centerY), o.rotation = s.rotationRad), o.alpha = n;
65
65
  }
66
- function Y(o, t) {
67
- const i = new vt();
68
- return i.rect(0, 0, 10, 10).fill({ color: gt(t ?? o), alpha: 1 }), i;
66
+ function Z(o, e) {
67
+ const r = new ge();
68
+ return r.rect(0, 0, 10, 10).fill({ color: Te(e ?? o), alpha: 1 }), r;
69
69
  }
70
- function te(o, t, i) {
71
- const r = `<svg xmlns="http://www.w3.org/2000/svg" width="${o}" height="${t}"><rect width="100%" height="100%" fill="#0f172a" fill-opacity="0.8"/></svg>`;
72
- return `data:image/svg+xml;base64,${btoa(r)}`;
70
+ function et(o, e, r) {
71
+ const i = `<svg xmlns="http://www.w3.org/2000/svg" width="${o}" height="${e}"><rect width="100%" height="100%" fill="#0f172a" fill-opacity="0.8"/></svg>`;
72
+ return `data:image/svg+xml;base64,${btoa(i)}`;
73
73
  }
74
- function gt(o) {
75
- let t = 0;
76
- for (let i = 0; i < o.length; i++)
77
- t = o.charCodeAt(i) + ((t << 5) - t);
78
- return t & 16777215;
74
+ function Te(o) {
75
+ let e = 0;
76
+ for (let r = 0; r < o.length; r++)
77
+ e = o.charCodeAt(r) + ((e << 5) - e);
78
+ return e & 16777215;
79
79
  }
80
- function J(o) {
81
- const t = o.tracks.flatMap((i) => i.children.map((r) => r.endTime));
82
- return t.length ? Math.max(...t) : 0;
80
+ function te(o) {
81
+ const e = o.tracks.flatMap((r) => r.children.map((i) => i.endTime));
82
+ return e.length ? Math.max(...e) : 0;
83
83
  }
84
- function X(o, t, i) {
85
- return Math.min(Math.max(o, t), i);
84
+ function ee(o, e, r) {
85
+ return Math.min(Math.max(o, e), r);
86
86
  }
87
- function pt(o) {
88
- const t = zt(o);
89
- return JSON.parse(JSON.stringify(t));
87
+ function ye(o) {
88
+ const e = Ge(o);
89
+ return JSON.parse(JSON.stringify(e));
90
90
  }
91
- function xt(o) {
91
+ function be(o) {
92
92
  return "opacity" in o;
93
93
  }
94
- function ee(o) {
95
- return xt(o) && typeof o.opacity == "number" ? o.opacity : 1;
94
+ function tt(o) {
95
+ return be(o) && typeof o.opacity == "number" ? o.opacity : 1;
96
96
  }
97
- class oe {
97
+ class ot {
98
98
  protocol;
99
99
  clips = /* @__PURE__ */ new Map();
100
100
  loadingClips = /* @__PURE__ */ new Map();
@@ -104,44 +104,54 @@ class oe {
104
104
  mp4States = /* @__PURE__ */ new Map();
105
105
  audioGains = /* @__PURE__ */ new Map();
106
106
  mp4Gains = /* @__PURE__ */ new Map();
107
+ audioElements = /* @__PURE__ */ new Map();
108
+ useMediaElementForAudio = !0;
107
109
  ctx;
108
110
  lastTime = 0;
109
- constructor(t) {
110
- this.protocol = t, this.ctx = new (window.AudioContext || window.webkitAudioContext)();
111
+ constructor(e) {
112
+ this.protocol = e, this.ctx = new (window.AudioContext || window.webkitAudioContext)();
111
113
  }
112
- setProtocol(t) {
113
- this.protocol = t;
114
+ setProtocol(e) {
115
+ this.protocol = e;
114
116
  }
115
- async sync(t, i) {
116
- if (!i) {
117
- this.stopAll(), this.lastTime = t;
117
+ async sync(e, r) {
118
+ if (!r) {
119
+ this.stopAll(), this.lastTime = e;
118
120
  return;
119
121
  }
120
122
  this.ctx.state === "suspended" && await this.ctx.resume().catch(() => {
121
- }), Math.abs(t - this.lastTime) > 1e3 && this.stopAll(), this.lastTime = t;
122
- const r = Mt(this.protocol, t), a = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set();
123
- for (const { segment: c } of r)
123
+ }), Math.abs(e - this.lastTime) > 1e3 && this.stopAll(), this.lastTime = e;
124
+ const i = xe(this.protocol, e), n = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set();
125
+ for (const { segment: c } of i)
124
126
  if (c.segmentType === "audio") {
125
- const d = this.audioKey(c.id);
126
- a.add(d), this.ensureAudioLoop(c, t);
127
+ const s = this.audioKey(c.id);
128
+ n.add(s), this.useMediaElementForAudio ? this.syncAudioElement(c, e) : this.ensureAudioLoop(c, e);
127
129
  } else if (c.segmentType === "frames" && "type" in c && c.type === "video") {
128
- const d = this.videoKey(c.id);
129
- u.add(d);
130
+ const s = this.videoKey(c.id);
131
+ d.add(s);
130
132
  }
131
- for (const [c, d] of this.audioLoops)
132
- if (!a.has(c)) {
133
- d.stop();
134
- for (const l of d.sources)
133
+ for (const [c, s] of this.audioLoops)
134
+ if (!n.has(c)) {
135
+ s.stop();
136
+ for (const l of s.sources)
135
137
  try {
136
138
  l.stop(), l.disconnect();
137
139
  } catch {
138
140
  }
139
141
  this.audioLoops.delete(c), this.audioLoopContexts.delete(c), this.audioGains.delete(c);
140
142
  }
141
- for (const [c, d] of this.mp4Loops)
142
- if (!u.has(c)) {
143
- d.stop();
144
- for (const l of d.sources)
143
+ for (const [c, s] of this.audioElements)
144
+ if (!n.has(c)) {
145
+ try {
146
+ s.el.pause(), s.pendingPlay = void 0, s.lastTimelineMs = void 0, s.lastSourceSec = void 0, s.lastSeekTimelineMs = void 0;
147
+ } catch {
148
+ }
149
+ this.findSegmentInProtocol(s.segmentId) || (this.destroyAudioElement(s.el), this.audioElements.delete(c));
150
+ }
151
+ for (const [c, s] of this.mp4Loops)
152
+ if (!d.has(c)) {
153
+ s.stop();
154
+ for (const l of s.sources)
145
155
  try {
146
156
  l.stop(), l.disconnect();
147
157
  } catch {
@@ -149,872 +159,941 @@ class oe {
149
159
  this.mp4Loops.delete(c), this.mp4States.delete(c), this.mp4Gains.delete(c);
150
160
  }
151
161
  for (const c of this.mp4States.keys())
152
- !u.has(c) && !this.mp4Loops.has(c) && (this.mp4States.delete(c), this.mp4Gains.delete(c));
162
+ !d.has(c) && !this.mp4Loops.has(c) && (this.mp4States.delete(c), this.mp4Gains.delete(c));
153
163
  }
154
164
  /**
155
165
  * Play audio frames from MP4 video directly.
156
166
  * Called by renderer after it gets audio data from clip.tick()
157
167
  */
158
- playMp4AudioFrames(t, i, r) {
159
- if (!i || i.length === 0 || !i[0]?.length)
168
+ playMp4AudioFrames(e, r, i) {
169
+ if (!r || r.length === 0 || !r[0]?.length)
160
170
  return;
161
- const a = this.videoKey(t), u = this.getSegmentVolume(t), c = this.getOrCreateGain(this.mp4Gains, a, u);
171
+ const n = this.videoKey(e), d = this.getSegmentVolume(e), c = this.getOrCreateGain(this.mp4Gains, n, d);
162
172
  this.ctx.state === "suspended" && this.ctx.resume().catch(() => {
163
173
  });
164
- let d = this.mp4States.get(a);
165
- d || (d = {
174
+ let s = this.mp4States.get(n);
175
+ s || (s = {
166
176
  loop: { stop: () => {
167
177
  }, sources: [], isStopped: () => !1 },
168
178
  startUs: 0,
169
179
  startCtxTime: this.ctx.currentTime,
170
180
  fps: 30,
171
181
  nextStartAt: 0
172
- }, this.mp4States.set(a, d)), d.nextStartAt = this.playFrames(i, r, d.nextStartAt ?? 0, c, d.loop.sources);
182
+ }, this.mp4States.set(n, s)), s.nextStartAt = this.playFrames(r, i, s.nextStartAt ?? 0, c, s.loop.sources);
173
183
  }
174
184
  /**
175
185
  * Reset MP4 audio playback state (call when seeking or pausing)
176
186
  */
177
- resetMp4Audio(t) {
178
- const i = this.videoKey(t), r = this.mp4States.get(i);
179
- r && (r.nextStartAt = 0);
187
+ resetMp4Audio(e) {
188
+ const r = this.videoKey(e), i = this.mp4States.get(r);
189
+ i && (i.nextStartAt = 0);
180
190
  }
181
191
  /**
182
192
  * Stop and clean up MP4 audio for a video segment
183
193
  */
184
- stopMp4Audio(t) {
185
- const i = this.videoKey(t), r = this.mp4States.get(i);
186
- if (r) {
187
- r.loop.stop();
188
- for (const a of r.loop.sources)
194
+ stopMp4Audio(e) {
195
+ const r = this.videoKey(e), i = this.mp4States.get(r);
196
+ if (i) {
197
+ i.loop.stop();
198
+ for (const n of i.loop.sources)
189
199
  try {
190
- a.stop(), a.disconnect();
200
+ n.stop(), n.disconnect();
191
201
  } catch {
192
202
  }
193
- this.mp4Loops.delete(i), this.mp4States.delete(i), this.mp4Gains.delete(i);
203
+ this.mp4Loops.delete(r), this.mp4States.delete(r), this.mp4Gains.delete(r);
194
204
  }
195
205
  }
196
206
  /**
197
207
  * @deprecated Use playMp4AudioFrames instead
198
208
  */
199
- ensureMp4Audio(t, i, r, a) {
200
- const u = this.videoKey(t), c = this.getSegmentVolume(t), d = this.getOrCreateGain(this.mp4Gains, u, c), l = this.mp4States.get(u);
209
+ ensureMp4Audio(e, r, i, n) {
210
+ const d = this.videoKey(e), c = this.getSegmentVolume(e), s = this.getOrCreateGain(this.mp4Gains, d, c), l = this.mp4States.get(d);
201
211
  if (l) {
202
- d.gain.value = Math.max(0, c);
203
- const h = (this.ctx.currentTime - l.startCtxTime) * 1e6, m = l.startUs + h;
204
- if (Math.abs(m - r) < 15e4 && l.fps === a)
212
+ s.gain.value = Math.max(0, c);
213
+ const p = (this.ctx.currentTime - l.startCtxTime) * 1e6, w = l.startUs + p;
214
+ if (Math.abs(w - i) < 15e4 && l.fps === n)
205
215
  return;
206
216
  l.loop.stop();
207
- for (const S of l.loop.sources)
217
+ for (const T of l.loop.sources)
208
218
  try {
209
- S.stop(), S.disconnect();
219
+ T.stop(), T.disconnect();
210
220
  } catch {
211
221
  }
212
- this.mp4Loops.delete(u), this.mp4States.delete(u);
222
+ this.mp4Loops.delete(d), this.mp4States.delete(d);
213
223
  }
214
224
  this.ctx.state === "suspended" && this.ctx.resume().catch(() => {
215
225
  });
216
- const p = this.startMp4Loop(i, r, a, d);
217
- this.mp4Loops.set(u, p), this.mp4States.set(u, {
218
- loop: p,
219
- startUs: r,
226
+ const m = this.startMp4Loop(r, i, n, s);
227
+ this.mp4Loops.set(d, m), this.mp4States.set(d, {
228
+ loop: m,
229
+ startUs: i,
220
230
  startCtxTime: this.ctx.currentTime,
221
- fps: a
231
+ fps: n
222
232
  });
223
233
  }
224
234
  destroy() {
225
235
  this.stopAll();
226
- for (const t of this.clips.values())
227
- t.clip.destroy();
236
+ for (const e of this.clips.values())
237
+ e.clip.destroy();
228
238
  this.clips.clear();
239
+ for (const e of this.audioElements.values())
240
+ this.destroyAudioElement(e.el);
241
+ this.audioElements.clear();
229
242
  }
230
243
  stopAll() {
231
- for (const t of this.audioLoops.values()) {
232
- t.stop();
233
- for (const i of t.sources)
244
+ for (const e of this.audioElements.values())
245
+ try {
246
+ e.el.pause(), e.pendingPlay = void 0, e.lastTimelineMs = void 0, e.lastSourceSec = void 0, e.lastSeekTimelineMs = void 0;
247
+ } catch {
248
+ }
249
+ for (const e of this.audioLoops.values()) {
250
+ e.stop();
251
+ for (const r of e.sources)
234
252
  try {
235
- i.stop(0), i.disconnect();
253
+ r.stop(0), r.disconnect();
236
254
  } catch {
237
255
  }
238
- t.sources.length = 0;
256
+ e.sources.length = 0;
239
257
  }
240
- for (const t of this.mp4Loops.values()) {
241
- t.stop();
242
- for (const i of t.sources)
258
+ for (const e of this.mp4Loops.values()) {
259
+ e.stop();
260
+ for (const r of e.sources)
243
261
  try {
244
- i.stop(0), i.disconnect();
262
+ r.stop(0), r.disconnect();
245
263
  } catch {
246
264
  }
247
- t.sources.length = 0;
265
+ e.sources.length = 0;
248
266
  }
249
- for (const t of this.audioGains.values())
267
+ for (const e of this.audioGains.values())
250
268
  try {
251
- t.disconnect();
269
+ e.disconnect();
252
270
  } catch {
253
271
  }
254
- for (const t of this.mp4Gains.values())
272
+ for (const e of this.mp4Gains.values())
255
273
  try {
256
- t.disconnect();
274
+ e.disconnect();
257
275
  } catch {
258
276
  }
259
277
  this.audioLoops.clear(), this.audioLoopContexts.clear(), this.audioGains.clear(), this.mp4Loops.clear(), this.mp4States.clear(), this.mp4Gains.clear();
260
278
  }
261
- async ensureAudioLoop(t, i) {
262
- const r = this.audioKey(t.id), a = await this.loadClip(t);
263
- if (!a)
279
+ async ensureAudioLoop(e, r) {
280
+ const i = this.audioKey(e.id), n = await this.loadClip(e);
281
+ if (!n)
264
282
  return;
265
- const u = t.fromTime ?? 0, c = Math.max(0.1, Math.min(100, t.playRate ?? 1)), d = i - t.startTime, l = u + d * c, p = this.getOrCreateGain(this.audioGains, r, t.volume);
266
- this.applyFadeToGain(t, d, p);
267
- const h = this.audioLoops.get(r);
268
- if (h && !h.isStopped())
283
+ const d = e.fromTime ?? 0, c = this.normalizePlayRate(e.playRate), s = r - e.startTime, l = d + s * c, m = this.getOrCreateGain(this.audioGains, i, e.volume);
284
+ this.applyFadeToGain(e, s, m);
285
+ const p = this.audioLoops.get(i);
286
+ if (p && !p.isStopped())
269
287
  return;
270
- h && (this.audioLoops.delete(r), this.audioLoopContexts.delete(r));
271
- const S = (t.endTime - t.startTime) * c, M = u + S, k = this.startAudioLoop(a.clip, Math.max(0, l) * 1e3, p, c, M * 1e3);
272
- this.audioLoops.set(r, k), this.audioLoopContexts.set(r, {
273
- segment: t,
288
+ p && (this.audioLoops.delete(i), this.audioLoopContexts.delete(i));
289
+ const T = (e.endTime - e.startTime) * c, h = d + T, v = this.startAudioLoop(n.clip, Math.max(0, l) * 1e3, m, c, h * 1e3);
290
+ this.audioLoops.set(i, v), this.audioLoopContexts.set(i, {
291
+ segment: e,
274
292
  startedAt: this.ctx.currentTime,
275
- segmentRelativeMs: d
293
+ segmentRelativeMs: s
276
294
  });
277
295
  }
278
- applyFadeToGain(t, i, r) {
279
- const a = Math.max(0, typeof t.volume == "number" ? t.volume : 1), u = t.endTime - t.startTime, c = t.fadeInDuration ?? 0, d = t.fadeOutDuration ?? 0;
280
- let l = 1;
281
- c > 0 && i < c && (l = Math.max(0, i / c));
282
- const p = u - i;
283
- d > 0 && p < d && (l = Math.min(l, Math.max(0, p / d))), r.gain.value = a * l;
284
- }
285
- startMp4Loop(t, i, r, a) {
286
- let u = !1, c = i, d = 0, l = !0;
287
- const p = Math.round(1e3 / Math.max(r || 30, 1) * 1e3), h = this.getClipSampleRate(t), m = [], S = window.setInterval(async () => {
288
- if (u)
296
+ syncAudioElement(e, r) {
297
+ const i = this.audioKey(e.id), n = this.getOrCreateAudioElementState(i, e), d = r - e.startTime, c = this.normalizePlayRate(e.playRate), s = e.fromTime ?? 0, l = s + d * c, p = Math.max(0, e.endTime - e.startTime) * c, w = s + p, T = Math.max(0, w) / 1e3, h = Number.isFinite(n.el.duration) ? Math.max(0, n.el.duration) : void 0, v = h === void 0 ? T : Math.min(T, h), y = Math.max(0, Math.min(l / 1e3, v)), g = l / 1e3 >= v - 0.01;
298
+ Math.abs(n.el.playbackRate - c) > 1e-3 && (n.el.playbackRate = c);
299
+ const R = this.computeSegmentVolume(e, d);
300
+ Math.abs(n.el.volume - R) > 1e-3 && (n.el.volume = R);
301
+ const I = 0.24, E = 500, A = 300, k = -40, K = n.lastTimelineMs, z = n.lastSourceSec, D = K === void 0 ? 0 : r - K;
302
+ let O = !1;
303
+ if (K === void 0)
304
+ O = !0;
305
+ else if (D < k || D > A)
306
+ O = !0;
307
+ else if (z !== void 0) {
308
+ const L = z + D * c / 1e3, W = Math.abs(L - y), j = n.lastSeekTimelineMs === void 0 || r - n.lastSeekTimelineMs >= E;
309
+ W > I && j && (O = !0);
310
+ }
311
+ if (O && Math.abs(n.el.currentTime - y) > 0.06)
312
+ try {
313
+ n.el.currentTime = y, n.lastSeekTimelineMs = r;
314
+ } catch {
315
+ }
316
+ if (n.lastTimelineMs = r, n.lastSourceSec = y, g) {
317
+ if (!n.el.paused)
318
+ try {
319
+ n.el.pause();
320
+ } catch {
321
+ }
322
+ n.pendingPlay = void 0;
323
+ return;
324
+ }
325
+ if (n.el.paused && !n.pendingPlay) {
326
+ const L = n.el.play();
327
+ L && typeof L.then == "function" && (n.pendingPlay = L.catch(() => {
328
+ }).finally(() => {
329
+ n.pendingPlay = void 0;
330
+ }));
331
+ }
332
+ }
333
+ applyFadeToGain(e, r, i) {
334
+ i.gain.value = this.computeSegmentVolume(e, r);
335
+ }
336
+ startMp4Loop(e, r, i, n) {
337
+ let d = !1, c = r, s = 0, l = !0;
338
+ const m = Math.round(1e3 / Math.max(i || 30, 1) * 1e3), p = this.getClipSampleRate(e), w = [], T = window.setInterval(async () => {
339
+ if (d)
289
340
  return;
290
- const { audio: M, state: k } = await t.tick(Math.round(c));
291
- if (c += p, k === "done")
341
+ const { audio: h, state: v } = await e.tick(Math.round(c));
342
+ if (c += m, v === "done")
292
343
  return;
293
344
  if (l) {
294
345
  l = !1;
295
346
  return;
296
347
  }
297
- (M?.[0]?.length ?? 0) !== 0 && (d = this.playFrames(M, h, d, a, m));
298
- }, Math.round(1e3 / Math.max(r || 30, 1)));
348
+ (h?.[0]?.length ?? 0) !== 0 && (s = this.playFrames(h, p, s, n, w));
349
+ }, Math.round(1e3 / Math.max(i || 30, 1)));
299
350
  return {
300
- sources: m,
351
+ sources: w,
301
352
  stop: () => {
302
- u = !0, window.clearInterval(S);
353
+ d = !0, window.clearInterval(T);
303
354
  },
304
- isStopped: () => u
355
+ isStopped: () => d
305
356
  };
306
357
  }
307
- startAudioLoop(t, i, r, a = 1, u) {
308
- let c = !1, d = i, l = 0, p = !1;
309
- const h = this.getClipSampleRate(t), m = [], M = Math.round(1e5 * a), k = async () => {
358
+ startAudioLoop(e, r, i, n = 1, d) {
359
+ let c = !1, s = r, l = 0, m = !1;
360
+ const p = this.getClipSampleRate(e), w = [], h = Math.round(1e5 * n), v = async () => {
310
361
  if (c)
311
362
  return;
312
- if (p || (i > 0 && await t.tick(i), p = !0), d += M, u !== void 0 && d > u) {
363
+ if (m || (r > 0 && await e.tick(r), m = !0), s += h, d !== void 0 && s > d) {
313
364
  c = !0;
314
365
  return;
315
366
  }
316
- const { audio: w, state: x } = await t.tick(d);
367
+ const { audio: y, state: g } = await e.tick(s);
317
368
  if (c)
318
369
  return;
319
- if (x === "done") {
370
+ if (g === "done") {
320
371
  c = !0;
321
372
  return;
322
373
  }
323
- if ((w?.[0]?.length ?? 0) === 0) {
374
+ if ((y?.[0]?.length ?? 0) === 0) {
324
375
  c = !0;
325
376
  return;
326
377
  }
327
- const E = a !== 1 ? this.resampleForPlayRate(w, a) : w;
328
- l = this.playFrames(E, h, l, r, m), c || setTimeout(() => k(), 0);
378
+ l = this.playFrames(y, p, l, i, w, n), c || setTimeout(() => v(), 0);
329
379
  };
330
- return k(), {
331
- sources: m,
380
+ return v(), {
381
+ sources: w,
332
382
  stop: () => {
333
383
  c = !0;
334
384
  },
335
- isStopped: () => c
385
+ // Treat loop as active while there are still scheduled sources playing.
386
+ isStopped: () => c && w.length === 0
336
387
  };
337
388
  }
338
- resampleForPlayRate(t, i) {
339
- const r = Math.round(t[0].length / i);
340
- return r <= 0 ? t : t.map((a) => {
341
- const u = new Float32Array(r);
342
- for (let c = 0; c < r; c++) {
343
- const d = c * i, l = Math.floor(d), p = Math.min(l + 1, a.length - 1), h = d - l;
344
- u[c] = a[l] * (1 - h) + a[p] * h;
345
- }
346
- return u;
347
- });
348
- }
349
- playFrames(t, i, r, a, u) {
350
- const c = Math.max(t.length, 1), d = t[0]?.length ?? 0;
351
- if (d === 0)
352
- return r;
353
- const l = this.ctx.createBuffer(c, d, i);
354
- for (let m = 0; m < c; m++) {
355
- const S = t[m] ?? new Float32Array(d);
356
- l.copyToChannel(new Float32Array(S), m);
389
+ playFrames(e, r, i, n, d, c = 1) {
390
+ const s = Math.max(e.length, 1), l = e[0]?.length ?? 0;
391
+ if (l === 0)
392
+ return i;
393
+ const m = this.ctx.createBuffer(s, l, r);
394
+ for (let h = 0; h < s; h++) {
395
+ const v = e[h] ?? new Float32Array(l);
396
+ m.copyToChannel(new Float32Array(v), h);
357
397
  }
358
398
  const p = this.ctx.createBufferSource();
359
- p.buffer = l, p.connect(a);
360
- const h = Math.max(this.ctx.currentTime, r);
361
- if (p.start(h), u) {
362
- u.push(p);
363
- const m = l.duration * 1e3;
399
+ p.buffer = m;
400
+ const w = Math.max(0.1, c);
401
+ p.playbackRate.value = w, p.connect(n);
402
+ const T = Math.max(this.ctx.currentTime, i);
403
+ if (p.start(T), d) {
404
+ d.push(p);
405
+ const h = m.duration / w * 1e3;
364
406
  setTimeout(() => {
365
- const S = u.indexOf(p);
366
- S > -1 && u.splice(S, 1);
367
- }, m + 100);
407
+ const v = d.indexOf(p);
408
+ v > -1 && d.splice(v, 1);
409
+ }, h + 100);
368
410
  }
369
- return h + l.duration;
411
+ return T + m.duration / w;
370
412
  }
371
- getOrCreateGain(t, i, r) {
372
- const a = t.get(i);
373
- if (a)
374
- return typeof r == "number" && (a.gain.value = Math.max(0, r)), a;
375
- const u = this.ctx.createGain();
376
- return u.gain.value = Math.max(0, typeof r == "number" ? r : 1), u.connect(this.ctx.destination), t.set(i, u), u;
413
+ getOrCreateGain(e, r, i) {
414
+ const n = e.get(r);
415
+ if (n)
416
+ return typeof i == "number" && (n.gain.value = this.normalizeVolume(i)), n;
417
+ const d = this.ctx.createGain();
418
+ return d.gain.value = this.normalizeVolume(i), d.connect(this.ctx.destination), e.set(r, d), d;
377
419
  }
378
- audioKey(t) {
379
- return `audio:${t}`;
420
+ getOrCreateAudioElementState(e, r) {
421
+ const i = this.audioElements.get(e);
422
+ if (i)
423
+ return i.url !== r.url && (i.el.pause(), i.el.src = r.url, i.el.currentTime = 0, i.url = r.url, i.pendingPlay = void 0, i.lastTimelineMs = void 0, i.lastSourceSec = void 0, i.lastSeekTimelineMs = void 0), i;
424
+ const n = new Audio(r.url);
425
+ n.preload = "auto", n.loop = !1, n.volume = this.normalizeVolume(r.volume), n.playbackRate = this.normalizePlayRate(r.playRate);
426
+ const d = {
427
+ segmentId: r.id,
428
+ url: r.url,
429
+ el: n
430
+ };
431
+ return this.audioElements.set(e, d), d;
380
432
  }
381
- videoKey(t) {
382
- return `video:${t}`;
433
+ destroyAudioElement(e) {
434
+ try {
435
+ e.pause();
436
+ } catch {
437
+ }
438
+ e.removeAttribute("src");
439
+ try {
440
+ e.load();
441
+ } catch {
442
+ }
383
443
  }
384
- async loadClip(t) {
385
- const i = this.clips.get(t.id);
386
- if (i)
387
- return i;
388
- const r = this.loadingClips.get(t.id);
444
+ normalizePlayRate(e) {
445
+ return typeof e != "number" || !Number.isFinite(e) ? 1 : Math.max(0.1, Math.min(100, e));
446
+ }
447
+ normalizeVolume(e) {
448
+ return typeof e != "number" || !Number.isFinite(e) ? 1 : Math.max(0, Math.min(1, e));
449
+ }
450
+ computeSegmentVolume(e, r) {
451
+ const i = this.normalizeVolume(e.volume), n = Math.max(0, e.endTime - e.startTime), d = Math.max(0, e.fadeInDuration ?? 0), c = Math.max(0, e.fadeOutDuration ?? 0);
452
+ let s = 1;
453
+ d > 0 && r < d && (s = Math.max(0, r / d));
454
+ const l = n - r;
455
+ return c > 0 && l < c && (s = Math.min(s, Math.max(0, l / c))), i * s;
456
+ }
457
+ audioKey(e) {
458
+ return `audio:${e}`;
459
+ }
460
+ videoKey(e) {
461
+ return `video:${e}`;
462
+ }
463
+ async loadClip(e) {
464
+ const r = this.clips.get(e.id);
389
465
  if (r)
390
466
  return r;
391
- const a = (async () => {
467
+ const i = this.loadingClips.get(e.id);
468
+ if (i)
469
+ return i;
470
+ const n = (async () => {
392
471
  try {
393
- const u = await fetch(t.url);
394
- if (!u.body) {
395
- this.loadingClips.delete(t.id);
472
+ const d = await fetch(e.url);
473
+ if (!d.body) {
474
+ this.loadingClips.delete(e.id);
396
475
  return;
397
476
  }
398
- const c = new jt(u.body), d = { clip: c, ready: c.ready };
399
- if (await c.ready, !this.findSegmentInProtocol(t.id)) {
400
- c.destroy(), this.loadingClips.delete(t.id);
477
+ const c = new je(d.body), s = { clip: c, ready: c.ready };
478
+ if (await c.ready, !this.findSegmentInProtocol(e.id)) {
479
+ c.destroy(), this.loadingClips.delete(e.id);
401
480
  return;
402
481
  }
403
- return this.clips.set(t.id, d), this.loadingClips.delete(t.id), d;
404
- } catch (u) {
405
- console.error(`[AudioManager] Failed to load audio ${t.url}`, u), this.loadingClips.delete(t.id);
482
+ return this.clips.set(e.id, s), this.loadingClips.delete(e.id), s;
483
+ } catch (d) {
484
+ console.error(`[AudioManager] Failed to load audio ${e.url}`, d), this.loadingClips.delete(e.id);
406
485
  return;
407
486
  }
408
487
  })();
409
- return this.loadingClips.set(t.id, a), a;
488
+ return this.loadingClips.set(e.id, n), n;
410
489
  }
411
- findSegmentInProtocol(t) {
412
- for (const i of this.protocol.tracks)
413
- for (const r of i.children)
414
- if (r.id === t) return !0;
490
+ findSegmentInProtocol(e) {
491
+ for (const r of this.protocol.tracks)
492
+ for (const i of r.children)
493
+ if (i.id === e) return !0;
415
494
  return !1;
416
495
  }
417
- getSegmentVolume(t) {
418
- for (const i of this.protocol.tracks)
419
- for (const r of i.children) {
420
- if (r.id !== t)
496
+ getSegmentVolume(e) {
497
+ for (const r of this.protocol.tracks)
498
+ for (const i of r.children) {
499
+ if (i.id !== e)
421
500
  continue;
422
- const a = r.volume;
423
- return typeof a == "number" ? a : 1;
501
+ const n = i.volume;
502
+ return this.normalizeVolume(n);
424
503
  }
425
504
  return 1;
426
505
  }
427
- getClipSampleRate(t) {
428
- const i = t.meta;
429
- if (!i)
506
+ getClipSampleRate(e) {
507
+ const r = e.meta;
508
+ if (!r)
430
509
  return 48e3;
431
- const r = i.audioSampleRate;
432
- if (typeof r == "number" && r > 0)
433
- return r;
434
- const a = i.sampleRate;
435
- return typeof a == "number" && a > 0 ? a : 48e3;
510
+ const i = r.audioSampleRate;
511
+ if (typeof i == "number" && i > 0)
512
+ return i;
513
+ const n = r.sampleRate;
514
+ return typeof n == "number" && n > 0 ? n : 48e3;
436
515
  }
437
516
  }
438
- const re = 100, $ = /* @__PURE__ */ new Map();
439
- let ie = re;
440
- function ne(o, t) {
441
- $.delete(o), $.set(o, t);
517
+ const it = 100, U = /* @__PURE__ */ new Map();
518
+ let rt = it;
519
+ function nt(o, e) {
520
+ U.delete(o), U.set(o, e);
442
521
  }
443
- function ae() {
444
- for (; $.size > ie; ) {
445
- const [o, t] = $.entries().next().value;
446
- $.delete(o), t.close?.();
522
+ function at() {
523
+ for (; U.size > rt; ) {
524
+ const [o, e] = U.entries().next().value;
525
+ U.delete(o), e.close?.();
447
526
  }
448
527
  }
449
- function se(o) {
450
- return o.map((t) => t.content).filter(Boolean).join(`
528
+ function st(o) {
529
+ return o.map((e) => e.content).filter(Boolean).join(`
451
530
  `);
452
531
  }
453
- function ce(o) {
454
- const t = Array.isArray(o.fontFamily) ? o.fontFamily.join(", ") : o.fontFamily, i = o.fontSize ?? 32, r = o.fontWeight ?? "normal", a = o.fontStyle ?? "normal", u = o.fill ?? "#ffffff", c = o.align ?? "left", d = [
455
- `font-size: ${i}px`,
456
- `font-weight: ${r}`,
457
- `font-style: ${a}`,
458
- `color: ${u}`,
532
+ function ct(o) {
533
+ const e = Array.isArray(o.fontFamily) ? o.fontFamily.join(", ") : o.fontFamily, r = o.fontSize ?? 32, i = o.fontWeight ?? "normal", n = o.fontStyle ?? "normal", d = o.fill ?? "#ffffff", c = o.align ?? "left", s = [
534
+ `font-size: ${r}px`,
535
+ `font-weight: ${i}`,
536
+ `font-style: ${n}`,
537
+ `color: ${d}`,
459
538
  `text-align: ${c}`,
460
539
  "white-space: pre-wrap"
461
540
  ];
462
- if (t && d.push(`font-family: ${t}`), typeof o.letterSpacing == "number" && d.push(`letter-spacing: ${o.letterSpacing}px`), typeof o.leading == "number" && d.push(`line-height: ${o.leading}px`), o.background?.color && d.push(`background: ${o.background.color}`), o.stroke?.color && typeof o.stroke.width == "number" && d.push(`-webkit-text-stroke: ${o.stroke.width}px ${o.stroke.color}`), o.underline && d.push("text-decoration: underline"), o.dropShadow?.color && typeof o.dropShadow.distance == "number") {
463
- const l = (o.dropShadow.angle ?? 45) * (Math.PI / 180), p = Math.cos(l) * o.dropShadow.distance, h = Math.sin(l) * o.dropShadow.distance, m = o.dropShadow.blur ?? 0;
464
- d.push(`text-shadow: ${p}px ${h}px ${m}px ${o.dropShadow.color}`);
541
+ if (e && s.push(`font-family: ${e}`), typeof o.letterSpacing == "number" && s.push(`letter-spacing: ${o.letterSpacing}px`), typeof o.leading == "number" && s.push(`line-height: ${o.leading}px`), o.background?.color && s.push(`background: ${o.background.color}`), o.stroke?.color && typeof o.stroke.width == "number" && s.push(`-webkit-text-stroke: ${o.stroke.width}px ${o.stroke.color}`), o.underline && s.push("text-decoration: underline"), o.dropShadow?.color && typeof o.dropShadow.distance == "number") {
542
+ const l = (o.dropShadow.angle ?? 45) * (Math.PI / 180), m = Math.cos(l) * o.dropShadow.distance, p = Math.sin(l) * o.dropShadow.distance, w = o.dropShadow.blur ?? 0;
543
+ s.push(`text-shadow: ${m}px ${p}px ${w}px ${o.dropShadow.color}`);
465
544
  }
466
- return d.join("; ");
545
+ return s.join("; ");
467
546
  }
468
- async function de(o, t) {
469
- const i = `${t}::${o}`, r = $.get(i);
470
- if (r)
471
- return ne(i, r), r;
472
- const a = await _t(o, t);
473
- return $.set(i, a), ae(), a;
547
+ async function ut(o, e) {
548
+ const r = `${e}::${o}`, i = U.get(r);
549
+ if (i)
550
+ return nt(r, i), i;
551
+ const n = await _e(o, e);
552
+ return U.set(r, n), at(), n;
474
553
  }
475
- const ue = "/video-editor-res";
476
- async function le(o) {
477
- const t = Gt(), i = Kt(o.protocol) ? o.protocol : ut(o.protocol), r = ut(
478
- t.verify(pt(lt(i)))
479
- ), a = o.app ?? await Xt(o.appOptions), u = new Yt();
480
- a.stage.addChild(u);
481
- const c = Nt({ dir: o.resourceDir }), d = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Set(), m = /* @__PURE__ */ new Set(), S = o.videoSourceMode ?? "auto", M = /* @__PURE__ */ new Map(), k = /* @__PURE__ */ new Map(), w = ft(0), x = ft(!1), R = qt(() => J(r.value)), E = new oe(r.value);
482
- let A, L = 0, C = 0;
483
- async function St(e) {
484
- const s = C, { protocol: n, at: f, layer: y } = e, v = Ot(n, f), g = Mt(n, v), T = e.app.renderer.width, b = e.app.renderer.height;
485
- E.sync(f, x.value);
486
- const I = [];
487
- for (const { segment: U } of g) {
488
- if (s !== C)
554
+ const dt = "/video-editor-res";
555
+ async function lt(o) {
556
+ const e = De(), r = Ke(o.protocol) ? o.protocol : pe(o.protocol), i = pe(
557
+ e.verify(ye(he(r)))
558
+ ), n = o.app ?? await Xe(o.appOptions), d = new Ye();
559
+ n.stage.addChild(d);
560
+ const c = Ne({ dir: o.resourceDir }), s = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Set(), w = /* @__PURE__ */ new Set(), T = o.videoSourceMode ?? "auto", h = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), y = me(0), g = me(!1), R = qe(() => te(i.value)), I = new ot(i.value);
561
+ let E, A = 0, k = 0;
562
+ async function K(t) {
563
+ const u = k, { protocol: a, at: f, layer: M } = t, S = Oe(a, f), x = xe(a, S), b = t.app.renderer.width, C = t.app.renderer.height;
564
+ I.sync(f, g.value);
565
+ const P = [];
566
+ for (const { segment: N } of x) {
567
+ if (u !== k)
489
568
  return;
490
- const P = await e.getDisplay(U);
491
- if (s !== C)
569
+ const V = await t.getDisplay(N);
570
+ if (u !== k)
492
571
  return;
493
- if (P && !P.destroyed) {
494
- if (Zt(P, U, T, b), Pt(U) && await j(U, v), s !== C)
572
+ if (V && !V.destroyed) {
573
+ if (Ze(V, N, b, C), Fe(N) && await J(N, S), u !== k)
495
574
  return;
496
- I.push(P);
575
+ P.push(V);
497
576
  }
498
577
  }
499
- if (s !== C)
578
+ if (u !== k)
500
579
  return;
501
- y.removeChildren();
502
- const F = I.filter(Boolean);
503
- F.length && y.addChild(...F), s === C && e.app.render();
504
- }
505
- const z = fe(() => St({
506
- app: a,
507
- layer: u,
508
- protocol: r.value,
509
- at: w.value,
510
- getDisplay: Rt
511
- })), Q = Bt();
512
- Q.run(() => {
513
- W(
514
- () => lt(i),
515
- (e) => {
580
+ M.removeChildren();
581
+ const F = P.filter(Boolean);
582
+ F.length && M.addChild(...F), u === k && t.app.render();
583
+ }
584
+ const z = ft(() => K({
585
+ app: n,
586
+ layer: d,
587
+ protocol: i.value,
588
+ at: y.value,
589
+ getDisplay: Re
590
+ })), D = Be();
591
+ D.run(() => {
592
+ Q(
593
+ () => he(r),
594
+ (t) => {
516
595
  try {
517
- r.value = t.verify(pt(e));
518
- } catch (s) {
519
- console.error("[renderer] invalid protocol update", s);
596
+ i.value = e.verify(ye(t));
597
+ } catch (u) {
598
+ console.error("[renderer] invalid protocol update", u);
520
599
  return;
521
600
  }
522
- E.setProtocol(r.value), C += 1, Z(), o.warmUpResources !== !1 && Tt(r.value), bt(r.value), K(), o.manualRender || z();
601
+ I.setProtocol(i.value), k += 1, j(), o.warmUpResources !== !1 && L(i.value), W(i.value), O(), o.manualRender || z();
523
602
  },
524
603
  { deep: !0, immediate: !0 }
525
- ), o.manualRender || W(w, () => {
526
- K(), z();
527
- }), W(R, () => K());
604
+ ), o.manualRender || Q(y, () => {
605
+ O(), z();
606
+ }), Q(R, () => O());
528
607
  });
529
- function K() {
530
- const e = R.value;
531
- e <= 0 ? w.value = 0 : w.value > e ? w.value = e : w.value < 0 && (w.value = 0);
608
+ function O() {
609
+ const t = R.value;
610
+ t <= 0 ? y.value = 0 : y.value > t ? y.value = t : y.value < 0 && (y.value = 0);
532
611
  }
533
- function Tt(e) {
534
- for (const s of Qt(e))
535
- d.has(s) || (d.add(s), st(s) !== "video" && it(s) && c.add(s).catch(() => {
612
+ function L(t) {
613
+ for (const u of Qe(t))
614
+ s.has(u) || (s.add(u), de(u) !== "video" && se(u) && c.add(u).catch(() => {
536
615
  }));
537
616
  }
538
- function bt(e) {
539
- const s = /* @__PURE__ */ new Set();
540
- for (const n of e.tracks)
541
- for (const f of n.children)
542
- s.add(f.id);
543
- for (const [n, f] of l)
544
- s.has(n) || (f.destroy(), l.delete(n));
545
- for (const [n, f] of M)
546
- s.has(n) || (nt(f), M.delete(n));
547
- }
548
- function Z() {
549
- u.removeChildren();
550
- for (const e of l.values())
551
- e.destroy();
552
- l.clear(), p.clear();
553
- for (const e of M.values())
554
- nt(e);
555
- M.clear();
556
- }
557
- function tt() {
558
- x.value || (x.value = !0, L = performance.now(), A = requestAnimationFrame(et));
559
- }
560
- function q() {
561
- x.value = !1, A !== void 0 && cancelAnimationFrame(A), A = void 0, E.sync(w.value, !1), o.freezeOnPause !== !1 && $t();
562
- }
563
- function et() {
564
- ot(), x.value && (A = requestAnimationFrame(et));
565
- }
566
- function ot(e) {
567
- if (!x.value && e === void 0)
617
+ function W(t) {
618
+ const u = /* @__PURE__ */ new Set();
619
+ for (const a of t.tracks)
620
+ for (const f of a.children)
621
+ u.add(f.id);
622
+ for (const [a, f] of l)
623
+ u.has(a) || (f.destroy(), l.delete(a));
624
+ for (const [a, f] of h)
625
+ u.has(a) || (ce(f), h.delete(a));
626
+ }
627
+ function j() {
628
+ d.removeChildren();
629
+ for (const t of l.values())
630
+ t.destroy();
631
+ l.clear(), m.clear();
632
+ for (const t of h.values())
633
+ ce(t);
634
+ h.clear();
635
+ }
636
+ function ie() {
637
+ g.value || (g.value = !0, A = performance.now(), E = requestAnimationFrame(re));
638
+ }
639
+ function Y() {
640
+ g.value = !1, E !== void 0 && cancelAnimationFrame(E), E = void 0, I.sync(y.value, !1), o.freezeOnPause !== !1 && Ve();
641
+ }
642
+ function re() {
643
+ ne(), g.value && (E = requestAnimationFrame(re));
644
+ }
645
+ function ne(t) {
646
+ if (!g.value && t === void 0)
568
647
  return;
569
- const s = performance.now(), n = e ?? (L ? s - L : 0);
570
- L = s, n !== 0 && (w.value = X(
571
- w.value + n,
648
+ const u = performance.now(), a = t ?? (A ? u - A : 0);
649
+ A = u, a !== 0 && (y.value = ee(
650
+ y.value + a,
572
651
  0,
573
652
  R.value || Number.POSITIVE_INFINITY
574
- ), R.value > 0 && w.value >= R.value && q());
653
+ ), R.value > 0 && y.value >= R.value && Y());
575
654
  }
576
- function kt(e) {
577
- w.value = X(e, 0, R.value || Number.POSITIVE_INFINITY);
655
+ function ke(t) {
656
+ y.value = ee(t, 0, R.value || Number.POSITIVE_INFINITY);
578
657
  }
579
- async function Ct(e) {
580
- w.value = X(e, 0, R.value || Number.POSITIVE_INFINITY), await z();
658
+ async function Ce(t) {
659
+ y.value = ee(t, 0, R.value || Number.POSITIVE_INFINITY), await z();
581
660
  }
582
- async function Rt(e) {
583
- const s = l.get(e.id);
584
- if (s)
585
- return s;
586
- const n = p.get(e.id);
587
- if (n)
588
- return n;
589
- const f = At(e);
590
- p.set(e.id, f);
591
- const y = await f;
592
- return y && l.set(e.id, y), p.delete(e.id), y;
593
- }
594
- async function At(e) {
595
- if (e.segmentType === "frames" || e.segmentType === "sticker") {
596
- if (!e.url)
597
- return Y(e.segmentType);
598
- if ("type" in e && e.type === "video" && ct(e.url)) {
599
- const n = await Et(e);
600
- return n || Y(e.segmentType, e.url);
661
+ async function Re(t) {
662
+ const u = l.get(t.id);
663
+ if (u)
664
+ return u;
665
+ const a = m.get(t.id);
666
+ if (a)
667
+ return a;
668
+ const f = Ee(t);
669
+ m.set(t.id, f);
670
+ const M = await f;
671
+ return M && l.set(t.id, M), m.delete(t.id), M;
672
+ }
673
+ async function Ee(t) {
674
+ if (t.segmentType === "frames" || t.segmentType === "sticker") {
675
+ if (!t.url)
676
+ return Z(t.segmentType);
677
+ if ("type" in t && t.type === "video" && le(t.url)) {
678
+ const a = await Ie(t);
679
+ return a || Z(t.segmentType, t.url);
601
680
  }
602
- const s = await Lt(e.url);
603
- return s ? new O(s) : Y(e.segmentType, e.url);
681
+ const u = await Pe(t.url);
682
+ return u ? new $(u) : Z(t.segmentType, t.url);
604
683
  }
605
- if (e.segmentType === "text")
606
- return await It(e);
607
- e.segmentType === "effect" || e.segmentType;
684
+ if (t.segmentType === "text")
685
+ return await Ae(t);
686
+ t.segmentType === "effect" || t.segmentType;
608
687
  }
609
- async function It(e) {
610
- const s = se(e.texts);
611
- if (!s)
688
+ async function Ae(t) {
689
+ const u = st(t.texts);
690
+ if (!u)
612
691
  return;
613
- const [n] = e.texts;
614
- if (!n)
692
+ const [a] = t.texts;
693
+ if (!a)
615
694
  return;
616
- const f = await de(s, ce(n)), y = V.from(f);
617
- return new O(y);
695
+ const f = await ut(u, ct(a)), M = G.from(f);
696
+ return new $(M);
618
697
  }
619
- async function Lt(e) {
620
- const s = e.startsWith("data:"), n = /^https?:\/\//.test(e);
621
- if (!s && !n)
698
+ async function Pe(t) {
699
+ const u = t.startsWith("data:"), a = /^https?:\/\//.test(t);
700
+ if (!u && !a)
622
701
  try {
623
- await c.add(e);
624
- const f = await c.get(e);
702
+ await c.add(t);
703
+ const f = await c.get(t);
625
704
  if (f instanceof HTMLImageElement)
626
- return V.from(f);
705
+ return G.from(f);
627
706
  } catch {
628
707
  }
629
- return await Vt(e);
630
- }
631
- async function Et(e) {
632
- const s = M.get(e.id);
633
- if (s)
634
- return s.sprite;
635
- const n = N(e.url), f = S !== "element", y = S !== "mp4clip";
636
- if (n && h.has(n)) {
637
- if (!y)
638
- throw new Error(`[renderer] MP4Clip unsupported for ${e.url}`);
639
- const v = await D(e.url).catch((g) => {
640
- console.warn("[renderer] failed to load video via <video>", e.url, g);
708
+ return await Ue(t);
709
+ }
710
+ async function Ie(t) {
711
+ const u = h.get(t.id);
712
+ if (u)
713
+ return u.sprite;
714
+ const a = _(t.url), f = T !== "element", M = T !== "mp4clip";
715
+ if (a && p.has(a)) {
716
+ if (!M)
717
+ throw new Error(`[renderer] MP4Clip unsupported for ${t.url}`);
718
+ const S = await q(t.url).catch((x) => {
719
+ console.warn("[renderer] failed to load video via <video>", t.url, x);
641
720
  });
642
- return v ? (M.set(e.id, v), v.sprite) : void 0;
721
+ return S ? (h.set(t.id, S), S.sprite) : void 0;
643
722
  }
644
723
  if (f) {
645
- const v = await at(e.url).catch((g) => {
646
- if (n && B(g) && h.add(n), (!n || !m.has(n)) && (n && m.add(n), console.warn("[renderer] failed to load video via MP4Clip", e.url, g)), !y)
647
- throw g;
724
+ const S = await ue(t.url).catch((x) => {
725
+ if (a && X(x) && p.add(a), (!a || !w.has(a)) && (a && w.add(a), console.warn("[renderer] failed to load video via MP4Clip", t.url, x)), !M)
726
+ throw x;
648
727
  });
649
- if (v)
650
- return console.info("[renderer] video source: mp4clip", e.url), M.set(e.id, v), v.sprite;
728
+ if (S)
729
+ return console.info("[renderer] video source: mp4clip", t.url), h.set(t.id, S), S.sprite;
651
730
  }
652
- if (y) {
653
- const v = await D(e.url).catch((g) => {
654
- console.warn("[renderer] failed to load video via <video>", e.url, g);
731
+ if (M) {
732
+ const S = await q(t.url).catch((x) => {
733
+ console.warn("[renderer] failed to load video via <video>", t.url, x);
655
734
  });
656
- if (v)
657
- return console.info("[renderer] video source: element", e.url), M.set(e.id, v), v.sprite;
735
+ if (S)
736
+ return console.info("[renderer] video source: element", t.url), h.set(t.id, S), S.sprite;
658
737
  }
659
738
  }
660
- function B(e) {
661
- if (!(e instanceof Error))
739
+ function X(t) {
740
+ if (!(t instanceof Error))
662
741
  return !1;
663
- const s = e.message || "";
664
- return s.includes("stream is done") || s.includes("not emit ready") || s.includes("tick video timeout");
742
+ const u = t.message || "";
743
+ return u.includes("stream is done") || u.includes("not emit ready") || u.includes("tick video timeout");
665
744
  }
666
- async function j(e, s) {
667
- const n = M.get(e.id);
668
- if (n)
745
+ async function J(t, u) {
746
+ const a = h.get(t.id);
747
+ if (a)
669
748
  try {
670
- const f = e.fromTime ?? 0, y = Math.max(0, s - e.startTime + f), v = Math.floor(y * 1e3);
671
- if (n.kind === "frozen") {
672
- const T = N(e.url);
673
- if (!T)
749
+ const f = t.fromTime ?? 0, M = Math.max(0, u - t.startTime + f), S = Math.floor(M * 1e3);
750
+ if (a.kind === "frozen") {
751
+ const b = _(t.url);
752
+ if (!b)
674
753
  return;
675
- const b = await Ft(e.url, T, { sprite: n.sprite, oldTexture: n.texture });
676
- return b ? (M.set(e.id, b), await j(e, s)) : void 0;
754
+ const C = await Le(t.url, b, { sprite: a.sprite, oldTexture: a.texture });
755
+ return C ? (h.set(t.id, C), await J(t, u)) : void 0;
677
756
  }
678
- if (n.kind === "mp4clip")
757
+ if (a.kind === "mp4clip")
679
758
  try {
680
- const T = await n.clip.tick(v);
681
- if (T.video) {
682
- const b = n.canvas.getContext("2d");
683
- b && (b.drawImage(T.video, 0, 0, n.canvas.width, n.canvas.height), dt(n.texture)), T.video.close();
759
+ const b = await a.clip.tick(S);
760
+ if (b.video) {
761
+ const C = a.canvas.getContext("2d");
762
+ C && (C.drawImage(b.video, 0, 0, a.canvas.width, a.canvas.height), fe(a.texture)), b.video.close();
684
763
  }
685
- if (x.value && T.audio && T.audio.length > 0) {
686
- const b = n.clip.meta?.audioSampleRate ?? 48e3;
687
- E.playMp4AudioFrames(e.id, T.audio, b);
764
+ if (g.value && b.audio && b.audio.length > 0) {
765
+ const C = a.clip.meta?.audioSampleRate ?? 48e3;
766
+ I.playMp4AudioFrames(t.id, b.audio, C);
688
767
  }
689
768
  return;
690
- } catch (T) {
691
- const b = N(e.url);
692
- if (b && B(T) && (h.add(b), n.clip.destroy(), S !== "mp4clip")) {
693
- const I = await D(e.url, { sprite: n.sprite, oldTexture: n.texture }).catch((F) => {
694
- console.warn("[renderer] failed to fallback to <video> after MP4Clip error", e.url, F);
769
+ } catch (b) {
770
+ const C = _(t.url);
771
+ if (C && X(b) && (p.add(C), a.clip.destroy(), T !== "mp4clip")) {
772
+ const P = await q(t.url, { sprite: a.sprite, oldTexture: a.texture }).catch((F) => {
773
+ console.warn("[renderer] failed to fallback to <video> after MP4Clip error", t.url, F);
695
774
  });
696
- if (I)
697
- return M.set(e.id, I), await j(e, s);
775
+ if (P)
776
+ return h.set(t.id, P), await J(t, u);
698
777
  }
699
- b && !m.has(b) && (m.add(b), console.warn("[renderer] MP4Clip tick failed", e.url, T));
778
+ C && !w.has(C) && (w.add(C), console.warn("[renderer] MP4Clip tick failed", t.url, b));
700
779
  return;
701
780
  }
702
- const g = y / 1e3;
703
- if (!Number.isFinite(g) || n.kind !== "element")
781
+ const x = M / 1e3;
782
+ if (!Number.isFinite(x) || a.kind !== "element")
704
783
  return;
705
- await Ut(n, {
706
- targetSec: g,
707
- playbackRate: e.playRate ?? 1,
708
- volume: e.volume ?? 1
784
+ await $e(a, {
785
+ targetSec: x,
786
+ playbackRate: t.playRate ?? 1,
787
+ volume: t.volume ?? 1
709
788
  });
710
789
  } catch (f) {
711
790
  console.warn("[renderer] update video frame failed", f);
712
791
  }
713
792
  }
714
- async function Ft(e, s, n) {
715
- const f = S !== "element", y = S !== "mp4clip";
716
- if (h.has(s)) {
717
- if (!y)
718
- throw new Error(`[renderer] MP4Clip unsupported for ${e}`);
719
- return await D(e, n).catch(() => {
793
+ async function Le(t, u, a) {
794
+ const f = T !== "element", M = T !== "mp4clip";
795
+ if (p.has(u)) {
796
+ if (!M)
797
+ throw new Error(`[renderer] MP4Clip unsupported for ${t}`);
798
+ return await q(t, a).catch(() => {
720
799
  });
721
800
  }
722
801
  if (f) {
723
- const v = await at(e, n).catch((g) => {
724
- if (B(g) && h.add(s), !y)
725
- throw g;
802
+ const S = await ue(t, a).catch((x) => {
803
+ if (X(x) && p.add(u), !M)
804
+ throw x;
726
805
  });
727
- if (v)
728
- return v;
806
+ if (S)
807
+ return S;
729
808
  }
730
- if (y)
731
- return await D(e, n).catch(() => {
809
+ if (M)
810
+ return await q(t, a).catch(() => {
732
811
  });
733
812
  }
734
- function Pt(e) {
735
- return e.segmentType === "frames" && e.type === "video" && typeof e.url == "string" && ct(e.url);
813
+ function Fe(t) {
814
+ return t.segmentType === "frames" && t.type === "video" && typeof t.url == "string" && le(t.url);
736
815
  }
737
- function Ot(e, s) {
738
- const n = J(e);
739
- if (n <= 0)
816
+ function Oe(t, u) {
817
+ const a = te(t);
818
+ if (a <= 0)
740
819
  return 0;
741
- if (s < n)
742
- return s;
743
- const f = Math.max(1e3 / Math.max(e.fps || 30, 1), 1);
744
- return Math.max(n - f, 0);
820
+ if (u < a)
821
+ return u;
822
+ const f = Math.max(1e3 / Math.max(t.fps || 30, 1), 1);
823
+ return Math.max(a - f, 0);
745
824
  }
746
- async function rt(e) {
747
- const s = o.resourceDir ?? ue;
825
+ async function ae(t) {
826
+ const u = o.resourceDir ?? dt;
748
827
  try {
749
- const n = N(e);
750
- if (!n)
828
+ const a = _(t);
829
+ if (!a)
751
830
  return;
752
- const f = Wt(`${s}/${n}`, "r");
831
+ const f = We(`${u}/${a}`, "r");
753
832
  if (await f.exists())
754
833
  return f;
755
834
  } catch {
756
835
  return;
757
836
  }
758
837
  }
759
- function it(e) {
760
- return !(!e || e.startsWith("data:") || e.startsWith("blob:"));
838
+ function se(t) {
839
+ return !(!t || t.startsWith("data:") || t.startsWith("blob:"));
761
840
  }
762
- function $t() {
763
- for (const [e, s] of M) {
764
- if (s.kind === "mp4clip") {
765
- s.clip.destroy(), M.set(e, {
841
+ function Ve() {
842
+ for (const [t, u] of h) {
843
+ if (u.kind === "mp4clip") {
844
+ u.clip.destroy(), h.set(t, {
766
845
  kind: "frozen",
767
- canvas: s.canvas,
768
- texture: s.texture,
769
- sprite: s.sprite,
770
- meta: s.meta
846
+ canvas: u.canvas,
847
+ texture: u.texture,
848
+ sprite: u.sprite,
849
+ meta: u.meta
771
850
  });
772
851
  continue;
773
852
  }
774
- s.kind === "element" && s.video.pause();
853
+ u.kind === "element" && u.video.pause();
775
854
  }
776
855
  }
777
- function nt(e) {
778
- if (e.kind === "mp4clip") {
779
- e.clip.destroy();
856
+ function ce(t) {
857
+ if (t.kind === "mp4clip") {
858
+ t.clip.destroy();
780
859
  return;
781
860
  }
782
- if (e.kind === "frozen")
861
+ if (t.kind === "frozen")
783
862
  return;
784
- e.video.pause();
785
- const s = k.get(e.video);
786
- s && (URL.revokeObjectURL(s), k.delete(e.video)), e.video.removeAttribute("src"), e.video.load();
787
- }
788
- function _(e, s, n = 1e3) {
789
- return new Promise((f, y) => {
790
- const v = window.setTimeout(() => {
791
- b(), y(new Error(`Timed out waiting for media event: ${s}`));
792
- }, n), g = () => {
793
- b(), f();
794
- }, T = () => {
795
- b();
796
- const I = e.error ? `${e.error.code}` : "unknown";
797
- y(new Error(`Media error (${I}) while waiting for ${s}`));
863
+ t.video.pause();
864
+ const u = v.get(t.video);
865
+ u && (URL.revokeObjectURL(u), v.delete(t.video)), t.video.removeAttribute("src"), t.video.load();
866
+ }
867
+ function H(t, u, a = 1e3) {
868
+ return new Promise((f, M) => {
869
+ const S = window.setTimeout(() => {
870
+ C(), M(new Error(`Timed out waiting for media event: ${u}`));
871
+ }, a), x = () => {
872
+ C(), f();
798
873
  }, b = () => {
799
- window.clearTimeout(v), e.removeEventListener(s, g), e.removeEventListener("error", T);
874
+ C();
875
+ const P = t.error ? `${t.error.code}` : "unknown";
876
+ M(new Error(`Media error (${P}) while waiting for ${u}`));
877
+ }, C = () => {
878
+ window.clearTimeout(S), t.removeEventListener(u, x), t.removeEventListener("error", b);
800
879
  };
801
- e.addEventListener(s, g, { once: !0 }), e.addEventListener("error", T, { once: !0 });
880
+ t.addEventListener(u, x, { once: !0 }), t.addEventListener("error", b, { once: !0 });
802
881
  });
803
882
  }
804
- async function at(e, s) {
805
- let n;
806
- it(e) && (n = await rt(e), n || (await c.add(e).catch(() => {
807
- }), n = await rt(e)));
883
+ async function ue(t, u) {
884
+ let a;
885
+ se(t) && (a = await ae(t), a || (await c.add(t).catch(() => {
886
+ }), a = await ae(t)));
808
887
  let f;
809
888
  try {
810
- if (n)
811
- f = new G(n);
889
+ if (a)
890
+ f = new B(a);
812
891
  else {
813
- const I = await fetch(e);
814
- if (I.body)
815
- f = new G(I.body);
892
+ const P = await fetch(t);
893
+ if (P.body)
894
+ f = new B(P.body);
816
895
  else {
817
- const F = await I.arrayBuffer(), U = new ReadableStream({
818
- start(P) {
819
- P.enqueue(new Uint8Array(F)), P.close();
896
+ const F = await P.arrayBuffer(), N = new ReadableStream({
897
+ start(V) {
898
+ V.enqueue(new Uint8Array(F)), V.close();
820
899
  }
821
900
  });
822
- f = new G(U);
901
+ f = new B(N);
823
902
  }
824
903
  }
825
904
  await f.ready;
826
- const { width: y, height: v } = f.meta, g = document.createElement("canvas");
827
- g.width = y || 1, g.height = v || 1;
828
- const T = V.from(g), b = s?.sprite ?? new O(T);
829
- return s?.sprite && (s.sprite.texture = T, s.oldTexture?.destroy(!0)), { kind: "mp4clip", clip: f, canvas: g, texture: T, sprite: b, meta: { width: y, height: v } };
830
- } catch (y) {
831
- throw f?.destroy(), y;
905
+ const { width: M, height: S } = f.meta, x = document.createElement("canvas");
906
+ x.width = M || 1, x.height = S || 1;
907
+ const b = G.from(x), C = u?.sprite ?? new $(b);
908
+ return u?.sprite && (u.sprite.texture = b, u.oldTexture?.destroy(!0)), { kind: "mp4clip", clip: f, canvas: x, texture: b, sprite: C, meta: { width: M, height: S } };
909
+ } catch (M) {
910
+ throw f?.destroy(), M;
832
911
  }
833
912
  }
834
- function st(e) {
835
- const n = e.split("#")[0].split("?")[0].split("/").pop()?.split(".").pop()?.toLowerCase() ?? "";
836
- return ["mp4", "m4v", "mov", "webm"].includes(n) ? "video" : ["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg", "avif"].includes(n) ? "image" : ["mp3", "wav", "aac", "m4a", "ogg", "flac"].includes(n) ? "audio" : "unknown";
913
+ function de(t) {
914
+ const a = t.split("#")[0].split("?")[0].split("/").pop()?.split(".").pop()?.toLowerCase() ?? "";
915
+ return ["mp4", "m4v", "mov", "webm"].includes(a) ? "video" : ["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg", "avif"].includes(a) ? "image" : ["mp3", "wav", "aac", "m4a", "ogg", "flac"].includes(a) ? "audio" : "unknown";
837
916
  }
838
- function ct(e) {
839
- const s = st(e);
840
- return !(s === "image" || s === "audio");
917
+ function le(t) {
918
+ const u = de(t);
919
+ return !(u === "image" || u === "audio");
841
920
  }
842
- async function D(e, s) {
843
- const n = document.createElement("video");
844
- n.crossOrigin = "anonymous", n.muted = !1, n.playsInline = !0, n.preload = "metadata", n.src = e, n.load();
921
+ async function q(t, u) {
922
+ const a = document.createElement("video");
923
+ a.crossOrigin = "anonymous", a.muted = !1, a.playsInline = !0, a.preload = "metadata", a.src = t, a.load();
845
924
  try {
846
- await _(n, "loadedmetadata", 15e3);
847
- } catch (b) {
848
- n.pause();
849
- const I = k.get(n);
850
- throw I && (URL.revokeObjectURL(I), k.delete(n)), n.removeAttribute("src"), n.load(), b;
925
+ await H(a, "loadedmetadata", 15e3);
926
+ } catch (C) {
927
+ a.pause();
928
+ const P = v.get(a);
929
+ throw P && (URL.revokeObjectURL(P), v.delete(a)), a.removeAttribute("src"), a.load(), C;
851
930
  }
852
- const f = n.videoWidth || 1, y = n.videoHeight || 1, v = document.createElement("canvas");
853
- v.width = f, v.height = y;
854
- const g = V.from(v), T = s?.sprite ?? new O(g);
855
- return s?.sprite && (s.sprite.texture = g, s.oldTexture?.destroy(!0)), { kind: "element", video: n, canvas: v, texture: g, sprite: T, meta: { width: f, height: y } };
856
- }
857
- async function Ut(e, s) {
858
- const { video: n, canvas: f, texture: y } = e;
859
- n.playbackRate = Number.isFinite(s.playbackRate) && s.playbackRate > 0 ? s.playbackRate : 1, n.volume = Math.max(0, Math.min(1, s.volume ?? 1)), x.value ? n.play().catch(() => {
860
- }) : n.pause();
861
- const v = Number.isFinite(n.duration) && n.duration > 0 ? n.duration : null, g = v ? Math.min(s.targetSec, Math.max(v - 0.03, 0)) : s.targetSec, T = n.currentTime, b = Math.abs(T - g), I = x.value ? 0.25 : 0.03;
862
- if (Number.isFinite(T) && b > I) {
931
+ const f = a.videoWidth || 1, M = a.videoHeight || 1, S = document.createElement("canvas");
932
+ S.width = f, S.height = M;
933
+ const x = G.from(S), b = u?.sprite ?? new $(x);
934
+ return u?.sprite && (u.sprite.texture = x, u.oldTexture?.destroy(!0)), { kind: "element", video: a, canvas: S, texture: x, sprite: b, meta: { width: f, height: M } };
935
+ }
936
+ async function $e(t, u) {
937
+ const { video: a, canvas: f, texture: M } = t;
938
+ a.playbackRate = Number.isFinite(u.playbackRate) && u.playbackRate > 0 ? u.playbackRate : 1, a.volume = Math.max(0, Math.min(1, u.volume ?? 1)), g.value ? a.play().catch(() => {
939
+ }) : a.pause();
940
+ const S = Number.isFinite(a.duration) && a.duration > 0 ? a.duration : null, x = S ? Math.min(u.targetSec, Math.max(S - 0.03, 0)) : u.targetSec, b = a.currentTime, C = Math.abs(b - x), P = g.value ? 0.25 : 0.03;
941
+ if (Number.isFinite(b) && C > P) {
863
942
  try {
864
- n.currentTime = g;
943
+ a.currentTime = x;
865
944
  } catch {
866
945
  }
867
- await _(n, "seeked", 250).catch(() => {
946
+ await H(a, "seeked", 250).catch(() => {
868
947
  });
869
948
  }
870
- if (n.readyState < 2 && (await _(n, "canplay", 250).catch(() => {
871
- }), n.readyState < 2))
949
+ if (a.readyState < 2 && (await H(a, "canplay", 250).catch(() => {
950
+ }), a.readyState < 2))
872
951
  return;
873
952
  const F = f.getContext("2d");
874
- F && (F.drawImage(n, 0, 0, f.width, f.height), dt(y));
875
- }
876
- function Vt(e) {
877
- return new Promise((s) => {
878
- const n = new Image();
879
- n.crossOrigin = "anonymous", n.onload = () => s(V.from(n)), n.onerror = () => {
880
- console.warn("[renderer] failed to load image", e), s(void 0);
881
- }, n.src = e;
953
+ F && (F.drawImage(a, 0, 0, f.width, f.height), fe(M));
954
+ }
955
+ function Ue(t) {
956
+ return new Promise((u) => {
957
+ const a = new Image();
958
+ a.crossOrigin = "anonymous", a.onload = () => u(G.from(a)), a.onerror = () => {
959
+ console.warn("[renderer] failed to load image", t), u(void 0);
960
+ }, a.src = t;
882
961
  });
883
962
  }
884
- function dt(e) {
885
- const s = e.source;
886
- if ("update" in s && typeof s.update == "function") {
887
- s.update();
963
+ function fe(t) {
964
+ const u = t.source;
965
+ if ("update" in u && typeof u.update == "function") {
966
+ u.update();
888
967
  return;
889
968
  }
890
- typeof e.update == "function" && e.update();
969
+ typeof t.update == "function" && t.update();
891
970
  }
892
- function Dt() {
893
- q(), C += 1, Q.stop(), Z(), u.destroy({ children: !0 }), l.clear(), p.clear(), d.clear(), o.app || a.destroy(), E.destroy();
971
+ function ze() {
972
+ Y(), k += 1, D.stop(), j(), d.destroy({ children: !0 }), l.clear(), m.clear(), s.clear(), o.app || n.destroy(), I.destroy();
894
973
  }
895
- return o.autoPlay && tt(), {
896
- app: a,
897
- layer: u,
898
- currentTime: w,
974
+ return o.autoPlay && ie(), {
975
+ app: n,
976
+ layer: d,
977
+ currentTime: y,
899
978
  duration: R,
900
- isPlaying: x,
901
- play: tt,
902
- pause: q,
903
- tick: ot,
904
- seek: kt,
905
- renderAt: Ct,
906
- destroy: Dt
979
+ isPlaying: g,
980
+ play: ie,
981
+ pause: Y,
982
+ tick: ne,
983
+ seek: ke,
984
+ renderAt: Ce,
985
+ destroy: ze
907
986
  };
908
987
  }
909
- function fe(o) {
910
- let t = !1, i = !1, r = null, a = null;
988
+ function ft(o) {
989
+ let e = !1, r = !1, i = null, n = null;
911
990
  return async () => {
912
- r || (r = new Promise((d) => {
913
- a = d;
991
+ i || (i = new Promise((s) => {
992
+ n = s;
914
993
  }));
915
- const c = r;
916
- if (i)
917
- return t = !0, c;
918
- i = !0;
994
+ const c = i;
995
+ if (r)
996
+ return e = !0, c;
997
+ r = !0;
919
998
  do
920
- t = !1, await o();
921
- while (t);
922
- return i = !1, a?.(), r = null, a = null, c;
999
+ e = !1, await o();
1000
+ while (e);
1001
+ return r = !1, n?.(), i = null, n = null, c;
923
1002
  };
924
1003
  }
925
- function pe(o) {
1004
+ function pt(o) {
926
1005
  return typeof o == "object" && o !== null && "createReader" in o && "getSize" in o;
927
1006
  }
928
- function he(o) {
1007
+ function ht(o) {
929
1008
  return typeof ReadableStream < "u" && o instanceof ReadableStream;
930
1009
  }
931
- function me(o) {
932
- return typeof o == "string" || o instanceof Blob || pe(o) || he(o) ? { source: o } : o;
1010
+ function mt(o) {
1011
+ return typeof o == "string" || o instanceof Blob || pt(o) || ht(o) ? { source: o } : o;
933
1012
  }
934
- async function ht(o) {
1013
+ async function we(o) {
935
1014
  if (typeof o == "string") {
936
- const t = await fetch(o);
937
- if (!t.body)
1015
+ const e = await fetch(o);
1016
+ if (!e.body)
938
1017
  throw new Error("concatVideos: unable to read video stream from url");
939
- return t.body;
1018
+ return e.body;
940
1019
  }
941
1020
  return o instanceof Blob ? o.stream() : o;
942
1021
  }
943
- function we(o, t) {
944
- let i = !1;
945
- const r = () => {
946
- i || (i = !0, t());
947
- }, a = o.getReader();
1022
+ function yt(o, e) {
1023
+ let r = !1;
1024
+ const i = () => {
1025
+ r || (r = !0, e());
1026
+ }, n = o.getReader();
948
1027
  return new ReadableStream({
949
- async pull(u) {
950
- const { done: c, value: d } = await a.read();
1028
+ async pull(d) {
1029
+ const { done: c, value: s } = await n.read();
951
1030
  if (c) {
952
- r(), u.close();
1031
+ i(), d.close();
953
1032
  return;
954
1033
  }
955
- u.enqueue(d);
1034
+ d.enqueue(s);
956
1035
  },
957
- async cancel(u) {
1036
+ async cancel(d) {
958
1037
  try {
959
- await a.cancel(u);
1038
+ await n.cancel(d);
960
1039
  } finally {
961
- r();
1040
+ i();
962
1041
  }
963
1042
  }
964
1043
  });
965
1044
  }
966
- async function Te(o, t = {}) {
1045
+ async function Tt(o, e = {}) {
967
1046
  if (o.length === 0)
968
1047
  throw new Error("concatVideos: expected at least one source");
969
1048
  const {
970
- onProgress: i,
971
- width: r,
972
- height: a,
973
- ...u
974
- } = t, c = o.map(me), [d, ...l] = c, p = await ht(d.source), h = new G(p);
975
- await h.ready;
976
- const m = r ?? Math.round(h.meta.width || 0), S = a ?? Math.round(h.meta.height || 0);
977
- if (!m || !S)
978
- throw h.destroy(), new Error("concatVideos: output width/height is required");
979
- const M = new mt({
980
- ...u,
981
- width: m,
982
- height: S
1049
+ onProgress: r,
1050
+ width: i,
1051
+ height: n,
1052
+ ...d
1053
+ } = e, c = o.map(mt), [s, ...l] = c, m = await we(s.source), p = new B(m);
1054
+ await p.ready;
1055
+ const w = i ?? Math.round(p.meta.width || 0), T = n ?? Math.round(p.meta.height || 0);
1056
+ if (!w || !T)
1057
+ throw p.destroy(), new Error("concatVideos: output width/height is required");
1058
+ const h = new ve({
1059
+ ...d,
1060
+ width: w,
1061
+ height: T
983
1062
  });
984
- i && M.on("OutputProgress", i);
985
- let k = 0;
986
- const w = async (A) => {
987
- const L = A.meta.duration;
988
- if (!Number.isFinite(L) || L <= 0)
989
- throw A.destroy(), new Error("concatVideos: invalid clip duration");
990
- const C = new wt(A);
1063
+ r && h.on("OutputProgress", r);
1064
+ let v = 0;
1065
+ const y = async (E) => {
1066
+ const A = E.meta.duration;
1067
+ if (!Number.isFinite(A) || A <= 0)
1068
+ throw E.destroy(), new Error("concatVideos: invalid clip duration");
1069
+ const k = new Me(E);
991
1070
  try {
992
- await C.ready, C.rect.x = 0, C.rect.y = 0, C.rect.w = m, C.rect.h = S, C.time.offset = k, C.time.duration = L, await M.addSprite(C), k += L;
1071
+ await k.ready, k.rect.x = 0, k.rect.y = 0, k.rect.w = w, k.rect.h = T, k.time.offset = v, k.time.duration = A, await h.addSprite(k), v += A;
993
1072
  } finally {
994
- C.destroy();
1073
+ k.destroy();
995
1074
  }
996
1075
  };
997
1076
  try {
998
- await w(h);
999
- for (const A of l) {
1000
- const L = await ht(A.source), C = new G(L);
1001
- await C.ready, await w(C);
1077
+ await y(p);
1078
+ for (const E of l) {
1079
+ const A = await we(E.source), k = new B(A);
1080
+ await k.ready, await y(k);
1002
1081
  }
1003
- } catch (A) {
1004
- throw M.destroy(), A;
1082
+ } catch (E) {
1083
+ throw h.destroy(), E;
1005
1084
  }
1006
- const x = k, R = M.output({ maxTime: x }), E = () => {
1007
- M.destroy();
1085
+ const g = v, R = h.output({ maxTime: g }), I = () => {
1086
+ h.destroy();
1008
1087
  };
1009
1088
  return {
1010
- stream: we(R, E),
1011
- width: m,
1012
- height: S,
1013
- durationMs: Math.round(x / 1e3),
1014
- destroy: E
1089
+ stream: yt(R, I),
1090
+ width: w,
1091
+ height: T,
1092
+ durationMs: Math.round(g / 1e3),
1093
+ destroy: I
1015
1094
  };
1016
1095
  }
1017
- class H {
1096
+ class oe {
1018
1097
  ready;
1019
1098
  meta;
1020
1099
  protocol;
@@ -1022,149 +1101,149 @@ class H {
1022
1101
  renderer;
1023
1102
  app;
1024
1103
  destroyed = !1;
1025
- constructor(t, i = {}) {
1026
- this.protocol = t, this.options = i;
1027
- const r = i.width ?? t.width, a = i.height ?? t.height, u = J(t);
1104
+ constructor(e, r = {}) {
1105
+ this.protocol = e, this.options = r;
1106
+ const i = r.width ?? e.width, n = r.height ?? e.height, d = te(e);
1028
1107
  this.meta = {
1029
- width: r,
1030
- height: a,
1031
- duration: Math.max(0, Math.round(u * 1e3))
1108
+ width: i,
1109
+ height: n,
1110
+ duration: Math.max(0, Math.round(d * 1e3))
1032
1111
  }, this.ready = this.init();
1033
1112
  }
1034
1113
  async init() {
1035
- const t = this.options.width ?? this.protocol.width, i = this.options.height ?? this.protocol.height;
1036
- if (!t || !i)
1114
+ const e = this.options.width ?? this.protocol.width, r = this.options.height ?? this.protocol.height;
1115
+ if (!e || !r)
1037
1116
  throw new Error("ProtocolVideoClip: output width/height is required");
1038
- const r = new yt();
1039
- await r.init({
1040
- width: t,
1041
- height: i,
1117
+ const i = new Se();
1118
+ await i.init({
1119
+ width: e,
1120
+ height: r,
1042
1121
  backgroundAlpha: 0,
1043
1122
  ...this.options.appOptions
1044
- }), r.ticker.stop(), this.app = r;
1045
- const a = this.options.rendererOptions ?? {}, u = await le({
1123
+ }), i.ticker.stop(), this.app = i;
1124
+ const n = this.options.rendererOptions ?? {}, d = await lt({
1046
1125
  protocol: this.protocol,
1047
- app: r,
1048
- ...a,
1126
+ app: i,
1127
+ ...n,
1049
1128
  autoPlay: !1,
1050
1129
  freezeOnPause: !1,
1051
1130
  manualRender: !0,
1052
- videoSourceMode: a.videoSourceMode ?? "mp4clip"
1131
+ videoSourceMode: n.videoSourceMode ?? "mp4clip"
1053
1132
  });
1054
- this.renderer = u;
1055
- const c = u.duration.value;
1133
+ this.renderer = d;
1134
+ const c = d.duration.value;
1056
1135
  return this.meta = {
1057
- width: r.renderer.width,
1058
- height: r.renderer.height,
1136
+ width: i.renderer.width,
1137
+ height: i.renderer.height,
1059
1138
  duration: Math.max(0, Math.round(c * 1e3))
1060
1139
  }, this.meta;
1061
1140
  }
1062
- async tick(t) {
1063
- const i = [];
1141
+ async tick(e) {
1142
+ const r = [];
1064
1143
  if (this.destroyed)
1065
- return { audio: i, state: "done" };
1144
+ return { audio: r, state: "done" };
1066
1145
  if (await this.ready, !this.renderer)
1067
- return { audio: i, state: "done" };
1068
- const r = this.meta.duration;
1069
- if (t >= r)
1070
- return { audio: i, state: "done" };
1071
- const a = Math.max(0, Math.min(t, r));
1072
- return await this.renderer.renderAt(a / 1e3), {
1146
+ return { audio: r, state: "done" };
1147
+ const i = this.meta.duration;
1148
+ if (e >= i)
1149
+ return { audio: r, state: "done" };
1150
+ const n = Math.max(0, Math.min(e, i));
1151
+ return await this.renderer.renderAt(n / 1e3), {
1073
1152
  video: new VideoFrame(this.renderer.app.canvas, {
1074
- timestamp: t
1153
+ timestamp: e
1075
1154
  }),
1076
- audio: i,
1155
+ audio: r,
1077
1156
  state: "success"
1078
1157
  };
1079
1158
  }
1080
1159
  async clone() {
1081
- const t = new H(this.protocol, this.options);
1082
- return await t.ready, t;
1160
+ const e = new oe(this.protocol, this.options);
1161
+ return await e.ready, e;
1083
1162
  }
1084
1163
  destroy() {
1085
1164
  this.destroyed || (this.destroyed = !0, this.renderer?.destroy(), this.app?.destroy(!0));
1086
1165
  }
1087
1166
  }
1088
- function ye(o, t) {
1089
- let i = !1;
1090
- const r = () => {
1091
- i || (i = !0, t());
1092
- }, a = o.getReader();
1167
+ function wt(o, e) {
1168
+ let r = !1;
1169
+ const i = () => {
1170
+ r || (r = !0, e());
1171
+ }, n = o.getReader();
1093
1172
  return new ReadableStream({
1094
- async pull(u) {
1095
- const { done: c, value: d } = await a.read();
1173
+ async pull(d) {
1174
+ const { done: c, value: s } = await n.read();
1096
1175
  if (c) {
1097
- r(), u.close();
1176
+ i(), d.close();
1098
1177
  return;
1099
1178
  }
1100
- u.enqueue(d);
1179
+ d.enqueue(s);
1101
1180
  },
1102
- async cancel(u) {
1181
+ async cancel(d) {
1103
1182
  try {
1104
- await a.cancel(u);
1183
+ await n.cancel(d);
1105
1184
  } finally {
1106
- r();
1185
+ i();
1107
1186
  }
1108
1187
  }
1109
1188
  });
1110
1189
  }
1111
- async function be(o, t = {}) {
1190
+ async function bt(o, e = {}) {
1112
1191
  const {
1113
- width: i,
1114
- height: r,
1115
- fps: a,
1116
- onProgress: u,
1192
+ width: r,
1193
+ height: i,
1194
+ fps: n,
1195
+ onProgress: d,
1117
1196
  clipOptions: c,
1118
- audioSprites: d,
1197
+ audioSprites: s,
1119
1198
  ...l
1120
- } = t, p = i ?? o.width, h = r ?? o.height;
1121
- if (!p || !h)
1199
+ } = e, m = r ?? o.width, p = i ?? o.height;
1200
+ if (!m || !p)
1122
1201
  throw new Error("composeProtocol: output width/height is required");
1123
- const m = a ?? o.fps, S = typeof d == "function", M = l.audio ?? (S ? void 0 : !1), k = new mt({
1202
+ const w = n ?? o.fps, T = typeof s == "function", h = l.audio ?? (T ? void 0 : !1), v = new ve({
1124
1203
  ...l,
1125
- audio: M,
1126
- width: p,
1127
- height: h,
1128
- fps: m
1204
+ audio: h,
1205
+ width: m,
1206
+ height: p,
1207
+ fps: w
1129
1208
  });
1130
- u && k.on("OutputProgress", u);
1131
- let w, x;
1209
+ d && v.on("OutputProgress", d);
1210
+ let y, g;
1132
1211
  try {
1133
- if (w = new H(o, {
1134
- width: p,
1135
- height: h,
1136
- fps: m,
1212
+ if (y = new oe(o, {
1213
+ width: m,
1214
+ height: p,
1215
+ fps: w,
1137
1216
  ...c,
1138
1217
  rendererOptions: {
1139
1218
  warmUpResources: !1,
1140
1219
  ...c?.rendererOptions
1141
1220
  }
1142
- }), await w.ready, x = new wt(w), await x.ready, x.time.offset = 0, x.time.duration = w.meta.duration, x.rect.x = 0, x.rect.y = 0, x.rect.w = w.meta.width, x.rect.h = w.meta.height, await k.addSprite(x, { main: !0 }), d) {
1143
- const L = await d(o);
1144
- for (const C of L)
1145
- await k.addSprite(C);
1221
+ }), await y.ready, g = new Me(y), await g.ready, g.time.offset = 0, g.time.duration = y.meta.duration, g.rect.x = 0, g.rect.y = 0, g.rect.w = y.meta.width, g.rect.h = y.meta.height, await v.addSprite(g, { main: !0 }), s) {
1222
+ const A = await s(o);
1223
+ for (const k of A)
1224
+ await v.addSprite(k);
1146
1225
  }
1147
- } catch (L) {
1148
- throw k.destroy(), L;
1226
+ } catch (A) {
1227
+ throw v.destroy(), A;
1149
1228
  }
1150
- const R = w?.meta.duration ?? 0;
1229
+ const R = y?.meta.duration ?? 0;
1151
1230
  if (!R)
1152
1231
  throw new Error("composeProtocol: protocol has no duration");
1153
- const E = k.output({ maxTime: R }), A = () => {
1154
- x?.destroy(), w?.destroy(), k.destroy();
1232
+ const I = v.output({ maxTime: R }), E = () => {
1233
+ g?.destroy(), y?.destroy(), v.destroy();
1155
1234
  };
1156
1235
  return {
1157
- stream: ye(E, A),
1158
- width: p,
1159
- height: h,
1236
+ stream: wt(I, E),
1237
+ width: m,
1238
+ height: p,
1160
1239
  durationMs: Math.round(R / 1e3),
1161
- destroy: A
1240
+ destroy: E
1162
1241
  };
1163
1242
  }
1164
1243
  export {
1165
- H as ProtocolVideoClip,
1166
- be as composeProtocol,
1167
- Te as concatVideos,
1168
- le as createRenderer
1244
+ oe as ProtocolVideoClip,
1245
+ bt as composeProtocol,
1246
+ Tt as concatVideos,
1247
+ lt as createRenderer
1169
1248
  };
1170
1249
  //# sourceMappingURL=index.js.map