@video-editor/renderer 0.0.1-beta.5 → 0.0.1-beta.7
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 +131 -122
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { createValidator as
|
|
2
|
-
import { toRaw as
|
|
1
|
+
import { createValidator as le, createResourceManager as de } from "@video-editor/protocol";
|
|
2
|
+
import { toRaw as pe, isRef as ve, shallowRef as q, unref as L, ref as W, computed as he, effectScope as ye, watch as k } from "@vue/reactivity";
|
|
3
3
|
import { MP4Clip as _ } from "@webav/av-cliper";
|
|
4
|
-
import { file as
|
|
5
|
-
import { Application as
|
|
6
|
-
async function
|
|
7
|
-
const n = new
|
|
4
|
+
import { file as me } from "opfs-tools";
|
|
5
|
+
import { Application as we, Sprite as F, Texture as R, Graphics as B, Container as Te } from "pixi.js";
|
|
6
|
+
async function xe(t) {
|
|
7
|
+
const n = new we();
|
|
8
8
|
return await n.init({ resizeTo: window, ...t }), n;
|
|
9
9
|
}
|
|
10
|
-
function
|
|
10
|
+
function Ie(t) {
|
|
11
11
|
const n = /* @__PURE__ */ new Set();
|
|
12
12
|
for (const a of t.tracks)
|
|
13
13
|
for (const i of a.children)
|
|
14
14
|
i.url && n.add(i.url);
|
|
15
15
|
return n;
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function ge(t, n) {
|
|
18
18
|
const a = [];
|
|
19
19
|
return t.tracks.forEach((i, u) => {
|
|
20
20
|
i.children.forEach((s, p) => {
|
|
@@ -22,189 +22,189 @@ function Te(t, n) {
|
|
|
22
22
|
});
|
|
23
23
|
}), a.sort((i, u) => i.trackIndex === u.trackIndex ? i.childIndex - u.childIndex : i.trackIndex - u.trackIndex);
|
|
24
24
|
}
|
|
25
|
-
function
|
|
26
|
-
const u =
|
|
25
|
+
function Me(t, n, a, i) {
|
|
26
|
+
const u = Ce(n);
|
|
27
27
|
t instanceof F ? (t.anchor.set(0.5), t.width = a, t.height = i, t.x = a / 2, t.y = i / 2, t.texture.source?.addEventListener?.("error", () => {
|
|
28
|
-
t.texture =
|
|
29
|
-
}, { once: !0 })) : t instanceof
|
|
30
|
-
const s =
|
|
28
|
+
t.texture = R.from(Se(a, i));
|
|
29
|
+
}, { once: !0 })) : t instanceof B && (t.clear(), t.rect(0, 0, a, i).fill({ color: G("url" in n && typeof n.url == "string" ? n.url : n.segmentType), alpha: Q(n) ? u : 0.35 }), t.pivot.set(a / 2, i / 2), t.position.set(a / 2, i / 2)), t.alpha = u;
|
|
30
|
+
const s = Re(n);
|
|
31
31
|
if (s) {
|
|
32
|
-
const [p,
|
|
33
|
-
t.position.set(a / 2 + p * a / 2, i / 2 -
|
|
32
|
+
const [p, I] = s.position ?? [0, 0], [v, y] = s.scale ?? [1, 1], h = s.rotation?.[2] ?? 0;
|
|
33
|
+
t.position.set(a / 2 + p * a / 2, i / 2 - I * i / 2), t.scale.set(v, y), t.rotation = h / 180 * Math.PI;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
function H(t, n) {
|
|
37
|
-
const a = new
|
|
38
|
-
return a.rect(0, 0, 10, 10).fill({ color:
|
|
37
|
+
const a = new B();
|
|
38
|
+
return a.rect(0, 0, 10, 10).fill({ color: G(n ?? t), alpha: 1 }), a;
|
|
39
39
|
}
|
|
40
|
-
function
|
|
40
|
+
function Se(t, n, a) {
|
|
41
41
|
const i = `<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${n}"><rect width="100%" height="100%" fill="#0f172a" fill-opacity="0.8"/></svg>`;
|
|
42
42
|
return `data:image/svg+xml;base64,${btoa(i)}`;
|
|
43
43
|
}
|
|
44
|
-
function
|
|
44
|
+
function G(t) {
|
|
45
45
|
let n = 0;
|
|
46
46
|
for (let a = 0; a < t.length; a++)
|
|
47
47
|
n = t.charCodeAt(a) + ((n << 5) - n);
|
|
48
48
|
return n & 16777215;
|
|
49
49
|
}
|
|
50
|
-
function
|
|
50
|
+
function z(t) {
|
|
51
51
|
const n = t.tracks.flatMap((a) => a.children.map((i) => i.endTime));
|
|
52
52
|
return n.length ? Math.max(...n) : 0;
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function J(t, n, a) {
|
|
55
55
|
return Math.min(Math.max(t, n), a);
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
const n =
|
|
57
|
+
function Y(t) {
|
|
58
|
+
const n = pe(t);
|
|
59
59
|
return JSON.parse(JSON.stringify(n));
|
|
60
60
|
}
|
|
61
|
-
function
|
|
61
|
+
function Q(t) {
|
|
62
62
|
return "opacity" in t;
|
|
63
63
|
}
|
|
64
|
-
function
|
|
65
|
-
return
|
|
64
|
+
function Ce(t) {
|
|
65
|
+
return Q(t) && typeof t.opacity == "number" ? t.opacity : 1;
|
|
66
66
|
}
|
|
67
|
-
function
|
|
67
|
+
function De(t) {
|
|
68
68
|
return "transform" in t;
|
|
69
69
|
}
|
|
70
|
-
function
|
|
71
|
-
if (
|
|
70
|
+
function Re(t) {
|
|
71
|
+
if (De(t))
|
|
72
72
|
return t.transform;
|
|
73
73
|
}
|
|
74
|
-
const
|
|
75
|
-
async function
|
|
76
|
-
const n =
|
|
77
|
-
n.verify(
|
|
78
|
-
), u = t.app ?? await
|
|
74
|
+
const Ae = "/video-editor-res";
|
|
75
|
+
async function $e(t) {
|
|
76
|
+
const n = le(), a = ve(t.protocol) ? t.protocol : q(t.protocol), i = q(
|
|
77
|
+
n.verify(Y(L(a)))
|
|
78
|
+
), u = t.app ?? await xe(t.appOptions), s = new Te();
|
|
79
79
|
u.stage.addChild(s);
|
|
80
|
-
const p =
|
|
81
|
-
let
|
|
82
|
-
async function
|
|
83
|
-
const { protocol: o, at: r, layer: c } = e, l =
|
|
84
|
-
for (const { segment:
|
|
85
|
-
const P = await e.getDisplay(
|
|
86
|
-
P && (
|
|
80
|
+
const p = de({ dir: t.resourceDir }), I = /* @__PURE__ */ new Set(), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Map(), f = W(0), T = W(!1), m = he(() => z(i.value));
|
|
81
|
+
let g, C = 0;
|
|
82
|
+
async function j(e) {
|
|
83
|
+
const { protocol: o, at: r, layer: c } = e, l = ie(o, r), x = ge(o, l), d = e.app.renderer.width, w = e.app.renderer.height, M = [];
|
|
84
|
+
for (const { segment: D } of x) {
|
|
85
|
+
const P = await e.getDisplay(D);
|
|
86
|
+
P && (Me(P, D, d, w), ae(D) && await oe(D, l), M.push(P));
|
|
87
87
|
}
|
|
88
88
|
c.removeChildren();
|
|
89
|
-
const S =
|
|
89
|
+
const S = M.filter(Boolean);
|
|
90
90
|
S.length && c.addChild(...S), e.app.render();
|
|
91
91
|
}
|
|
92
|
-
const O =
|
|
92
|
+
const O = Ee(() => j({
|
|
93
93
|
app: u,
|
|
94
94
|
layer: s,
|
|
95
95
|
protocol: i.value,
|
|
96
96
|
at: f.value,
|
|
97
|
-
getDisplay:
|
|
98
|
-
})),
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
() =>
|
|
97
|
+
getDisplay: ee
|
|
98
|
+
})), N = ye();
|
|
99
|
+
N.run(() => {
|
|
100
|
+
k(
|
|
101
|
+
() => L(a),
|
|
102
102
|
(e) => {
|
|
103
103
|
try {
|
|
104
|
-
i.value = n.verify(
|
|
104
|
+
i.value = n.verify(Y(e));
|
|
105
105
|
} catch (o) {
|
|
106
106
|
console.error("[renderer] invalid protocol update", o);
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
$(), K(i.value), X(i.value), A(), O();
|
|
110
110
|
},
|
|
111
111
|
{ deep: !0, immediate: !0 }
|
|
112
|
-
),
|
|
113
|
-
|
|
114
|
-
}),
|
|
112
|
+
), k(f, () => {
|
|
113
|
+
A(), O();
|
|
114
|
+
}), k(m, () => A());
|
|
115
115
|
});
|
|
116
|
-
function
|
|
117
|
-
const e =
|
|
116
|
+
function A() {
|
|
117
|
+
const e = m.value;
|
|
118
118
|
e <= 0 ? f.value = 0 : f.value > e ? f.value = e : f.value < 0 && (f.value = 0);
|
|
119
119
|
}
|
|
120
|
-
function
|
|
121
|
-
for (const o of
|
|
122
|
-
|
|
120
|
+
function K(e) {
|
|
121
|
+
for (const o of Ie(e))
|
|
122
|
+
I.has(o) || (I.add(o), p.add(o).catch(() => {
|
|
123
123
|
}));
|
|
124
124
|
}
|
|
125
|
-
function
|
|
125
|
+
function X(e) {
|
|
126
126
|
const o = new Set(e.tracks.flatMap((r) => r.children.map((c) => c.id)));
|
|
127
127
|
for (const [r, c] of v)
|
|
128
128
|
o.has(r) || (c.destroy(), v.delete(r));
|
|
129
|
-
for (const [r, c] of
|
|
130
|
-
o.has(r) || (c.clip.destroy(),
|
|
129
|
+
for (const [r, c] of h)
|
|
130
|
+
o.has(r) || (c.clip.destroy(), h.delete(r));
|
|
131
131
|
}
|
|
132
|
-
function
|
|
132
|
+
function $() {
|
|
133
133
|
s.removeChildren();
|
|
134
134
|
for (const e of v.values())
|
|
135
135
|
e.destroy();
|
|
136
|
-
v.clear(),
|
|
137
|
-
for (const { clip: e } of
|
|
136
|
+
v.clear(), y.clear();
|
|
137
|
+
for (const { clip: e } of h.values())
|
|
138
138
|
e.destroy();
|
|
139
|
-
|
|
139
|
+
h.clear();
|
|
140
140
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
141
|
+
function U() {
|
|
142
|
+
T.value || (T.value = !0, C = performance.now(), g = requestAnimationFrame(V));
|
|
143
143
|
}
|
|
144
144
|
function E() {
|
|
145
|
-
|
|
145
|
+
T.value = !1, g !== void 0 && cancelAnimationFrame(g), g = void 0;
|
|
146
146
|
}
|
|
147
|
-
function
|
|
148
|
-
|
|
147
|
+
function V() {
|
|
148
|
+
b(), T.value && (g = requestAnimationFrame(V));
|
|
149
149
|
}
|
|
150
|
-
function
|
|
151
|
-
if (!
|
|
150
|
+
function b(e) {
|
|
151
|
+
if (!T.value && e === void 0)
|
|
152
152
|
return;
|
|
153
153
|
const o = performance.now(), r = e ?? (C ? o - C : 0);
|
|
154
|
-
C = o, r !== 0 && (f.value =
|
|
154
|
+
C = o, r !== 0 && (f.value = J(
|
|
155
155
|
f.value + r,
|
|
156
156
|
0,
|
|
157
|
-
|
|
158
|
-
),
|
|
157
|
+
m.value || Number.POSITIVE_INFINITY
|
|
158
|
+
), m.value > 0 && f.value >= m.value && E());
|
|
159
159
|
}
|
|
160
|
-
function
|
|
161
|
-
f.value =
|
|
160
|
+
function Z(e) {
|
|
161
|
+
f.value = J(e, 0, m.value || Number.POSITIVE_INFINITY);
|
|
162
162
|
}
|
|
163
|
-
async function
|
|
163
|
+
async function ee(e) {
|
|
164
164
|
const o = v.get(e.id);
|
|
165
165
|
if (o)
|
|
166
166
|
return o;
|
|
167
|
-
const r =
|
|
167
|
+
const r = y.get(e.id);
|
|
168
168
|
if (r)
|
|
169
169
|
return r;
|
|
170
|
-
const c =
|
|
171
|
-
|
|
170
|
+
const c = te(e);
|
|
171
|
+
y.set(e.id, c);
|
|
172
172
|
const l = await c;
|
|
173
|
-
return l && v.set(e.id, l),
|
|
173
|
+
return l && v.set(e.id, l), y.delete(e.id), l;
|
|
174
174
|
}
|
|
175
|
-
async function
|
|
176
|
-
if (e.segmentType === "frames" || e.segmentType === "
|
|
175
|
+
async function te(e) {
|
|
176
|
+
if (e.segmentType === "frames" || e.segmentType === "sticker") {
|
|
177
177
|
if (!e.url)
|
|
178
178
|
return H(e.segmentType);
|
|
179
179
|
if ("type" in e && e.type === "video") {
|
|
180
|
-
const r = await
|
|
180
|
+
const r = await ne(e);
|
|
181
181
|
if (r)
|
|
182
182
|
return r;
|
|
183
183
|
}
|
|
184
|
-
const o = await
|
|
184
|
+
const o = await re(e.url);
|
|
185
185
|
return o ? new F(o) : H(e.segmentType, e.url);
|
|
186
186
|
}
|
|
187
187
|
e.segmentType !== "text" && (e.segmentType === "effect" || e.segmentType);
|
|
188
188
|
}
|
|
189
|
-
async function
|
|
189
|
+
async function re(e) {
|
|
190
190
|
const o = e.startsWith("data:"), r = /^https?:\/\//.test(e);
|
|
191
191
|
if (!o && !r)
|
|
192
192
|
try {
|
|
193
193
|
await p.add(e);
|
|
194
194
|
const c = await p.get(e);
|
|
195
195
|
if (c instanceof HTMLImageElement)
|
|
196
|
-
return
|
|
196
|
+
return R.from(c);
|
|
197
197
|
} catch {
|
|
198
198
|
}
|
|
199
|
-
return await
|
|
199
|
+
return await se(e);
|
|
200
200
|
}
|
|
201
|
-
async function
|
|
202
|
-
const o =
|
|
201
|
+
async function ne(e) {
|
|
202
|
+
const o = h.get(e.id);
|
|
203
203
|
if (o)
|
|
204
204
|
return o.sprite;
|
|
205
205
|
let r;
|
|
206
206
|
try {
|
|
207
|
-
await p.add(e.url), r = await
|
|
207
|
+
await p.add(e.url), r = await ce(e.url);
|
|
208
208
|
} catch {
|
|
209
209
|
r = void 0;
|
|
210
210
|
}
|
|
@@ -213,10 +213,10 @@ async function ke(t) {
|
|
|
213
213
|
if (r)
|
|
214
214
|
c = new _(r);
|
|
215
215
|
else {
|
|
216
|
-
const
|
|
217
|
-
if (!
|
|
216
|
+
const S = await fetch(e.url);
|
|
217
|
+
if (!S.body)
|
|
218
218
|
return;
|
|
219
|
-
c = new _(
|
|
219
|
+
c = new _(S.body);
|
|
220
220
|
}
|
|
221
221
|
} catch {
|
|
222
222
|
return;
|
|
@@ -227,46 +227,55 @@ async function ke(t) {
|
|
|
227
227
|
c.destroy();
|
|
228
228
|
return;
|
|
229
229
|
}
|
|
230
|
-
const { width: l, height:
|
|
231
|
-
d.width = l || 1, d.height =
|
|
232
|
-
const
|
|
233
|
-
return
|
|
230
|
+
const { width: l, height: x } = c.meta, d = document.createElement("canvas");
|
|
231
|
+
d.width = l || 1, d.height = x || 1;
|
|
232
|
+
const w = R.from(d), M = new F(w);
|
|
233
|
+
return h.set(e.id, { clip: c, canvas: d, texture: w, sprite: M, meta: { width: l, height: x } }), M;
|
|
234
234
|
}
|
|
235
|
-
async function
|
|
236
|
-
const r =
|
|
235
|
+
async function oe(e, o) {
|
|
236
|
+
const r = h.get(e.id);
|
|
237
237
|
if (r)
|
|
238
238
|
try {
|
|
239
|
-
const c = e.fromTime ?? 0, l = Math.max(0, o - e.startTime + c),
|
|
239
|
+
const c = e.fromTime ?? 0, l = Math.max(0, o - e.startTime + c), x = Math.floor(l * 1e3), d = await r.clip.tick(x);
|
|
240
240
|
if (d.video) {
|
|
241
|
-
const
|
|
242
|
-
|
|
241
|
+
const w = r.canvas.getContext("2d");
|
|
242
|
+
w && (w.drawImage(d.video, 0, 0, r.canvas.width, r.canvas.height), ue(r.texture)), d.video.close();
|
|
243
243
|
}
|
|
244
244
|
} catch (c) {
|
|
245
245
|
console.warn("[renderer] update video frame failed", c);
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
|
-
function
|
|
248
|
+
function ae(e) {
|
|
249
249
|
return e.segmentType === "frames" && e.type === "video" && typeof e.url == "string";
|
|
250
250
|
}
|
|
251
|
-
|
|
252
|
-
const
|
|
251
|
+
function ie(e, o) {
|
|
252
|
+
const r = z(e);
|
|
253
|
+
if (r <= 0)
|
|
254
|
+
return 0;
|
|
255
|
+
if (o < r)
|
|
256
|
+
return o;
|
|
257
|
+
const c = Math.max(1e3 / Math.max(e.fps || 30, 1), 1);
|
|
258
|
+
return Math.max(r - c, 0);
|
|
259
|
+
}
|
|
260
|
+
async function ce(e) {
|
|
261
|
+
const o = t.resourceDir ?? Ae;
|
|
253
262
|
try {
|
|
254
|
-
const r =
|
|
263
|
+
const r = me(`${o}/${e}`);
|
|
255
264
|
if (await r.exists())
|
|
256
265
|
return r;
|
|
257
266
|
} catch {
|
|
258
267
|
return;
|
|
259
268
|
}
|
|
260
269
|
}
|
|
261
|
-
function
|
|
270
|
+
function se(e) {
|
|
262
271
|
return new Promise((o) => {
|
|
263
272
|
const r = new Image();
|
|
264
|
-
r.crossOrigin = "anonymous", r.onload = () => o(
|
|
273
|
+
r.crossOrigin = "anonymous", r.onload = () => o(R.from(r)), r.onerror = () => {
|
|
265
274
|
console.warn("[renderer] failed to load image", e), o(void 0);
|
|
266
275
|
}, r.src = e;
|
|
267
276
|
});
|
|
268
277
|
}
|
|
269
|
-
function
|
|
278
|
+
function ue(e) {
|
|
270
279
|
const o = e.source;
|
|
271
280
|
if ("update" in o && typeof o.update == "function") {
|
|
272
281
|
o.update();
|
|
@@ -274,23 +283,23 @@ async function ke(t) {
|
|
|
274
283
|
}
|
|
275
284
|
typeof e.update == "function" && e.update();
|
|
276
285
|
}
|
|
277
|
-
function
|
|
278
|
-
E(),
|
|
286
|
+
function fe() {
|
|
287
|
+
E(), N.stop(), $(), s.destroy({ children: !0 }), v.clear(), y.clear(), I.clear(), t.app || u.destroy();
|
|
279
288
|
}
|
|
280
|
-
return t.autoPlay &&
|
|
289
|
+
return t.autoPlay && U(), {
|
|
281
290
|
app: u,
|
|
282
291
|
layer: s,
|
|
283
292
|
currentTime: f,
|
|
284
|
-
duration:
|
|
285
|
-
isPlaying:
|
|
286
|
-
play:
|
|
293
|
+
duration: m,
|
|
294
|
+
isPlaying: T,
|
|
295
|
+
play: U,
|
|
287
296
|
pause: E,
|
|
288
|
-
tick:
|
|
289
|
-
seek:
|
|
290
|
-
destroy:
|
|
297
|
+
tick: b,
|
|
298
|
+
seek: Z,
|
|
299
|
+
destroy: fe
|
|
291
300
|
};
|
|
292
301
|
}
|
|
293
|
-
function
|
|
302
|
+
function Ee(t) {
|
|
294
303
|
let n = !1, a = !1;
|
|
295
304
|
return async () => {
|
|
296
305
|
if (a) {
|
|
@@ -305,6 +314,6 @@ function Re(t) {
|
|
|
305
314
|
};
|
|
306
315
|
}
|
|
307
316
|
export {
|
|
308
|
-
|
|
317
|
+
$e as createRenderer
|
|
309
318
|
};
|
|
310
319
|
//# 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 active = collectActiveSegments(protocol, at)\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, at)\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 === 'image') {\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 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","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","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 } 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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"}
|
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.7",
|
|
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/
|
|
25
|
-
"@video-editor/
|
|
24
|
+
"@video-editor/protocol": "0.0.1-beta.7",
|
|
25
|
+
"@video-editor/shared": "0.0.1-beta.7"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "vite build",
|