@video-editor/renderer 0.0.1-beta.14 → 0.0.1-beta.15
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 +359 -231
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,319 +1,447 @@
|
|
|
1
|
-
import { createValidator as
|
|
2
|
-
import { toRaw as
|
|
3
|
-
import { MP4Clip as
|
|
4
|
-
import { file as
|
|
5
|
-
import { Application as
|
|
6
|
-
async function
|
|
7
|
-
const
|
|
8
|
-
return await
|
|
1
|
+
import { createValidator as Me, createResourceManager as Se, getResourceKey as O } from "@video-editor/protocol";
|
|
2
|
+
import { toRaw as Ie, isRef as be, shallowRef as X, unref as Z, ref as ee, computed as Ce, effectScope as Re, watch as $ } from "@vue/reactivity";
|
|
3
|
+
import { MP4Clip as L } from "@webav/av-cliper";
|
|
4
|
+
import { file as Fe } from "opfs-tools";
|
|
5
|
+
import { Application as Ve, Sprite as V, Texture as C, Graphics as ie, Container as De } from "pixi.js";
|
|
6
|
+
async function Pe(n) {
|
|
7
|
+
const o = new Ve();
|
|
8
|
+
return await o.init({ resizeTo: window, ...n }), o;
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
const
|
|
12
|
-
for (const a of
|
|
13
|
-
for (const
|
|
14
|
-
|
|
15
|
-
return
|
|
10
|
+
function Ae(n) {
|
|
11
|
+
const o = /* @__PURE__ */ new Set();
|
|
12
|
+
for (const a of n.tracks)
|
|
13
|
+
for (const c of a.children)
|
|
14
|
+
c.url && o.add(c.url);
|
|
15
|
+
return o;
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function Ne(n, o) {
|
|
18
18
|
const a = [];
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
return n.tracks.forEach((c, v) => {
|
|
20
|
+
c.children.forEach((p, w) => {
|
|
21
|
+
p.startTime <= o && o < p.endTime && a.push({ segment: p, trackIndex: v, childIndex: w });
|
|
22
22
|
});
|
|
23
|
-
}), a.sort((
|
|
23
|
+
}), a.sort((c, v) => c.trackIndex === v.trackIndex ? c.childIndex - v.childIndex : c.trackIndex - v.trackIndex);
|
|
24
24
|
}
|
|
25
|
-
function
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}, { once: !0 })) :
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
32
|
-
const [
|
|
33
|
-
|
|
25
|
+
function Oe(n, o, a, c) {
|
|
26
|
+
const v = Le(o);
|
|
27
|
+
n instanceof V ? (n.anchor.set(0.5), n.width = a, n.height = c, n.x = a / 2, n.y = c / 2, n.texture.source?.addEventListener?.("error", () => {
|
|
28
|
+
n.texture = C.from($e(a, c));
|
|
29
|
+
}, { once: !0 })) : n instanceof ie && (n.clear(), n.rect(0, 0, a, c).fill({ color: oe("url" in o && typeof o.url == "string" ? o.url : o.segmentType), alpha: ae(o) ? v : 0.35 }), n.pivot.set(a / 2, c / 2), n.position.set(a / 2, c / 2)), n.alpha = v;
|
|
30
|
+
const p = We(o);
|
|
31
|
+
if (p) {
|
|
32
|
+
const [w, S] = p.position ?? [0, 0], [y, g] = p.scale ?? [1, 1], k = p.rotation?.[2] ?? 0;
|
|
33
|
+
n.position.set(a / 2 + w * a / 2, c / 2 - S * c / 2), n.scale.set(y, g), n.rotation = k / 180 * Math.PI;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
function
|
|
37
|
-
const a = new
|
|
38
|
-
return a.rect(0, 0, 10, 10).fill({ color:
|
|
36
|
+
function U(n, o) {
|
|
37
|
+
const a = new ie();
|
|
38
|
+
return a.rect(0, 0, 10, 10).fill({ color: oe(o ?? n), alpha: 1 }), a;
|
|
39
39
|
}
|
|
40
|
-
function
|
|
41
|
-
const
|
|
42
|
-
return `data:image/svg+xml;base64,${btoa(
|
|
40
|
+
function $e(n, o, a) {
|
|
41
|
+
const c = `<svg xmlns="http://www.w3.org/2000/svg" width="${n}" height="${o}"><rect width="100%" height="100%" fill="#0f172a" fill-opacity="0.8"/></svg>`;
|
|
42
|
+
return `data:image/svg+xml;base64,${btoa(c)}`;
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
let
|
|
46
|
-
for (let a = 0; a <
|
|
47
|
-
|
|
48
|
-
return
|
|
44
|
+
function oe(n) {
|
|
45
|
+
let o = 0;
|
|
46
|
+
for (let a = 0; a < n.length; a++)
|
|
47
|
+
o = n.charCodeAt(a) + ((o << 5) - o);
|
|
48
|
+
return o & 16777215;
|
|
49
49
|
}
|
|
50
|
-
function
|
|
51
|
-
const
|
|
52
|
-
return
|
|
50
|
+
function te(n) {
|
|
51
|
+
const o = n.tracks.flatMap((a) => a.children.map((c) => c.endTime));
|
|
52
|
+
return o.length ? Math.max(...o) : 0;
|
|
53
53
|
}
|
|
54
|
-
function
|
|
55
|
-
return Math.min(Math.max(
|
|
54
|
+
function re(n, o, a) {
|
|
55
|
+
return Math.min(Math.max(n, o), a);
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
return JSON.parse(JSON.stringify(
|
|
57
|
+
function ne(n) {
|
|
58
|
+
const o = Ie(n);
|
|
59
|
+
return JSON.parse(JSON.stringify(o));
|
|
60
60
|
}
|
|
61
|
-
function
|
|
62
|
-
return "opacity" in
|
|
61
|
+
function ae(n) {
|
|
62
|
+
return "opacity" in n;
|
|
63
63
|
}
|
|
64
|
-
function
|
|
65
|
-
return
|
|
64
|
+
function Le(n) {
|
|
65
|
+
return ae(n) && typeof n.opacity == "number" ? n.opacity : 1;
|
|
66
66
|
}
|
|
67
|
-
function
|
|
68
|
-
return "transform" in
|
|
67
|
+
function Ue(n) {
|
|
68
|
+
return "transform" in n;
|
|
69
69
|
}
|
|
70
|
-
function
|
|
71
|
-
if (
|
|
72
|
-
return
|
|
70
|
+
function We(n) {
|
|
71
|
+
if (Ue(n))
|
|
72
|
+
return n.transform;
|
|
73
73
|
}
|
|
74
|
-
const
|
|
75
|
-
async function
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
),
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
let
|
|
82
|
-
async function
|
|
83
|
-
const { protocol:
|
|
84
|
-
for (const { segment:
|
|
85
|
-
const
|
|
86
|
-
|
|
74
|
+
const ze = "/video-editor-res";
|
|
75
|
+
async function je(n) {
|
|
76
|
+
const o = Me(), a = be(n.protocol) ? n.protocol : X(n.protocol), c = X(
|
|
77
|
+
o.verify(ne(Z(a)))
|
|
78
|
+
), v = n.app ?? await Pe(n.appOptions), p = new De();
|
|
79
|
+
v.stage.addChild(p);
|
|
80
|
+
const w = Se({ dir: n.resourceDir }), S = /* @__PURE__ */ new Set(), y = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Map(), k = /* @__PURE__ */ new Set(), W = /* @__PURE__ */ new Set(), m = /* @__PURE__ */ new Map(), h = ee(0), x = ee(!1), E = Ce(() => te(c.value));
|
|
81
|
+
let I, R = 0;
|
|
82
|
+
async function ce(e) {
|
|
83
|
+
const { protocol: r, at: t, layer: i } = e, s = we(r, t), u = Ne(r, s), d = e.app.renderer.width, f = e.app.renderer.height, l = [];
|
|
84
|
+
for (const { segment: M } of u) {
|
|
85
|
+
const b = await e.getDisplay(M);
|
|
86
|
+
b && (Oe(b, M, d, f), he(M) && await j(M, s), l.push(b));
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
const
|
|
93
|
-
app:
|
|
94
|
-
layer:
|
|
95
|
-
protocol:
|
|
96
|
-
at:
|
|
97
|
-
getDisplay:
|
|
98
|
-
})),
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
() =>
|
|
88
|
+
i.removeChildren();
|
|
89
|
+
const T = l.filter(Boolean);
|
|
90
|
+
T.length && i.addChild(...T), e.app.render();
|
|
91
|
+
}
|
|
92
|
+
const z = qe(() => ce({
|
|
93
|
+
app: v,
|
|
94
|
+
layer: p,
|
|
95
|
+
protocol: c.value,
|
|
96
|
+
at: h.value,
|
|
97
|
+
getDisplay: fe
|
|
98
|
+
})), q = Re();
|
|
99
|
+
q.run(() => {
|
|
100
|
+
$(
|
|
101
|
+
() => Z(a),
|
|
102
102
|
(e) => {
|
|
103
103
|
try {
|
|
104
|
-
|
|
105
|
-
} catch (
|
|
106
|
-
console.error("[renderer] invalid protocol update",
|
|
104
|
+
c.value = o.verify(ne(e));
|
|
105
|
+
} catch (r) {
|
|
106
|
+
console.error("[renderer] invalid protocol update", r);
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
H(), se(c.value), ue(c.value), D(), z();
|
|
110
110
|
},
|
|
111
111
|
{ deep: !0, immediate: !0 }
|
|
112
|
-
),
|
|
113
|
-
|
|
114
|
-
}),
|
|
112
|
+
), $(h, () => {
|
|
113
|
+
D(), z();
|
|
114
|
+
}), $(E, () => D());
|
|
115
115
|
});
|
|
116
|
-
function
|
|
117
|
-
const e =
|
|
118
|
-
e <= 0 ?
|
|
116
|
+
function D() {
|
|
117
|
+
const e = E.value;
|
|
118
|
+
e <= 0 ? h.value = 0 : h.value > e ? h.value = e : h.value < 0 && (h.value = 0);
|
|
119
119
|
}
|
|
120
|
-
function
|
|
121
|
-
for (const
|
|
122
|
-
|
|
120
|
+
function se(e) {
|
|
121
|
+
for (const r of Ae(e))
|
|
122
|
+
S.has(r) || (S.add(r), Te(r) !== "video" && A(r) && w.add(r).catch(() => {
|
|
123
123
|
}));
|
|
124
124
|
}
|
|
125
|
-
function
|
|
126
|
-
const
|
|
127
|
-
for (const [
|
|
128
|
-
|
|
129
|
-
for (const [
|
|
130
|
-
|
|
125
|
+
function ue(e) {
|
|
126
|
+
const r = new Set(e.tracks.flatMap((t) => t.children.map((i) => i.id)));
|
|
127
|
+
for (const [t, i] of y)
|
|
128
|
+
r.has(t) || (i.destroy(), y.delete(t));
|
|
129
|
+
for (const [t, i] of m)
|
|
130
|
+
r.has(t) || (B(i), m.delete(t));
|
|
131
131
|
}
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
for (const e of
|
|
132
|
+
function H() {
|
|
133
|
+
p.removeChildren();
|
|
134
|
+
for (const e of y.values())
|
|
135
135
|
e.destroy();
|
|
136
|
-
|
|
137
|
-
for (const
|
|
138
|
-
e
|
|
139
|
-
|
|
136
|
+
y.clear(), g.clear();
|
|
137
|
+
for (const e of m.values())
|
|
138
|
+
B(e);
|
|
139
|
+
m.clear();
|
|
140
140
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
141
|
+
function K() {
|
|
142
|
+
x.value || (x.value = !0, R = performance.now(), I = requestAnimationFrame(_));
|
|
143
143
|
}
|
|
144
|
-
function
|
|
145
|
-
|
|
144
|
+
function P() {
|
|
145
|
+
x.value = !1, I !== void 0 && cancelAnimationFrame(I), I = void 0, xe();
|
|
146
146
|
}
|
|
147
|
-
function
|
|
148
|
-
|
|
147
|
+
function _() {
|
|
148
|
+
J(), x.value && (I = requestAnimationFrame(_));
|
|
149
149
|
}
|
|
150
|
-
function
|
|
151
|
-
if (!
|
|
150
|
+
function J(e) {
|
|
151
|
+
if (!x.value && e === void 0)
|
|
152
152
|
return;
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
const r = performance.now(), t = e ?? (R ? r - R : 0);
|
|
154
|
+
R = r, t !== 0 && (h.value = re(
|
|
155
|
+
h.value + t,
|
|
156
156
|
0,
|
|
157
|
-
|
|
158
|
-
),
|
|
157
|
+
E.value || Number.POSITIVE_INFINITY
|
|
158
|
+
), E.value > 0 && h.value >= E.value && P());
|
|
159
159
|
}
|
|
160
|
-
function
|
|
161
|
-
|
|
160
|
+
function de(e) {
|
|
161
|
+
h.value = re(e, 0, E.value || Number.POSITIVE_INFINITY);
|
|
162
162
|
}
|
|
163
|
-
async function
|
|
164
|
-
const o = v.get(e.id);
|
|
165
|
-
if (o)
|
|
166
|
-
return o;
|
|
163
|
+
async function fe(e) {
|
|
167
164
|
const r = y.get(e.id);
|
|
168
165
|
if (r)
|
|
169
166
|
return r;
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
const t = g.get(e.id);
|
|
168
|
+
if (t)
|
|
169
|
+
return t;
|
|
170
|
+
const i = le(e);
|
|
171
|
+
g.set(e.id, i);
|
|
172
|
+
const s = await i;
|
|
173
|
+
return s && y.set(e.id, s), g.delete(e.id), s;
|
|
174
174
|
}
|
|
175
|
-
async function
|
|
175
|
+
async function le(e) {
|
|
176
176
|
if (e.segmentType === "frames" || e.segmentType === "sticker") {
|
|
177
177
|
if (!e.url)
|
|
178
|
-
return
|
|
178
|
+
return U(e.segmentType);
|
|
179
179
|
if ("type" in e && e.type === "video") {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
return r;
|
|
180
|
+
const t = await ve(e);
|
|
181
|
+
return t || U(e.segmentType, e.url);
|
|
183
182
|
}
|
|
184
|
-
const
|
|
185
|
-
return
|
|
183
|
+
const r = await pe(e.url);
|
|
184
|
+
return r ? new V(r) : U(e.segmentType, e.url);
|
|
186
185
|
}
|
|
187
186
|
e.segmentType !== "text" && (e.segmentType === "effect" || e.segmentType);
|
|
188
187
|
}
|
|
189
|
-
async function
|
|
190
|
-
const
|
|
191
|
-
if (!
|
|
188
|
+
async function pe(e) {
|
|
189
|
+
const r = e.startsWith("data:"), t = /^https?:\/\//.test(e);
|
|
190
|
+
if (!r && !t)
|
|
192
191
|
try {
|
|
193
|
-
await
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
196
|
-
return
|
|
192
|
+
await w.add(e);
|
|
193
|
+
const i = await w.get(e);
|
|
194
|
+
if (i instanceof HTMLImageElement)
|
|
195
|
+
return C.from(i);
|
|
197
196
|
} catch {
|
|
198
197
|
}
|
|
199
|
-
return await
|
|
198
|
+
return await Ee(e);
|
|
200
199
|
}
|
|
201
|
-
async function
|
|
202
|
-
const
|
|
203
|
-
if (
|
|
204
|
-
return
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
let c;
|
|
212
|
-
try {
|
|
213
|
-
if (r)
|
|
214
|
-
c = new _(r);
|
|
215
|
-
else {
|
|
216
|
-
const S = await fetch(e.url);
|
|
217
|
-
if (!S.body)
|
|
218
|
-
return;
|
|
219
|
-
c = new _(S.body);
|
|
220
|
-
}
|
|
221
|
-
} catch {
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
try {
|
|
225
|
-
await c.ready;
|
|
226
|
-
} catch {
|
|
227
|
-
c.destroy();
|
|
228
|
-
return;
|
|
200
|
+
async function ve(e) {
|
|
201
|
+
const r = m.get(e.id);
|
|
202
|
+
if (r)
|
|
203
|
+
return r.sprite;
|
|
204
|
+
const t = O(e.url);
|
|
205
|
+
if (t && k.has(t)) {
|
|
206
|
+
const u = await F(e.url).catch((d) => {
|
|
207
|
+
console.warn("[renderer] failed to load video via <video>", e.url, d);
|
|
208
|
+
});
|
|
209
|
+
return u ? (m.set(e.id, u), u.sprite) : void 0;
|
|
229
210
|
}
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
211
|
+
const i = await G(e.url).catch((u) => {
|
|
212
|
+
t && Y(u) && k.add(t), (!t || !W.has(t)) && (t && W.add(t), console.warn("[renderer] failed to load video via MP4Clip", e.url, u));
|
|
213
|
+
});
|
|
214
|
+
if (i)
|
|
215
|
+
return m.set(e.id, i), i.sprite;
|
|
216
|
+
const s = await F(e.url).catch((u) => {
|
|
217
|
+
console.warn("[renderer] failed to load video via <video>", e.url, u);
|
|
218
|
+
});
|
|
219
|
+
if (s)
|
|
220
|
+
return m.set(e.id, s), s.sprite;
|
|
234
221
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
222
|
+
function Y(e) {
|
|
223
|
+
if (!(e instanceof Error))
|
|
224
|
+
return !1;
|
|
225
|
+
const r = e.message || "";
|
|
226
|
+
return r.includes("stream is done") || r.includes("not emit ready");
|
|
227
|
+
}
|
|
228
|
+
async function j(e, r) {
|
|
229
|
+
const t = m.get(e.id);
|
|
230
|
+
if (t)
|
|
238
231
|
try {
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
241
|
-
const
|
|
242
|
-
|
|
232
|
+
const i = e.fromTime ?? 0, s = Math.max(0, r - e.startTime + i), u = Math.floor(s * 1e3);
|
|
233
|
+
if (t.kind === "frozen") {
|
|
234
|
+
const f = O(e.url);
|
|
235
|
+
if (!f)
|
|
236
|
+
return;
|
|
237
|
+
const l = await me(e.url, f, { sprite: t.sprite, oldTexture: t.texture });
|
|
238
|
+
return l ? (m.set(e.id, l), await j(e, r)) : void 0;
|
|
243
239
|
}
|
|
244
|
-
|
|
245
|
-
|
|
240
|
+
if (t.kind === "mp4clip") {
|
|
241
|
+
const f = await t.clip.tick(u);
|
|
242
|
+
if (f.video) {
|
|
243
|
+
const l = t.canvas.getContext("2d");
|
|
244
|
+
l && (l.drawImage(f.video, 0, 0, t.canvas.width, t.canvas.height), Q(t.texture)), f.video.close();
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const d = s / 1e3;
|
|
249
|
+
if (!Number.isFinite(d) || t.kind !== "element")
|
|
250
|
+
return;
|
|
251
|
+
await ge(t, {
|
|
252
|
+
targetSec: d,
|
|
253
|
+
playbackRate: e.playRate ?? 1
|
|
254
|
+
});
|
|
255
|
+
} catch (i) {
|
|
256
|
+
console.warn("[renderer] update video frame failed", i);
|
|
246
257
|
}
|
|
247
258
|
}
|
|
248
|
-
function
|
|
259
|
+
async function me(e, r, t) {
|
|
260
|
+
if (k.has(r))
|
|
261
|
+
return await F(e, t).catch(() => {
|
|
262
|
+
});
|
|
263
|
+
const i = await G(e, t).catch((s) => {
|
|
264
|
+
Y(s) && k.add(r);
|
|
265
|
+
});
|
|
266
|
+
return i || await F(e, t).catch(() => {
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
function he(e) {
|
|
249
270
|
return e.segmentType === "frames" && e.type === "video" && typeof e.url == "string";
|
|
250
271
|
}
|
|
251
|
-
function
|
|
252
|
-
const
|
|
253
|
-
if (
|
|
272
|
+
function we(e, r) {
|
|
273
|
+
const t = te(e);
|
|
274
|
+
if (t <= 0)
|
|
254
275
|
return 0;
|
|
255
|
-
if (
|
|
256
|
-
return
|
|
257
|
-
const
|
|
258
|
-
return Math.max(
|
|
276
|
+
if (r < t)
|
|
277
|
+
return r;
|
|
278
|
+
const i = Math.max(1e3 / Math.max(e.fps || 30, 1), 1);
|
|
279
|
+
return Math.max(t - i, 0);
|
|
259
280
|
}
|
|
260
|
-
async function
|
|
261
|
-
const
|
|
281
|
+
async function ye(e) {
|
|
282
|
+
const r = n.resourceDir ?? ze;
|
|
262
283
|
try {
|
|
263
|
-
const
|
|
264
|
-
if (
|
|
265
|
-
return
|
|
284
|
+
const t = O(e);
|
|
285
|
+
if (!t)
|
|
286
|
+
return;
|
|
287
|
+
const i = Fe(`${r}/${t}`, "r");
|
|
288
|
+
if (await i.exists())
|
|
289
|
+
return i;
|
|
266
290
|
} catch {
|
|
267
291
|
return;
|
|
268
292
|
}
|
|
269
293
|
}
|
|
270
|
-
function
|
|
271
|
-
return
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
294
|
+
function A(e) {
|
|
295
|
+
return !(!e || e.startsWith("data:") || e.startsWith("blob:"));
|
|
296
|
+
}
|
|
297
|
+
function xe() {
|
|
298
|
+
for (const [e, r] of m) {
|
|
299
|
+
if (r.kind === "mp4clip") {
|
|
300
|
+
r.clip.destroy(), m.set(e, {
|
|
301
|
+
kind: "frozen",
|
|
302
|
+
canvas: r.canvas,
|
|
303
|
+
texture: r.texture,
|
|
304
|
+
sprite: r.sprite,
|
|
305
|
+
meta: r.meta
|
|
306
|
+
});
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
r.kind === "element" && r.video.pause();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function B(e) {
|
|
313
|
+
if (e.kind === "mp4clip") {
|
|
314
|
+
e.clip.destroy();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
e.kind !== "frozen" && (e.video.pause(), e.video.removeAttribute("src"), e.video.load());
|
|
318
|
+
}
|
|
319
|
+
function N(e, r, t = 1e3) {
|
|
320
|
+
return new Promise((i, s) => {
|
|
321
|
+
const u = window.setTimeout(() => {
|
|
322
|
+
l(), s(new Error(`Timed out waiting for media event: ${r}`));
|
|
323
|
+
}, t), d = () => {
|
|
324
|
+
l(), i();
|
|
325
|
+
}, f = () => {
|
|
326
|
+
l();
|
|
327
|
+
const T = e.error ? `${e.error.code}` : "unknown";
|
|
328
|
+
s(new Error(`Media error (${T}) while waiting for ${r}`));
|
|
329
|
+
}, l = () => {
|
|
330
|
+
window.clearTimeout(u), e.removeEventListener(r, d), e.removeEventListener("error", f);
|
|
331
|
+
};
|
|
332
|
+
e.addEventListener(r, d, { once: !0 }), e.addEventListener("error", f, { once: !0 });
|
|
276
333
|
});
|
|
277
334
|
}
|
|
278
|
-
function
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
335
|
+
async function G(e, r) {
|
|
336
|
+
let t;
|
|
337
|
+
A(e) && (t = await ye(e));
|
|
338
|
+
let i;
|
|
339
|
+
try {
|
|
340
|
+
if (t)
|
|
341
|
+
i = new L(t);
|
|
342
|
+
else {
|
|
343
|
+
const T = await fetch(e);
|
|
344
|
+
if (!T.body)
|
|
345
|
+
return;
|
|
346
|
+
if (A(e)) {
|
|
347
|
+
const [M, b] = T.body.tee();
|
|
348
|
+
w.add(e, { body: b }).catch(() => {
|
|
349
|
+
}), i = new L(M);
|
|
350
|
+
} else
|
|
351
|
+
i = new L(T.body);
|
|
352
|
+
}
|
|
353
|
+
await i.ready;
|
|
354
|
+
const { width: s, height: u } = i.meta, d = document.createElement("canvas");
|
|
355
|
+
d.width = s || 1, d.height = u || 1;
|
|
356
|
+
const f = C.from(d), l = r?.sprite ?? new V(f);
|
|
357
|
+
return r?.sprite && (r.sprite.texture = f, r.oldTexture?.destroy(!0)), { kind: "mp4clip", clip: i, canvas: d, texture: f, sprite: l, meta: { width: s, height: u } };
|
|
358
|
+
} catch (s) {
|
|
359
|
+
throw i?.destroy(), s;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function Te(e) {
|
|
363
|
+
const t = e.split("#")[0].split("?")[0].split("/").pop()?.split(".").pop()?.toLowerCase() ?? "";
|
|
364
|
+
return ["mp4", "m4v", "mov", "webm"].includes(t) ? "video" : ["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg", "avif"].includes(t) ? "image" : ["mp3", "wav", "aac", "m4a", "ogg", "flac"].includes(t) ? "audio" : "unknown";
|
|
365
|
+
}
|
|
366
|
+
async function F(e, r) {
|
|
367
|
+
const t = document.createElement("video");
|
|
368
|
+
t.crossOrigin = "anonymous", t.muted = !0, t.playsInline = !0, t.preload = "auto", t.src = e;
|
|
369
|
+
try {
|
|
370
|
+
await N(t, "loadedmetadata", 4e3);
|
|
371
|
+
} catch (l) {
|
|
372
|
+
throw t.pause(), t.removeAttribute("src"), t.load(), l;
|
|
373
|
+
}
|
|
374
|
+
const i = t.videoWidth || 1, s = t.videoHeight || 1, u = document.createElement("canvas");
|
|
375
|
+
u.width = i, u.height = s;
|
|
376
|
+
const d = C.from(u), f = r?.sprite ?? new V(d);
|
|
377
|
+
return r?.sprite && (r.sprite.texture = d, r.oldTexture?.destroy(!0)), { kind: "element", video: t, canvas: u, texture: d, sprite: f, meta: { width: i, height: s } };
|
|
378
|
+
}
|
|
379
|
+
async function ge(e, r) {
|
|
380
|
+
const { video: t, canvas: i, texture: s } = e;
|
|
381
|
+
t.playbackRate = Number.isFinite(r.playbackRate) && r.playbackRate > 0 ? r.playbackRate : 1, x.value ? t.play().catch(() => {
|
|
382
|
+
}) : t.pause();
|
|
383
|
+
const u = t.currentTime, d = Math.abs(u - r.targetSec), f = x.value ? 0.25 : 0.03;
|
|
384
|
+
if (Number.isFinite(u) && d > f) {
|
|
385
|
+
try {
|
|
386
|
+
t.currentTime = r.targetSec;
|
|
387
|
+
} catch {
|
|
388
|
+
}
|
|
389
|
+
x.value || await N(t, "seeked", 250).catch(() => {
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
if (t.readyState < 2 && (await N(t, "canplay", 250).catch(() => {
|
|
393
|
+
}), t.readyState < 2))
|
|
394
|
+
return;
|
|
395
|
+
const l = i.getContext("2d");
|
|
396
|
+
l && (l.drawImage(t, 0, 0, i.width, i.height), Q(s));
|
|
397
|
+
}
|
|
398
|
+
function Ee(e) {
|
|
399
|
+
return new Promise((r) => {
|
|
400
|
+
const t = new Image();
|
|
401
|
+
t.crossOrigin = "anonymous", t.onload = () => r(C.from(t)), t.onerror = () => {
|
|
402
|
+
console.warn("[renderer] failed to load image", e), r(void 0);
|
|
403
|
+
}, t.src = e;
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
function Q(e) {
|
|
407
|
+
const r = e.source;
|
|
408
|
+
if ("update" in r && typeof r.update == "function") {
|
|
409
|
+
r.update();
|
|
282
410
|
return;
|
|
283
411
|
}
|
|
284
412
|
typeof e.update == "function" && e.update();
|
|
285
413
|
}
|
|
286
|
-
function
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
return
|
|
290
|
-
app:
|
|
291
|
-
layer:
|
|
292
|
-
currentTime:
|
|
293
|
-
duration:
|
|
294
|
-
isPlaying:
|
|
295
|
-
play:
|
|
296
|
-
pause:
|
|
297
|
-
tick:
|
|
298
|
-
seek:
|
|
299
|
-
destroy:
|
|
414
|
+
function ke() {
|
|
415
|
+
P(), q.stop(), H(), p.destroy({ children: !0 }), y.clear(), g.clear(), S.clear(), n.app || v.destroy();
|
|
416
|
+
}
|
|
417
|
+
return n.autoPlay && K(), {
|
|
418
|
+
app: v,
|
|
419
|
+
layer: p,
|
|
420
|
+
currentTime: h,
|
|
421
|
+
duration: E,
|
|
422
|
+
isPlaying: x,
|
|
423
|
+
play: K,
|
|
424
|
+
pause: P,
|
|
425
|
+
tick: J,
|
|
426
|
+
seek: de,
|
|
427
|
+
destroy: ke
|
|
300
428
|
};
|
|
301
429
|
}
|
|
302
|
-
function
|
|
303
|
-
let
|
|
430
|
+
function qe(n) {
|
|
431
|
+
let o = !1, a = !1;
|
|
304
432
|
return async () => {
|
|
305
433
|
if (a) {
|
|
306
|
-
|
|
434
|
+
o = !0;
|
|
307
435
|
return;
|
|
308
436
|
}
|
|
309
437
|
a = !0;
|
|
310
438
|
do
|
|
311
|
-
|
|
312
|
-
while (
|
|
439
|
+
o = !1, await n();
|
|
440
|
+
while (o);
|
|
313
441
|
a = !1;
|
|
314
442
|
};
|
|
315
443
|
}
|
|
316
444
|
export {
|
|
317
|
-
|
|
445
|
+
je as createRenderer
|
|
318
446
|
};
|
|
319
447
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/2d/index.ts","../src/helpers.ts","../src/index.ts"],"sourcesContent":["/// <reference types=\"vite/client\" />\nimport type { ApplicationOptions } from 'pixi.js'\nimport { Application } from 'pixi.js'\n\ndeclare global {\n\n // eslint-disable-next-line vars-on-top\n var __PIXI_APP__: Application\n}\n\nexport async function createApp(opts?: Partial<ApplicationOptions>) {\n const app = new Application()\n\n await app.init({ resizeTo: window, ...opts })\n\n if (import.meta.env.DEV) {\n globalThis.__PIXI_APP__ = app\n }\n\n return app\n}\n","import type { ITransform, IVideoProtocol, SegmentUnion } from '@video-editor/shared'\nimport type { PixiDisplayObject } from './types'\nimport { toRaw } from '@vue/reactivity'\nimport { Graphics, Sprite, Texture } from 'pixi.js'\n\nexport function collectResourceUrls(protocol: IVideoProtocol) {\n const urls = new Set<string>()\n for (const track of protocol.tracks) {\n for (const segment of track.children) {\n if (segment.url)\n urls.add(segment.url)\n }\n }\n return urls\n}\n\nexport function collectActiveSegments(protocol: IVideoProtocol, at: number) {\n const active: { segment: SegmentUnion, trackIndex: number, childIndex: number }[] = []\n protocol.tracks.forEach((track, trackIndex) => {\n track.children.forEach((segment, childIndex) => {\n if (segment.startTime <= at && at < segment.endTime)\n active.push({ segment, trackIndex, childIndex })\n })\n })\n\n return active.sort((a, b) => {\n if (a.trackIndex === b.trackIndex)\n return a.childIndex - b.childIndex\n return a.trackIndex - b.trackIndex\n })\n}\n\nexport function applyDisplayProps(display: PixiDisplayObject, segment: SegmentUnion, width: number, height: number) {\n const opacity = readOpacity(segment)\n // size\n if (display instanceof Sprite) {\n display.anchor.set(0.5)\n display.width = width\n display.height = height\n display.x = width / 2\n display.y = height / 2\n const src = display.texture.source as { addEventListener?: (type: string, cb: () => void, opts?: AddEventListenerOptions) => void } | undefined\n src?.addEventListener?.('error', () => {\n // fallback to a colored rect if texture failed\n display.texture = Texture.from(placeholderTexture(width, height))\n }, { once: true })\n }\n else if (display instanceof Graphics) {\n display.clear()\n display\n .rect(0, 0, width, height)\n .fill({ color: stringToColor('url' in segment && typeof segment.url === 'string' ? segment.url : segment.segmentType), alpha: hasOpacity(segment) ? opacity : 0.35 })\n display.pivot.set(width / 2, height / 2)\n display.position.set(width / 2, height / 2)\n }\n\n display.alpha = opacity\n\n // simple 2D transform\n const transform = readTransform(segment)\n if (transform) {\n const [px, py] = transform.position ?? [0, 0]\n const [sx, sy] = transform.scale ?? [1, 1]\n const rotation = transform.rotation?.[2] ?? 0\n\n display.position.set(width / 2 + (px * width) / 2, height / 2 - (py * height) / 2)\n display.scale.set(sx, sy)\n display.rotation = (rotation / 180) * Math.PI\n }\n}\n\nexport function placeholder(key: string, url?: string) {\n const g = new Graphics()\n g.rect(0, 0, 10, 10).fill({ color: stringToColor(url ?? key), alpha: 1 })\n return g\n}\n\nexport function placeholderTexture(width: number, height: number, color?: string) {\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"><rect width=\"100%\" height=\"100%\" fill=\"${color ?? '#0f172a'}\" fill-opacity=\"0.8\"/></svg>`\n return `data:image/svg+xml;base64,${btoa(svg)}`\n}\n\nexport function stringToColor(key: string) {\n let hash = 0\n for (let i = 0; i < key.length; i++)\n hash = key.charCodeAt(i) + ((hash << 5) - hash)\n return hash & 0x00FFFFFF\n}\n\nexport function computeDuration(protocol: IVideoProtocol) {\n const endTimes = protocol.tracks.flatMap(track => track.children.map(seg => seg.endTime))\n return endTimes.length ? Math.max(...endTimes) : 0\n}\n\nexport function clamp(num: number, min: number, max: number) {\n return Math.min(Math.max(num, min), max)\n}\n\nexport function cloneProtocol(protocol: IVideoProtocol) {\n const raw = toRaw(protocol) as IVideoProtocol\n // use JSON clone to avoid structuredClone errors on proxies (e.g., Vue reactive)\n return JSON.parse(JSON.stringify(raw)) as IVideoProtocol\n}\n\nfunction hasOpacity(segment: SegmentUnion): segment is SegmentUnion & { opacity?: number } {\n return 'opacity' in segment\n}\n\nfunction readOpacity(segment: SegmentUnion) {\n if (hasOpacity(segment) && typeof segment.opacity === 'number')\n return segment.opacity\n return 1\n}\n\nfunction hasTransform(segment: SegmentUnion): segment is SegmentUnion & { transform?: ITransform } {\n return 'transform' in segment\n}\n\nfunction readTransform(segment: SegmentUnion) {\n if (hasTransform(segment))\n return segment.transform\n return undefined\n}\n","import type { IVideoFramesSegment, IVideoProtocol, SegmentUnion } from '@video-editor/shared'\nimport type { ComputedRef, Ref, ShallowRef } from '@vue/reactivity'\nimport type { Application, ApplicationOptions } from 'pixi.js'\nimport type { MaybeRef, PixiDisplayObject } from './types'\nimport { createResourceManager, createValidator } from '@video-editor/protocol'\nimport {\n computed,\n effectScope,\n isRef,\n ref,\n shallowRef,\n unref,\n watch,\n} from '@vue/reactivity'\nimport { MP4Clip } from '@webav/av-cliper'\nimport { file as opfsFile } from 'opfs-tools'\nimport { Container, Sprite, Texture } from 'pixi.js'\nimport { createApp as create2dApp } from './2d'\nimport {\n applyDisplayProps,\n clamp,\n cloneProtocol,\n collectActiveSegments,\n collectResourceUrls,\n computeDuration,\n placeholder,\n} from './helpers'\n\nconst DEFAULT_RES_DIR = '/video-editor-res'\n\nexport interface RendererOptions {\n protocol: MaybeRef<IVideoProtocol>\n app?: Application\n appOptions?: Partial<ApplicationOptions>\n resourceDir?: string\n autoPlay?: boolean\n}\n\nexport interface Renderer {\n app: Application\n layer: Container\n currentTime: Ref<number>\n duration: ComputedRef<number>\n isPlaying: Ref<boolean>\n play: () => void\n pause: () => void\n tick: (deltaMs?: number) => void\n seek: (time: number) => void\n destroy: () => void\n}\n\n/**\n * Create a renderer that reacts to protocol updates and drives playback state.\n * - Pass a reactive `protocol` (Ref/readonly/normal object)\n * - Call `play/pause/seek/tick` to drive the timeline\n * - Rendering updates when `protocol` or `currentTime` changes\n */\nexport async function createRenderer(opts: RendererOptions): Promise<Renderer> {\n const validator = createValidator()\n const protocolInput: Ref<IVideoProtocol> | ShallowRef<IVideoProtocol>\n = isRef(opts.protocol) ? opts.protocol : shallowRef(opts.protocol)\n const validatedProtocol: ShallowRef<IVideoProtocol> = shallowRef(\n validator.verify(cloneProtocol(unref(protocolInput))),\n )\n\n const app = opts.app ?? await create2dApp(opts.appOptions)\n const layer = new Container()\n app.stage.addChild(layer)\n\n const resourceManager = createResourceManager({ dir: opts.resourceDir })\n const resourceWarmUp = new Set<string>()\n const displayCache = new Map<string, PixiDisplayObject>()\n const displayLoading = new Map<string, Promise<PixiDisplayObject | undefined>>()\n const videoEntries = new Map<string, {\n clip: MP4Clip\n canvas: HTMLCanvasElement\n texture: Texture\n sprite: Sprite\n meta?: { width: number, height: number }\n }>()\n\n const currentTime = ref(0)\n const isPlaying = ref(false)\n const duration = computed(() => computeDuration(validatedProtocol.value))\n\n let rafId: number | undefined\n let lastTickAt = 0\n\n interface RenderTask {\n app: Application\n layer: Container\n protocol: IVideoProtocol\n at: number\n getDisplay: (segment: SegmentUnion) => Promise<PixiDisplayObject | undefined>\n }\n\n async function renderScene(task: RenderTask) {\n const { protocol, at, layer } = task\n const renderAt = normalizeRenderTime(protocol, at)\n const active = collectActiveSegments(protocol, renderAt)\n const stageWidth = task.app.renderer.width\n const stageHeight = task.app.renderer.height\n\n const renders: (PixiDisplayObject | undefined)[] = []\n for (const { segment } of active) {\n const display = await task.getDisplay(segment)\n if (!display)\n continue\n applyDisplayProps(display, segment, stageWidth, stageHeight)\n if (isVideoSegment(segment))\n await updateVideoFrame(segment, renderAt)\n renders.push(display)\n }\n\n layer.removeChildren()\n const cleaned = renders.filter(Boolean) as PixiDisplayObject[]\n if (cleaned.length)\n layer.addChild(...cleaned)\n task.app.render()\n }\n\n const queueRender = createRenderQueue(() => renderScene({\n app,\n layer,\n protocol: validatedProtocol.value,\n at: currentTime.value,\n getDisplay: getDisplayForSegment,\n }))\n\n const scope = effectScope()\n scope.run(() => {\n // Sync external protocol mutations into a verified snapshot the renderer can rely on.\n watch(\n () => unref(protocolInput),\n (protocol) => {\n try {\n validatedProtocol.value = validator.verify(cloneProtocol(protocol))\n }\n catch (err) {\n console.error('[renderer] invalid protocol update', err)\n return\n }\n clearDisplays()\n warmUpResources(validatedProtocol.value)\n cleanupCache(validatedProtocol.value)\n clampCurrentTime()\n queueRender()\n },\n { deep: true, immediate: true },\n )\n\n // React to time changes.\n watch(currentTime, () => {\n clampCurrentTime()\n queueRender()\n })\n\n // Keep duration/currentTime in sync with protocol updates.\n watch(duration, () => clampCurrentTime())\n })\n\n function clampCurrentTime() {\n const nextDuration = duration.value\n if (nextDuration <= 0)\n currentTime.value = 0\n else if (currentTime.value > nextDuration)\n currentTime.value = nextDuration\n else if (currentTime.value < 0)\n currentTime.value = 0\n }\n\n function warmUpResources(protocol: IVideoProtocol) {\n for (const url of collectResourceUrls(protocol)) {\n if (resourceWarmUp.has(url))\n continue\n\n resourceWarmUp.add(url)\n resourceManager.add(url).catch(() => {\n // noop – render will fall back to Texture.from(url)\n })\n }\n }\n\n function cleanupCache(protocol: IVideoProtocol) {\n const ids = new Set(protocol.tracks.flatMap(track => track.children.map(seg => seg.id)))\n for (const [id, display] of displayCache) {\n if (ids.has(id))\n continue\n display.destroy()\n displayCache.delete(id)\n }\n for (const [id, entry] of videoEntries) {\n if (ids.has(id))\n continue\n entry.clip.destroy()\n videoEntries.delete(id)\n }\n }\n\n function clearDisplays() {\n layer.removeChildren()\n for (const display of displayCache.values()) {\n display.destroy()\n }\n displayCache.clear()\n displayLoading.clear()\n for (const { clip } of videoEntries.values())\n clip.destroy()\n videoEntries.clear()\n }\n\n function play() {\n if (isPlaying.value)\n return\n isPlaying.value = true\n lastTickAt = performance.now()\n rafId = requestAnimationFrame(loop)\n }\n\n function pause() {\n isPlaying.value = false\n if (rafId !== undefined)\n cancelAnimationFrame(rafId)\n rafId = undefined\n }\n\n function loop() {\n tick()\n if (isPlaying.value)\n rafId = requestAnimationFrame(loop)\n }\n\n function tick(deltaMs?: number) {\n if (!isPlaying.value && deltaMs === undefined)\n return\n\n const now = performance.now()\n const delta = deltaMs ?? (lastTickAt ? now - lastTickAt : 0)\n lastTickAt = now\n\n if (delta === 0)\n return\n\n currentTime.value = clamp(\n currentTime.value + delta,\n 0,\n duration.value || Number.POSITIVE_INFINITY,\n )\n\n if (duration.value > 0 && currentTime.value >= duration.value)\n pause()\n\n // render happens via watch on currentTime\n }\n\n function seek(time: number) {\n currentTime.value = clamp(time, 0, duration.value || Number.POSITIVE_INFINITY)\n }\n\n async function getDisplayForSegment(segment: SegmentUnion) {\n const cached = displayCache.get(segment.id)\n if (cached)\n return cached\n\n const loading = displayLoading.get(segment.id)\n if (loading)\n return loading\n\n const promise = loadDisplay(segment)\n displayLoading.set(segment.id, promise)\n\n const display = await promise\n if (display)\n displayCache.set(segment.id, display)\n\n displayLoading.delete(segment.id)\n return display\n }\n\n async function loadDisplay(segment: SegmentUnion): Promise<PixiDisplayObject | undefined> {\n // prioritize static resources via protocol resource manager\n if (segment.segmentType === 'frames' || segment.segmentType === 'sticker') {\n if (!segment.url)\n return placeholder(segment.segmentType)\n\n if ('type' in segment && segment.type === 'video') {\n const sprite = await loadVideoSprite(segment)\n if (sprite)\n return sprite\n }\n\n const texture = await loadTexture(segment.url)\n if (texture)\n return new Sprite(texture)\n return placeholder(segment.segmentType, segment.url)\n }\n\n if (segment.segmentType === 'text')\n return undefined\n\n if (segment.segmentType === 'effect' || segment.segmentType === 'filter')\n return undefined\n\n // audio segments do not render visuals\n return undefined\n }\n\n async function loadTexture(url: string) {\n const isDataUrl = url.startsWith('data:')\n const isHttp = /^https?:\\/\\//.test(url)\n\n if (!isDataUrl && !isHttp) {\n try {\n await resourceManager.add(url)\n const res = await resourceManager.get(url)\n if (res instanceof HTMLImageElement)\n return Texture.from(res)\n }\n catch {\n // fall through to direct image load\n }\n }\n\n // load image directly to avoid invalid path issues with http/data URLs\n return await loadImageTexture(url)\n }\n\n async function loadVideoSprite(segment: SegmentUnion & { type: 'video', url: string }): Promise<Sprite | undefined> {\n const existing = videoEntries.get(segment.id)\n if (existing)\n return existing.sprite\n\n let file\n try {\n await resourceManager.add(segment.url)\n file = await getOpfsFile(segment.url)\n }\n catch {\n file = undefined\n }\n let clip: MP4Clip\n try {\n if (file) {\n clip = new MP4Clip(file)\n }\n else {\n const res = await fetch(segment.url)\n if (!res.body)\n return undefined\n clip = new MP4Clip(res.body)\n }\n }\n catch {\n return undefined\n }\n\n try {\n await clip.ready\n }\n catch {\n clip.destroy()\n return undefined\n }\n\n const { width, height } = clip.meta\n const canvas = document.createElement('canvas')\n canvas.width = width || 1\n canvas.height = height || 1\n const texture = Texture.from(canvas)\n const sprite = new Sprite(texture)\n\n videoEntries.set(segment.id, { clip, canvas, texture, sprite, meta: { width, height } })\n return sprite\n }\n\n async function updateVideoFrame(segment: IVideoFramesSegment, at: number) {\n const entry = videoEntries.get(segment.id)\n if (!entry)\n return\n\n try {\n const offsetMs = segment.fromTime ?? 0\n const relativeMs = Math.max(0, at - segment.startTime + offsetMs)\n const relativeUs = Math.floor(relativeMs * 1000)\n const res = await entry.clip.tick(relativeUs)\n if (res.video) {\n const ctx = entry.canvas.getContext('2d')\n if (ctx) {\n ctx.drawImage(res.video, 0, 0, entry.canvas.width, entry.canvas.height)\n refreshCanvasTexture(entry.texture)\n }\n res.video.close()\n }\n }\n catch (err) {\n console.warn('[renderer] update video frame failed', err)\n }\n }\n\n function isVideoSegment(segment: SegmentUnion): segment is IVideoFramesSegment {\n return segment.segmentType === 'frames'\n && segment.type === 'video'\n && typeof segment.url === 'string'\n }\n\n function normalizeRenderTime(protocol: IVideoProtocol, at: number) {\n const total = computeDuration(protocol)\n if (total <= 0)\n return 0\n if (at < total)\n return at\n // Keep the last visible frame when playback reaches the end.\n const frameWindow = Math.max(1000 / Math.max(protocol.fps || 30, 1), 1)\n return Math.max(total - frameWindow, 0)\n }\n\n async function getOpfsFile(url: string) {\n const dir = opts.resourceDir ?? DEFAULT_RES_DIR\n try {\n const file = opfsFile(`${dir}/${url}`)\n if (await file.exists())\n return file\n }\n catch {\n return undefined\n }\n return undefined\n }\n\n function loadImageTexture(url: string): Promise<Texture | undefined> {\n return new Promise((resolve) => {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => resolve(Texture.from(img))\n img.onerror = () => {\n console.warn('[renderer] failed to load image', url)\n resolve(undefined)\n }\n img.src = url\n })\n }\n\n function refreshCanvasTexture(texture: Texture) {\n const source = texture.source\n if ('update' in source && typeof source.update === 'function') {\n source.update()\n return\n }\n\n if (typeof texture.update === 'function')\n texture.update()\n }\n\n function destroy() {\n pause()\n scope.stop()\n clearDisplays()\n layer.destroy({ children: true })\n displayCache.clear()\n displayLoading.clear()\n resourceWarmUp.clear()\n if (!opts.app)\n app.destroy()\n }\n\n if (opts.autoPlay)\n play()\n\n return {\n app,\n layer,\n currentTime,\n duration,\n isPlaying,\n play,\n pause,\n tick,\n seek,\n destroy,\n }\n}\n\nfunction createRenderQueue(job: () => Promise<void> | void) {\n let queued = false\n let running = false\n\n const run = async () => {\n if (running) {\n queued = true\n return\n }\n running = true\n do {\n queued = false\n await job()\n } while (queued)\n running = false\n }\n\n return run\n}\n"],"names":["createApp","opts","app","Application","collectResourceUrls","protocol","urls","track","segment","collectActiveSegments","at","active","trackIndex","childIndex","a","b","applyDisplayProps","display","width","height","opacity","readOpacity","Sprite","Texture","placeholderTexture","Graphics","stringToColor","hasOpacity","transform","readTransform","px","py","sx","sy","rotation","placeholder","key","url","g","color","svg","hash","i","computeDuration","endTimes","seg","clamp","num","min","max","cloneProtocol","raw","toRaw","hasTransform","DEFAULT_RES_DIR","createRenderer","validator","createValidator","protocolInput","isRef","shallowRef","validatedProtocol","unref","create2dApp","layer","Container","resourceManager","createResourceManager","resourceWarmUp","displayCache","displayLoading","videoEntries","currentTime","ref","isPlaying","duration","computed","rafId","lastTickAt","renderScene","task","renderAt","normalizeRenderTime","stageWidth","stageHeight","renders","isVideoSegment","updateVideoFrame","cleaned","queueRender","createRenderQueue","getDisplayForSegment","scope","effectScope","watch","err","clearDisplays","warmUpResources","cleanupCache","clampCurrentTime","nextDuration","ids","id","entry","clip","play","loop","pause","tick","deltaMs","now","delta","seek","time","cached","loading","promise","loadDisplay","sprite","loadVideoSprite","texture","loadTexture","isDataUrl","isHttp","res","loadImageTexture","existing","file","getOpfsFile","MP4Clip","canvas","offsetMs","relativeMs","relativeUs","ctx","refreshCanvasTexture","total","frameWindow","dir","opfsFile","resolve","img","source","destroy","job","queued","running"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/2d/index.ts","../src/helpers.ts","../src/index.ts"],"sourcesContent":["/// <reference types=\"vite/client\" />\nimport type { ApplicationOptions } from 'pixi.js'\nimport { Application } from 'pixi.js'\n\ndeclare global {\n\n // eslint-disable-next-line vars-on-top\n var __PIXI_APP__: Application\n}\n\nexport async function createApp(opts?: Partial<ApplicationOptions>) {\n const app = new Application()\n\n await app.init({ resizeTo: window, ...opts })\n\n if (import.meta.env.DEV) {\n globalThis.__PIXI_APP__ = app\n }\n\n return app\n}\n","import type { ITransform, IVideoProtocol, SegmentUnion } from '@video-editor/shared'\nimport type { PixiDisplayObject } from './types'\nimport { toRaw } from '@vue/reactivity'\nimport { Graphics, Sprite, Texture } from 'pixi.js'\n\nexport function collectResourceUrls(protocol: IVideoProtocol) {\n const urls = new Set<string>()\n for (const track of protocol.tracks) {\n for (const segment of track.children) {\n if (segment.url)\n urls.add(segment.url)\n }\n }\n return urls\n}\n\nexport function collectActiveSegments(protocol: IVideoProtocol, at: number) {\n const active: { segment: SegmentUnion, trackIndex: number, childIndex: number }[] = []\n protocol.tracks.forEach((track, trackIndex) => {\n track.children.forEach((segment, childIndex) => {\n if (segment.startTime <= at && at < segment.endTime)\n active.push({ segment, trackIndex, childIndex })\n })\n })\n\n return active.sort((a, b) => {\n if (a.trackIndex === b.trackIndex)\n return a.childIndex - b.childIndex\n return a.trackIndex - b.trackIndex\n })\n}\n\nexport function applyDisplayProps(display: PixiDisplayObject, segment: SegmentUnion, width: number, height: number) {\n const opacity = readOpacity(segment)\n // size\n if (display instanceof Sprite) {\n display.anchor.set(0.5)\n display.width = width\n display.height = height\n display.x = width / 2\n display.y = height / 2\n const src = display.texture.source as { addEventListener?: (type: string, cb: () => void, opts?: AddEventListenerOptions) => void } | undefined\n src?.addEventListener?.('error', () => {\n // fallback to a colored rect if texture failed\n display.texture = Texture.from(placeholderTexture(width, height))\n }, { once: true })\n }\n else if (display instanceof Graphics) {\n display.clear()\n display\n .rect(0, 0, width, height)\n .fill({ color: stringToColor('url' in segment && typeof segment.url === 'string' ? segment.url : segment.segmentType), alpha: hasOpacity(segment) ? opacity : 0.35 })\n display.pivot.set(width / 2, height / 2)\n display.position.set(width / 2, height / 2)\n }\n\n display.alpha = opacity\n\n // simple 2D transform\n const transform = readTransform(segment)\n if (transform) {\n const [px, py] = transform.position ?? [0, 0]\n const [sx, sy] = transform.scale ?? [1, 1]\n const rotation = transform.rotation?.[2] ?? 0\n\n display.position.set(width / 2 + (px * width) / 2, height / 2 - (py * height) / 2)\n display.scale.set(sx, sy)\n display.rotation = (rotation / 180) * Math.PI\n }\n}\n\nexport function placeholder(key: string, url?: string) {\n const g = new Graphics()\n g.rect(0, 0, 10, 10).fill({ color: stringToColor(url ?? key), alpha: 1 })\n return g\n}\n\nexport function placeholderTexture(width: number, height: number, color?: string) {\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"><rect width=\"100%\" height=\"100%\" fill=\"${color ?? '#0f172a'}\" fill-opacity=\"0.8\"/></svg>`\n return `data:image/svg+xml;base64,${btoa(svg)}`\n}\n\nexport function stringToColor(key: string) {\n let hash = 0\n for (let i = 0; i < key.length; i++)\n hash = key.charCodeAt(i) + ((hash << 5) - hash)\n return hash & 0x00FFFFFF\n}\n\nexport function computeDuration(protocol: IVideoProtocol) {\n const endTimes = protocol.tracks.flatMap(track => track.children.map(seg => seg.endTime))\n return endTimes.length ? Math.max(...endTimes) : 0\n}\n\nexport function clamp(num: number, min: number, max: number) {\n return Math.min(Math.max(num, min), max)\n}\n\nexport function cloneProtocol(protocol: IVideoProtocol) {\n const raw = toRaw(protocol) as IVideoProtocol\n // use JSON clone to avoid structuredClone errors on proxies (e.g., Vue reactive)\n return JSON.parse(JSON.stringify(raw)) as IVideoProtocol\n}\n\nfunction hasOpacity(segment: SegmentUnion): segment is SegmentUnion & { opacity?: number } {\n return 'opacity' in segment\n}\n\nfunction readOpacity(segment: SegmentUnion) {\n if (hasOpacity(segment) && typeof segment.opacity === 'number')\n return segment.opacity\n return 1\n}\n\nfunction hasTransform(segment: SegmentUnion): segment is SegmentUnion & { transform?: ITransform } {\n return 'transform' in segment\n}\n\nfunction readTransform(segment: SegmentUnion) {\n if (hasTransform(segment))\n return segment.transform\n return undefined\n}\n","import type { IVideoFramesSegment, IVideoProtocol, SegmentUnion } from '@video-editor/shared'\nimport type { ComputedRef, Ref, ShallowRef } from '@vue/reactivity'\nimport type { Application, ApplicationOptions } from 'pixi.js'\nimport type { MaybeRef, PixiDisplayObject } from './types'\nimport { createResourceManager, createValidator, getResourceKey } from '@video-editor/protocol'\nimport {\n computed,\n effectScope,\n isRef,\n ref,\n shallowRef,\n unref,\n watch,\n} from '@vue/reactivity'\nimport { MP4Clip } from '@webav/av-cliper'\nimport { file as opfsFile } from 'opfs-tools'\nimport { Container, Sprite, Texture } from 'pixi.js'\nimport { createApp as create2dApp } from './2d'\nimport {\n applyDisplayProps,\n clamp,\n cloneProtocol,\n collectActiveSegments,\n collectResourceUrls,\n computeDuration,\n placeholder,\n} from './helpers'\n\nconst DEFAULT_RES_DIR = '/video-editor-res'\n\nexport interface RendererOptions {\n protocol: MaybeRef<IVideoProtocol>\n app?: Application\n appOptions?: Partial<ApplicationOptions>\n resourceDir?: string\n autoPlay?: boolean\n}\n\nexport interface Renderer {\n app: Application\n layer: Container\n currentTime: Ref<number>\n duration: ComputedRef<number>\n isPlaying: Ref<boolean>\n play: () => void\n pause: () => void\n tick: (deltaMs?: number) => void\n seek: (time: number) => void\n destroy: () => void\n}\n\n/**\n * Create a renderer that reacts to protocol updates and drives playback state.\n * - Pass a reactive `protocol` (Ref/readonly/normal object)\n * - Call `play/pause/seek/tick` to drive the timeline\n * - Rendering updates when `protocol` or `currentTime` changes\n */\nexport async function createRenderer(opts: RendererOptions): Promise<Renderer> {\n const validator = createValidator()\n const protocolInput: Ref<IVideoProtocol> | ShallowRef<IVideoProtocol>\n = isRef(opts.protocol) ? opts.protocol : shallowRef(opts.protocol)\n const validatedProtocol: ShallowRef<IVideoProtocol> = shallowRef(\n validator.verify(cloneProtocol(unref(protocolInput))),\n )\n\n const app = opts.app ?? await create2dApp(opts.appOptions)\n const layer = new Container()\n app.stage.addChild(layer)\n\n const resourceManager = createResourceManager({ dir: opts.resourceDir })\n const resourceWarmUp = new Set<string>()\n const displayCache = new Map<string, PixiDisplayObject>()\n const displayLoading = new Map<string, Promise<PixiDisplayObject | undefined>>()\n const mp4ClipUnsupportedKeys = new Set<string>()\n const mp4ClipErrorLoggedKeys = new Set<string>()\n type VideoEntry = (\n | {\n kind: 'mp4clip'\n clip: MP4Clip\n canvas: HTMLCanvasElement\n texture: Texture\n sprite: Sprite\n meta?: { width: number, height: number }\n }\n | {\n kind: 'element'\n video: HTMLVideoElement\n canvas: HTMLCanvasElement\n texture: Texture\n sprite: Sprite\n meta?: { width: number, height: number }\n }\n | {\n kind: 'frozen'\n canvas: HTMLCanvasElement\n texture: Texture\n sprite: Sprite\n meta?: { width: number, height: number }\n }\n )\n const videoEntries = new Map<string, VideoEntry>()\n\n const currentTime = ref(0)\n const isPlaying = ref(false)\n const duration = computed(() => computeDuration(validatedProtocol.value))\n\n let rafId: number | undefined\n let lastTickAt = 0\n\n interface RenderTask {\n app: Application\n layer: Container\n protocol: IVideoProtocol\n at: number\n getDisplay: (segment: SegmentUnion) => Promise<PixiDisplayObject | undefined>\n }\n\n async function renderScene(task: RenderTask) {\n const { protocol, at, layer } = task\n const renderAt = normalizeRenderTime(protocol, at)\n const active = collectActiveSegments(protocol, renderAt)\n const stageWidth = task.app.renderer.width\n const stageHeight = task.app.renderer.height\n\n const renders: (PixiDisplayObject | undefined)[] = []\n for (const { segment } of active) {\n const display = await task.getDisplay(segment)\n if (!display)\n continue\n applyDisplayProps(display, segment, stageWidth, stageHeight)\n if (isVideoSegment(segment))\n await updateVideoFrame(segment, renderAt)\n renders.push(display)\n }\n\n layer.removeChildren()\n const cleaned = renders.filter(Boolean) as PixiDisplayObject[]\n if (cleaned.length)\n layer.addChild(...cleaned)\n task.app.render()\n }\n\n const queueRender = createRenderQueue(() => renderScene({\n app,\n layer,\n protocol: validatedProtocol.value,\n at: currentTime.value,\n getDisplay: getDisplayForSegment,\n }))\n\n const scope = effectScope()\n scope.run(() => {\n // Sync external protocol mutations into a verified snapshot the renderer can rely on.\n watch(\n () => unref(protocolInput),\n (protocol) => {\n try {\n validatedProtocol.value = validator.verify(cloneProtocol(protocol))\n }\n catch (err) {\n console.error('[renderer] invalid protocol update', err)\n return\n }\n clearDisplays()\n warmUpResources(validatedProtocol.value)\n cleanupCache(validatedProtocol.value)\n clampCurrentTime()\n queueRender()\n },\n { deep: true, immediate: true },\n )\n\n // React to time changes.\n watch(currentTime, () => {\n clampCurrentTime()\n queueRender()\n })\n\n // Keep duration/currentTime in sync with protocol updates.\n watch(duration, () => clampCurrentTime())\n })\n\n function clampCurrentTime() {\n const nextDuration = duration.value\n if (nextDuration <= 0)\n currentTime.value = 0\n else if (currentTime.value > nextDuration)\n currentTime.value = nextDuration\n else if (currentTime.value < 0)\n currentTime.value = 0\n }\n\n function warmUpResources(protocol: IVideoProtocol) {\n for (const url of collectResourceUrls(protocol)) {\n if (resourceWarmUp.has(url))\n continue\n\n resourceWarmUp.add(url)\n if (inferUrlMediaType(url) === 'video')\n continue\n if (!shouldUseResourceManager(url))\n continue\n resourceManager.add(url).catch(() => {\n // noop – render will fall back to Texture.from(url)\n })\n }\n }\n\n function cleanupCache(protocol: IVideoProtocol) {\n const ids = new Set(protocol.tracks.flatMap(track => track.children.map(seg => seg.id)))\n for (const [id, display] of displayCache) {\n if (ids.has(id))\n continue\n display.destroy()\n displayCache.delete(id)\n }\n for (const [id, entry] of videoEntries) {\n if (ids.has(id))\n continue\n destroyVideoEntry(entry)\n videoEntries.delete(id)\n }\n }\n\n function clearDisplays() {\n layer.removeChildren()\n for (const display of displayCache.values()) {\n display.destroy()\n }\n displayCache.clear()\n displayLoading.clear()\n for (const entry of videoEntries.values())\n destroyVideoEntry(entry)\n videoEntries.clear()\n }\n\n function play() {\n if (isPlaying.value)\n return\n isPlaying.value = true\n lastTickAt = performance.now()\n rafId = requestAnimationFrame(loop)\n }\n\n function pause() {\n isPlaying.value = false\n if (rafId !== undefined)\n cancelAnimationFrame(rafId)\n rafId = undefined\n freezeVideoEntries()\n }\n\n function loop() {\n tick()\n if (isPlaying.value)\n rafId = requestAnimationFrame(loop)\n }\n\n function tick(deltaMs?: number) {\n if (!isPlaying.value && deltaMs === undefined)\n return\n\n const now = performance.now()\n const delta = deltaMs ?? (lastTickAt ? now - lastTickAt : 0)\n lastTickAt = now\n\n if (delta === 0)\n return\n\n currentTime.value = clamp(\n currentTime.value + delta,\n 0,\n duration.value || Number.POSITIVE_INFINITY,\n )\n\n if (duration.value > 0 && currentTime.value >= duration.value)\n pause()\n\n // render happens via watch on currentTime\n }\n\n function seek(time: number) {\n currentTime.value = clamp(time, 0, duration.value || Number.POSITIVE_INFINITY)\n }\n\n async function getDisplayForSegment(segment: SegmentUnion) {\n const cached = displayCache.get(segment.id)\n if (cached)\n return cached\n\n const loading = displayLoading.get(segment.id)\n if (loading)\n return loading\n\n const promise = loadDisplay(segment)\n displayLoading.set(segment.id, promise)\n\n const display = await promise\n if (display)\n displayCache.set(segment.id, display)\n\n displayLoading.delete(segment.id)\n return display\n }\n\n async function loadDisplay(segment: SegmentUnion): Promise<PixiDisplayObject | undefined> {\n // prioritize static resources via protocol resource manager\n if (segment.segmentType === 'frames' || segment.segmentType === 'sticker') {\n if (!segment.url)\n return placeholder(segment.segmentType)\n\n if ('type' in segment && segment.type === 'video') {\n const sprite = await loadVideoSprite(segment)\n if (sprite)\n return sprite\n return placeholder(segment.segmentType, segment.url)\n }\n\n const texture = await loadTexture(segment.url)\n if (texture)\n return new Sprite(texture)\n return placeholder(segment.segmentType, segment.url)\n }\n\n if (segment.segmentType === 'text')\n return undefined\n\n if (segment.segmentType === 'effect' || segment.segmentType === 'filter')\n return undefined\n\n // audio segments do not render visuals\n return undefined\n }\n\n async function loadTexture(url: string) {\n const isDataUrl = url.startsWith('data:')\n const isHttp = /^https?:\\/\\//.test(url)\n\n if (!isDataUrl && !isHttp) {\n try {\n await resourceManager.add(url)\n const res = await resourceManager.get(url)\n if (res instanceof HTMLImageElement)\n return Texture.from(res)\n }\n catch {\n // fall through to direct image load\n }\n }\n\n // load image directly to avoid invalid path issues with http/data URLs\n return await loadImageTexture(url)\n }\n\n async function loadVideoSprite(segment: SegmentUnion & { type: 'video', url: string }): Promise<Sprite | undefined> {\n const existing = videoEntries.get(segment.id)\n if (existing)\n return existing.sprite\n\n const urlKey = getResourceKey(segment.url)\n if (urlKey && mp4ClipUnsupportedKeys.has(urlKey)) {\n const spriteFromElement = await loadVideoSpriteViaElement(segment.url).catch((err) => {\n console.warn('[renderer] failed to load video via <video>', segment.url, err)\n return undefined\n })\n if (spriteFromElement) {\n videoEntries.set(segment.id, spriteFromElement)\n return spriteFromElement.sprite\n }\n return undefined\n }\n\n const spriteFromClip = await loadVideoSpriteViaMP4Clip(segment.url).catch((err) => {\n if (urlKey && isMp4ClipUnsupported(err))\n mp4ClipUnsupportedKeys.add(urlKey)\n if (!urlKey || !mp4ClipErrorLoggedKeys.has(urlKey)) {\n if (urlKey)\n mp4ClipErrorLoggedKeys.add(urlKey)\n console.warn('[renderer] failed to load video via MP4Clip', segment.url, err)\n }\n return undefined\n })\n if (spriteFromClip) {\n videoEntries.set(segment.id, spriteFromClip)\n return spriteFromClip.sprite\n }\n\n const spriteFromElement = await loadVideoSpriteViaElement(segment.url).catch((err) => {\n console.warn('[renderer] failed to load video via <video>', segment.url, err)\n return undefined\n })\n if (spriteFromElement) {\n videoEntries.set(segment.id, spriteFromElement)\n return spriteFromElement.sprite\n }\n\n return undefined\n }\n\n function isMp4ClipUnsupported(err: unknown) {\n if (!(err instanceof Error))\n return false\n const msg = err.message || ''\n return msg.includes('stream is done') || msg.includes('not emit ready')\n }\n\n async function updateVideoFrame(segment: IVideoFramesSegment, at: number) {\n const entry = videoEntries.get(segment.id)\n if (!entry)\n return\n\n try {\n const offsetMs = segment.fromTime ?? 0\n const relativeMs = Math.max(0, at - segment.startTime + offsetMs)\n const relativeUs = Math.floor(relativeMs * 1000)\n if (entry.kind === 'frozen') {\n const urlKey = getResourceKey(segment.url)\n if (!urlKey)\n return\n const revived = await loadVideoEntry(segment.url, urlKey, { sprite: entry.sprite, oldTexture: entry.texture })\n if (!revived)\n return\n videoEntries.set(segment.id, revived)\n return await updateVideoFrame(segment, at)\n }\n if (entry.kind === 'mp4clip') {\n const res = await entry.clip.tick(relativeUs)\n if (res.video) {\n const ctx = entry.canvas.getContext('2d')\n if (ctx) {\n ctx.drawImage(res.video, 0, 0, entry.canvas.width, entry.canvas.height)\n refreshCanvasTexture(entry.texture)\n }\n res.video.close()\n }\n return\n }\n\n const relativeSec = relativeMs / 1000\n if (!Number.isFinite(relativeSec))\n return\n if (entry.kind !== 'element')\n return\n await updateVideoElementFrame(entry, {\n targetSec: relativeSec,\n playbackRate: segment.playRate ?? 1,\n })\n }\n catch (err) {\n console.warn('[renderer] update video frame failed', err)\n }\n }\n\n async function loadVideoEntry(url: string, urlKey: string, reuse: { sprite: Sprite, oldTexture?: Texture }) {\n if (mp4ClipUnsupportedKeys.has(urlKey))\n return await loadVideoSpriteViaElement(url, reuse).catch(() => undefined)\n\n const fromClip = await loadVideoSpriteViaMP4Clip(url, reuse).catch((err) => {\n if (isMp4ClipUnsupported(err))\n mp4ClipUnsupportedKeys.add(urlKey)\n return undefined\n })\n if (fromClip)\n return fromClip\n return await loadVideoSpriteViaElement(url, reuse).catch(() => undefined)\n }\n\n function isVideoSegment(segment: SegmentUnion): segment is IVideoFramesSegment {\n return segment.segmentType === 'frames'\n && segment.type === 'video'\n && typeof segment.url === 'string'\n }\n\n function normalizeRenderTime(protocol: IVideoProtocol, at: number) {\n const total = computeDuration(protocol)\n if (total <= 0)\n return 0\n if (at < total)\n return at\n // Keep the last visible frame when playback reaches the end.\n const frameWindow = Math.max(1000 / Math.max(protocol.fps || 30, 1), 1)\n return Math.max(total - frameWindow, 0)\n }\n\n async function getOpfsFile(url: string) {\n const dir = opts.resourceDir ?? DEFAULT_RES_DIR\n try {\n const key = getResourceKey(url)\n if (!key)\n return undefined\n const file = opfsFile(`${dir}/${key}`, 'r')\n if (await file.exists())\n return file\n }\n catch {\n return undefined\n }\n return undefined\n }\n\n function shouldUseResourceManager(url: string) {\n if (!url)\n return false\n if (url.startsWith('data:') || url.startsWith('blob:'))\n return false\n return true\n }\n\n function freezeVideoEntries() {\n for (const [id, entry] of videoEntries) {\n if (entry.kind === 'mp4clip') {\n entry.clip.destroy()\n videoEntries.set(id, {\n kind: 'frozen',\n canvas: entry.canvas,\n texture: entry.texture,\n sprite: entry.sprite,\n meta: entry.meta,\n })\n continue\n }\n\n if (entry.kind === 'element')\n entry.video.pause()\n }\n }\n\n function destroyVideoEntry(entry: VideoEntry) {\n if (entry.kind === 'mp4clip') {\n entry.clip.destroy()\n return\n }\n\n if (entry.kind === 'frozen')\n return\n\n entry.video.pause()\n entry.video.removeAttribute('src')\n entry.video.load()\n }\n\n function waitForMediaEvent(target: HTMLMediaElement, type: string, timeoutMs = 1000) {\n return new Promise<void>((resolve, reject) => {\n const timer = window.setTimeout(() => {\n cleanup()\n reject(new Error(`Timed out waiting for media event: ${type}`))\n }, timeoutMs)\n\n const onOk = () => {\n cleanup()\n resolve()\n }\n const onErr = () => {\n cleanup()\n const mediaError = target.error ? `${target.error.code}` : 'unknown'\n reject(new Error(`Media error (${mediaError}) while waiting for ${type}`))\n }\n const cleanup = () => {\n window.clearTimeout(timer)\n target.removeEventListener(type, onOk)\n target.removeEventListener('error', onErr)\n }\n\n target.addEventListener(type, onOk, { once: true })\n target.addEventListener('error', onErr, { once: true })\n })\n }\n\n async function loadVideoSpriteViaMP4Clip(url: string, reuse?: { sprite: Sprite, oldTexture?: Texture }): Promise<VideoEntry | undefined> {\n let file: ReturnType<typeof opfsFile> | undefined\n if (shouldUseResourceManager(url))\n file = await getOpfsFile(url)\n\n let clip: MP4Clip | undefined\n try {\n if (file) {\n clip = new MP4Clip(file)\n }\n else {\n const res = await fetch(url)\n if (!res.body)\n return undefined\n if (shouldUseResourceManager(url)) {\n const [clipStream, cacheStream] = res.body.tee()\n resourceManager.add(url, { body: cacheStream }).catch(() => {})\n clip = new MP4Clip(clipStream)\n }\n else {\n clip = new MP4Clip(res.body)\n }\n }\n\n await clip.ready\n\n const { width, height } = clip.meta\n const canvas = document.createElement('canvas')\n canvas.width = width || 1\n canvas.height = height || 1\n const texture = Texture.from(canvas)\n const sprite = reuse?.sprite ?? new Sprite(texture)\n if (reuse?.sprite) {\n reuse.sprite.texture = texture\n reuse.oldTexture?.destroy(true)\n }\n\n return { kind: 'mp4clip', clip, canvas, texture, sprite, meta: { width, height } }\n }\n catch (err) {\n clip?.destroy()\n throw err\n }\n }\n\n function inferUrlMediaType(url: string): 'video' | 'image' | 'audio' | 'unknown' {\n const raw = url.split('#')[0]!.split('?')[0]!\n const ext = raw.split('/').pop()?.split('.').pop()?.toLowerCase() ?? ''\n if (['mp4', 'm4v', 'mov', 'webm'].includes(ext))\n return 'video'\n if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'svg', 'avif'].includes(ext))\n return 'image'\n if (['mp3', 'wav', 'aac', 'm4a', 'ogg', 'flac'].includes(ext))\n return 'audio'\n return 'unknown'\n }\n\n async function loadVideoSpriteViaElement(url: string, reuse?: { sprite: Sprite, oldTexture?: Texture }): Promise<VideoEntry | undefined> {\n const video = document.createElement('video')\n video.crossOrigin = 'anonymous'\n video.muted = true\n video.playsInline = true\n video.preload = 'auto'\n video.src = url\n\n try {\n await waitForMediaEvent(video, 'loadedmetadata', 4000)\n }\n catch (err) {\n video.pause()\n video.removeAttribute('src')\n video.load()\n throw err\n }\n\n const width = video.videoWidth || 1\n const height = video.videoHeight || 1\n\n const canvas = document.createElement('canvas')\n canvas.width = width\n canvas.height = height\n const texture = Texture.from(canvas)\n const sprite = reuse?.sprite ?? new Sprite(texture)\n if (reuse?.sprite) {\n reuse.sprite.texture = texture\n reuse.oldTexture?.destroy(true)\n }\n\n return { kind: 'element', video, canvas, texture, sprite, meta: { width, height } }\n }\n\n async function updateVideoElementFrame(entry: Extract<VideoEntry, { kind: 'element' }>, opts: { targetSec: number, playbackRate: number }) {\n const { video, canvas, texture } = entry\n\n video.playbackRate = Number.isFinite(opts.playbackRate) && opts.playbackRate > 0 ? opts.playbackRate : 1\n if (isPlaying.value)\n video.play().catch(() => {})\n else\n video.pause()\n\n const current = video.currentTime\n const drift = Math.abs(current - opts.targetSec)\n const driftThreshold = isPlaying.value ? 0.25 : 0.03\n if (Number.isFinite(current) && drift > driftThreshold) {\n try {\n video.currentTime = opts.targetSec\n }\n catch {\n // ignore seek errors for not-yet-ready media\n }\n if (!isPlaying.value)\n await waitForMediaEvent(video, 'seeked', 250).catch(() => {})\n }\n\n if (video.readyState < 2) {\n // Avoid blocking the render queue for too long.\n await waitForMediaEvent(video, 'canplay', 250).catch(() => {})\n if (video.readyState < 2)\n return\n }\n\n const ctx = canvas.getContext('2d')\n if (!ctx)\n return\n ctx.drawImage(video, 0, 0, canvas.width, canvas.height)\n refreshCanvasTexture(texture)\n }\n\n function loadImageTexture(url: string): Promise<Texture | undefined> {\n return new Promise((resolve) => {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => resolve(Texture.from(img))\n img.onerror = () => {\n console.warn('[renderer] failed to load image', url)\n resolve(undefined)\n }\n img.src = url\n })\n }\n\n function refreshCanvasTexture(texture: Texture) {\n const source = texture.source\n if ('update' in source && typeof source.update === 'function') {\n source.update()\n return\n }\n\n if (typeof texture.update === 'function')\n texture.update()\n }\n\n function destroy() {\n pause()\n scope.stop()\n clearDisplays()\n layer.destroy({ children: true })\n displayCache.clear()\n displayLoading.clear()\n resourceWarmUp.clear()\n if (!opts.app)\n app.destroy()\n }\n\n if (opts.autoPlay)\n play()\n\n return {\n app,\n layer,\n currentTime,\n duration,\n isPlaying,\n play,\n pause,\n tick,\n seek,\n destroy,\n }\n}\n\nfunction createRenderQueue(job: () => Promise<void> | void) {\n let queued = false\n let running = false\n\n const run = async () => {\n if (running) {\n queued = true\n return\n }\n running = true\n do {\n queued = false\n await job()\n } while (queued)\n running = false\n }\n\n return run\n}\n"],"names":["createApp","opts","app","Application","collectResourceUrls","protocol","urls","track","segment","collectActiveSegments","at","active","trackIndex","childIndex","a","b","applyDisplayProps","display","width","height","opacity","readOpacity","Sprite","Texture","placeholderTexture","Graphics","stringToColor","hasOpacity","transform","readTransform","px","py","sx","sy","rotation","placeholder","key","url","g","color","svg","hash","i","computeDuration","endTimes","seg","clamp","num","min","max","cloneProtocol","raw","toRaw","hasTransform","DEFAULT_RES_DIR","createRenderer","validator","createValidator","protocolInput","isRef","shallowRef","validatedProtocol","unref","create2dApp","layer","Container","resourceManager","createResourceManager","resourceWarmUp","displayCache","displayLoading","mp4ClipUnsupportedKeys","mp4ClipErrorLoggedKeys","videoEntries","currentTime","ref","isPlaying","duration","computed","rafId","lastTickAt","renderScene","task","renderAt","normalizeRenderTime","stageWidth","stageHeight","renders","isVideoSegment","updateVideoFrame","cleaned","queueRender","createRenderQueue","getDisplayForSegment","scope","effectScope","watch","err","clearDisplays","warmUpResources","cleanupCache","clampCurrentTime","nextDuration","inferUrlMediaType","shouldUseResourceManager","ids","id","entry","destroyVideoEntry","play","loop","pause","freezeVideoEntries","tick","deltaMs","now","delta","seek","time","cached","loading","promise","loadDisplay","sprite","loadVideoSprite","texture","loadTexture","isDataUrl","isHttp","res","loadImageTexture","existing","urlKey","getResourceKey","spriteFromElement","loadVideoSpriteViaElement","spriteFromClip","loadVideoSpriteViaMP4Clip","isMp4ClipUnsupported","msg","offsetMs","relativeMs","relativeUs","revived","loadVideoEntry","ctx","refreshCanvasTexture","relativeSec","updateVideoElementFrame","reuse","fromClip","total","frameWindow","getOpfsFile","dir","file","opfsFile","waitForMediaEvent","target","type","timeoutMs","resolve","reject","timer","cleanup","onOk","onErr","mediaError","clip","MP4Clip","clipStream","cacheStream","canvas","ext","video","current","drift","driftThreshold","img","source","destroy","job","queued","running"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@video-editor/renderer",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.15",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"import": "./dist/index.js"
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"@webav/av-cliper": "^1.2.7",
|
|
22
22
|
"opfs-tools": "^0.7.4",
|
|
23
23
|
"pixi.js": "^8.14.3",
|
|
24
|
-
"@video-editor/protocol": "0.0.1-beta.
|
|
25
|
-
"@video-editor/shared": "0.0.1-beta.
|
|
24
|
+
"@video-editor/protocol": "0.0.1-beta.15",
|
|
25
|
+
"@video-editor/shared": "0.0.1-beta.15"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "vite build",
|