@pixerate/editor 0.115.0 → 0.116.0
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/THIRD_PARTY_NOTICES.md +3 -0
- package/dist/animation-editor/index.cjs +54 -54
- package/dist/animation-editor/index.d.cts +2 -2
- package/dist/animation-editor/index.d.ts +2 -2
- package/dist/animation-editor/index.js +2 -2
- package/dist/{chunk-DFQEX3AM.cjs → chunk-2UT4GXYA.cjs} +133 -8
- package/dist/chunk-2UT4GXYA.cjs.map +1 -0
- package/dist/{chunk-VXR7XWMF.js → chunk-7LNZAWSJ.js} +437 -41
- package/dist/chunk-7LNZAWSJ.js.map +1 -0
- package/dist/{chunk-LKCYANMW.js → chunk-ARQ7PQ6Q.js} +129 -4
- package/dist/chunk-ARQ7PQ6Q.js.map +1 -0
- package/dist/chunk-COAMRKVI.cjs +159 -0
- package/dist/chunk-COAMRKVI.cjs.map +1 -0
- package/dist/{chunk-C6C5PDKU.js → chunk-D53KSJUV.js} +3 -322
- package/dist/chunk-D53KSJUV.js.map +1 -0
- package/dist/chunk-D53VQGEJ.js +3262 -0
- package/dist/chunk-D53VQGEJ.js.map +1 -0
- package/dist/chunk-EJVDBITD.cjs +501 -0
- package/dist/chunk-EJVDBITD.cjs.map +1 -0
- package/dist/{chunk-LPLCWZTM.cjs → chunk-FODKPD44.cjs} +555 -159
- package/dist/chunk-FODKPD44.cjs.map +1 -0
- package/dist/chunk-HOCPSFGA.cjs +3262 -0
- package/dist/chunk-HOCPSFGA.cjs.map +1 -0
- package/dist/chunk-IPFRWILU.js +1908 -0
- package/dist/chunk-IPFRWILU.js.map +1 -0
- package/dist/{chunk-FV5AXTSF.cjs → chunk-JSSBHMMU.cjs} +36 -188
- package/dist/chunk-JSSBHMMU.cjs.map +1 -0
- package/dist/chunk-LF4WOZXZ.js +159 -0
- package/dist/chunk-LF4WOZXZ.js.map +1 -0
- package/dist/{chunk-26PGXHY7.cjs → chunk-M7O4BJRH.cjs} +36 -36
- package/dist/{chunk-26PGXHY7.cjs.map → chunk-M7O4BJRH.cjs.map} +1 -1
- package/dist/chunk-N3467VD6.js +501 -0
- package/dist/chunk-N3467VD6.js.map +1 -0
- package/dist/{chunk-ST7E3NEE.cjs → chunk-PAOWHJ5O.cjs} +18 -337
- package/dist/chunk-PAOWHJ5O.cjs.map +1 -0
- package/dist/{chunk-XICA4PVO.js → chunk-SEBYNBHW.js} +10 -10
- package/dist/chunk-SMJGE7HM.cjs +1908 -0
- package/dist/chunk-SMJGE7HM.cjs.map +1 -0
- package/dist/{chunk-MMVHBKMM.js → chunk-T2P5TIZ6.js} +2 -2
- package/dist/{chunk-FGW5OWJ4.js → chunk-VJUML33I.js} +4 -156
- package/dist/chunk-VJUML33I.js.map +1 -0
- package/dist/{chunk-I7FQBWMQ.cjs → chunk-ZYZGEILO.cjs} +239 -239
- package/dist/{chunk-I7FQBWMQ.cjs.map → chunk-ZYZGEILO.cjs.map} +1 -1
- package/dist/export/index.cjs +4 -2
- package/dist/export/index.cjs.map +1 -1
- package/dist/export/index.js +5 -3
- package/dist/{export-BJE8T0YA.d.cts → export-BXxSGBCq.d.cts} +2 -2
- package/dist/{export-Con3UKkm.d.ts → export-Dm44YUvS.d.ts} +2 -2
- package/dist/export-Dv0-ZVrV.d.cts +501 -0
- package/dist/export-Dv0-ZVrV.d.ts +501 -0
- package/dist/{retouch-Do6tBs2H.d.ts → flow-BMtHAmg4.d.ts} +561 -2
- package/dist/{retouch-Bxkuc0KH.d.cts → flow-COCB42TP.d.cts} +561 -2
- package/dist/image-editor/index.cjs +957 -795
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +6 -6
- package/dist/image-editor/index.d.ts +6 -6
- package/dist/image-editor/index.js +180 -18
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/kernel-wasm-WYCGNZR4.js +10 -0
- package/dist/kernel-wasm-WYCGNZR4.js.map +1 -0
- package/dist/kernel-wasm-YPVAEMVN.cjs +10 -0
- package/dist/kernel-wasm-YPVAEMVN.cjs.map +1 -0
- package/dist/paint/index.cjs +165 -3
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +225 -3
- package/dist/paint/index.d.ts +225 -3
- package/dist/paint/index.js +166 -4
- package/dist/paint-editor/index.cjs +4690 -845
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +1525 -277
- package/dist/paint-editor/index.d.ts +1525 -277
- package/dist/paint-editor/index.js +4560 -715
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/raster/index.cjs +4 -3
- package/dist/raster/index.cjs.map +1 -1
- package/dist/raster/index.js +10 -9
- package/dist/{svg-BnRj0q8i.d.cts → svg-CVdFc80-.d.cts} +2 -2
- package/dist/{svg-CmmBFfGT.d.ts → svg-DlEuhwoX.d.ts} +2 -2
- package/dist/{types-1SUQKDAw.d.ts → types-CDLGhAZp.d.ts} +40 -2
- package/dist/{types-yINF17Ta.d.cts → types-Tfly4Aya.d.cts} +40 -2
- package/dist/vector/index.cjs +1897 -975
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +292 -32
- package/dist/vector/index.d.ts +292 -32
- package/dist/vector/index.js +928 -6
- package/dist/vector/index.js.map +1 -1
- package/dist/video-editor/index.cjs +502 -2165
- package/dist/video-editor/index.cjs.map +1 -1
- package/dist/video-editor/index.d.cts +3 -501
- package/dist/video-editor/index.d.ts +3 -501
- package/dist/video-editor/index.js +151 -1814
- package/dist/video-editor/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/references/photoshop-files.md +7 -3
- package/skills/pixerate-vector/SKILL.md +3 -0
- package/dist/chunk-C6C5PDKU.js.map +0 -1
- package/dist/chunk-DFQEX3AM.cjs.map +0 -1
- package/dist/chunk-FGW5OWJ4.js.map +0 -1
- package/dist/chunk-FV5AXTSF.cjs.map +0 -1
- package/dist/chunk-GX332W2C.js +0 -181
- package/dist/chunk-GX332W2C.js.map +0 -1
- package/dist/chunk-LKCYANMW.js.map +0 -1
- package/dist/chunk-LPLCWZTM.cjs.map +0 -1
- package/dist/chunk-MUUXNRU4.cjs +0 -181
- package/dist/chunk-MUUXNRU4.cjs.map +0 -1
- package/dist/chunk-ST7E3NEE.cjs.map +0 -1
- package/dist/chunk-TCKIXI46.cjs +0 -1136
- package/dist/chunk-TCKIXI46.cjs.map +0 -1
- package/dist/chunk-UBIXVXPR.js +0 -1136
- package/dist/chunk-UBIXVXPR.js.map +0 -1
- package/dist/chunk-VXR7XWMF.js.map +0 -1
- /package/dist/{chunk-XICA4PVO.js.map → chunk-SEBYNBHW.js.map} +0 -0
- /package/dist/{chunk-MMVHBKMM.js.map → chunk-T2P5TIZ6.js.map} +0 -0
|
@@ -1,4 +1,126 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6;
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
var _chunkSMJGE7HMcjs = require('../chunk-SMJGE7HM.cjs');
|
|
123
|
+
|
|
2
124
|
|
|
3
125
|
var _chunkWAJQKWQUcjs = require('../chunk-WAJQKWQU.cjs');
|
|
4
126
|
|
|
@@ -11,708 +133,6 @@ require('../chunk-2FHLHZAL.cjs');
|
|
|
11
133
|
require('../chunk-MR3Z4OQI.cjs');
|
|
12
134
|
require('../chunk-A6PHCAGX.cjs');
|
|
13
135
|
|
|
14
|
-
// src/video-editor/types.ts
|
|
15
|
-
var VIDEO_FITS = ["contain", "cover", "fill", "none"];
|
|
16
|
-
var VIDEO_TRANSITION_TYPES = ["crossfade", "dip", "wipe", "push", "slide", "iris"];
|
|
17
|
-
var VIDEO_WIPE_DIRECTIONS = ["left", "right", "up", "down"];
|
|
18
|
-
var videoTransitionAudioCurve = (t) => _nullishCoalesce(t.audioCurve, () => ( (t.type === "dip" ? "linear" : "equal-power")));
|
|
19
|
-
var VIDEO_BLEND_MODES = ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "add"];
|
|
20
|
-
var VIDEO_CLIP_ANIMATION_EFFECTS = ["fade", "rise", "drop", "slide-left", "slide-right", "zoom", "pop"];
|
|
21
|
-
var VIDEO_FADE_CURVES = ["linear", "equal-power", "s-curve", "exponential", "logarithmic"];
|
|
22
|
-
var VIDEO_PLACEMENT_MODES = ["refuse", "overwrite", "insert"];
|
|
23
|
-
var VIDEO_CLIP_TYPES = ["media", "text", "color", "sequence"];
|
|
24
|
-
|
|
25
|
-
// src/video-editor/keyframes.ts
|
|
26
|
-
var VIDEO_EASE_NAMES = ["linear", "hold", "ease-in", "ease-out", "ease-in-out"];
|
|
27
|
-
var VIDEO_KEYFRAME_PROPERTIES = ["opacity", "volume", "x", "y", "scale", "rotation"];
|
|
28
|
-
var VIDEO_TRANSFORM_PROPERTIES = ["x", "y", "scale", "rotation"];
|
|
29
|
-
var VIDEO_KEYFRAME_LIMITS = {
|
|
30
|
-
opacity: { default: 1, min: 0, max: 1 },
|
|
31
|
-
volume: { default: 1, min: 0, max: 4 },
|
|
32
|
-
x: { default: 0 },
|
|
33
|
-
y: { default: 0 },
|
|
34
|
-
scale: { default: 1, min: 0 },
|
|
35
|
-
rotation: { default: 0 }
|
|
36
|
-
};
|
|
37
|
-
var NAMED = {
|
|
38
|
-
"ease-in": [0.42, 0, 1, 1],
|
|
39
|
-
"ease-out": [0, 0, 0.58, 1],
|
|
40
|
-
"ease-in-out": [0.42, 0, 0.58, 1]
|
|
41
|
-
};
|
|
42
|
-
var isVideoKeyframes = (v) => typeof v === "object" && v !== null && Array.isArray(v.keys);
|
|
43
|
-
function videoEaseBezier(ease) {
|
|
44
|
-
if (ease === void 0 || ease === "linear" || ease === "hold") return null;
|
|
45
|
-
return Array.isArray(ease) ? ease : NAMED[ease];
|
|
46
|
-
}
|
|
47
|
-
var bez = (a, b, s) => 3 * a * (1 - s) * (1 - s) * s + 3 * b * (1 - s) * s * s + s * s * s;
|
|
48
|
-
var bezSlope = (a, b, s) => 3 * a * (1 - s) * (1 - s) + 6 * (b - a) * (1 - s) * s + 3 * (1 - b) * s * s;
|
|
49
|
-
function bezierParam(x1, x2, x) {
|
|
50
|
-
let s = x;
|
|
51
|
-
for (let i = 0; i < 8; i++) {
|
|
52
|
-
const err = bez(x1, x2, s) - x;
|
|
53
|
-
if (Math.abs(err) < 1e-7) return s;
|
|
54
|
-
const d = bezSlope(x1, x2, s);
|
|
55
|
-
if (Math.abs(d) < 1e-6) break;
|
|
56
|
-
s -= err / d;
|
|
57
|
-
if (s < 0 || s > 1) break;
|
|
58
|
-
}
|
|
59
|
-
let lo = 0;
|
|
60
|
-
let hi = 1;
|
|
61
|
-
s = x;
|
|
62
|
-
for (let i = 0; i < 60; i++) {
|
|
63
|
-
const v = bez(x1, x2, s);
|
|
64
|
-
if (Math.abs(v - x) < 1e-9) break;
|
|
65
|
-
if (v < x) lo = s;
|
|
66
|
-
else hi = s;
|
|
67
|
-
s = (lo + hi) / 2;
|
|
68
|
-
}
|
|
69
|
-
return s;
|
|
70
|
-
}
|
|
71
|
-
function videoEaseProgress(ease, p) {
|
|
72
|
-
if (p <= 0) return 0;
|
|
73
|
-
if (p >= 1) return ease === "hold" ? 0 : 1;
|
|
74
|
-
if (ease === "hold") return 0;
|
|
75
|
-
const b = videoEaseBezier(ease);
|
|
76
|
-
if (!b) return p;
|
|
77
|
-
return bez(b[1], b[3], bezierParam(b[0], b[2], p));
|
|
78
|
-
}
|
|
79
|
-
function keyBefore(keys, t) {
|
|
80
|
-
let lo = 0;
|
|
81
|
-
let hi = keys.length - 1;
|
|
82
|
-
if (t < keys[0].t) return -1;
|
|
83
|
-
while (lo < hi) {
|
|
84
|
-
const mid = lo + hi + 1 >> 1;
|
|
85
|
-
if (keys[mid].t <= t) lo = mid;
|
|
86
|
-
else hi = mid - 1;
|
|
87
|
-
}
|
|
88
|
-
return lo;
|
|
89
|
-
}
|
|
90
|
-
function videoValueAt(prop, clipTime, fallback = 0) {
|
|
91
|
-
if (prop === void 0) return fallback;
|
|
92
|
-
if (typeof prop === "number") return prop;
|
|
93
|
-
const { keys } = prop;
|
|
94
|
-
if (!keys.length) return fallback;
|
|
95
|
-
const i = keyBefore(keys, clipTime);
|
|
96
|
-
if (i < 0) return keys[0].v;
|
|
97
|
-
if (i >= keys.length - 1) return keys[keys.length - 1].v;
|
|
98
|
-
const a = keys[i];
|
|
99
|
-
const b = keys[i + 1];
|
|
100
|
-
if (a.ease === "hold") return a.v;
|
|
101
|
-
return a.v + (b.v - a.v) * videoEaseProgress(a.ease, (clipTime - a.t) / (b.t - a.t));
|
|
102
|
-
}
|
|
103
|
-
var videoKeysOf = (prop) => isVideoKeyframes(prop) ? prop.keys : [];
|
|
104
|
-
function retimeVideoAnimatable(prop, dt, k = 1) {
|
|
105
|
-
if (!isVideoKeyframes(prop)) return prop;
|
|
106
|
-
return { keys: prop.keys.map((key) => ({ ...key, t: key.t * k + dt })) };
|
|
107
|
-
}
|
|
108
|
-
function splitEase(ease, p) {
|
|
109
|
-
if (ease === "hold") return ["hold", "hold"];
|
|
110
|
-
const b = videoEaseBezier(ease);
|
|
111
|
-
if (!b) return [ease, ease];
|
|
112
|
-
const s = bezierParam(b[0], b[2], p);
|
|
113
|
-
const lerp = (u, v, k) => [u[0] + (v[0] - u[0]) * k, u[1] + (v[1] - u[1]) * k];
|
|
114
|
-
const P0 = [0, 0];
|
|
115
|
-
const P1 = [b[0], b[1]];
|
|
116
|
-
const P2 = [b[2], b[3]];
|
|
117
|
-
const P3 = [1, 1];
|
|
118
|
-
const A = lerp(P0, P1, s);
|
|
119
|
-
const B = lerp(P1, P2, s);
|
|
120
|
-
const C = lerp(P2, P3, s);
|
|
121
|
-
const AB = lerp(A, B, s);
|
|
122
|
-
const BC = lerp(B, C, s);
|
|
123
|
-
const M = lerp(AB, BC, s);
|
|
124
|
-
const r = (v) => Math.round(v * 1e6) / 1e6;
|
|
125
|
-
const left = Math.abs(M[1]) < 1e-9 ? "linear" : [r(A[0] / M[0]), r(A[1] / M[1]), r(AB[0] / M[0]), r(AB[1] / M[1])];
|
|
126
|
-
const dx = 1 - M[0];
|
|
127
|
-
const dy = 1 - M[1];
|
|
128
|
-
const right = Math.abs(dy) < 1e-9 ? "linear" : [r((BC[0] - M[0]) / dx), r((BC[1] - M[1]) / dy), r((C[0] - M[0]) / dx), r((C[1] - M[1]) / dy)];
|
|
129
|
-
return [left, right];
|
|
130
|
-
}
|
|
131
|
-
function splitVideoAnimatable(prop, at) {
|
|
132
|
-
if (!isVideoKeyframes(prop)) return [prop, prop];
|
|
133
|
-
const keys = prop.keys;
|
|
134
|
-
const eps = 1e-6;
|
|
135
|
-
const v = videoValueAt(prop, at);
|
|
136
|
-
const i = keyBefore(keys, at);
|
|
137
|
-
const exact = i >= 0 && Math.abs(keys[i].t - at) < eps;
|
|
138
|
-
let leftEase;
|
|
139
|
-
let rightEase;
|
|
140
|
-
if (exact) rightEase = keys[i].ease;
|
|
141
|
-
else if (i >= 0 && i < keys.length - 1) {
|
|
142
|
-
const a = keys[i];
|
|
143
|
-
[leftEase, rightEase] = splitEase(a.ease, (at - a.t) / (keys[i + 1].t - a.t));
|
|
144
|
-
}
|
|
145
|
-
const before = keys.slice(0, exact ? i : i + 1).map((k) => ({ ...k }));
|
|
146
|
-
if (before.length && leftEase !== void 0) before[before.length - 1] = withEase(before[before.length - 1], leftEase);
|
|
147
|
-
const left = [...before, { t: at, v }];
|
|
148
|
-
const right = [withEase({ t: 0, v }, rightEase), ...keys.slice(i + 1).map((k) => ({ ...k, t: k.t - at }))];
|
|
149
|
-
return [{ keys: left }, { keys: right }];
|
|
150
|
-
}
|
|
151
|
-
var withEase = (key, ease) => {
|
|
152
|
-
const { ease: _old, ...rest } = key;
|
|
153
|
-
return ease === void 0 || ease === "linear" ? rest : { ...rest, ease };
|
|
154
|
-
};
|
|
155
|
-
function sortVideoKeys(keys) {
|
|
156
|
-
const sorted = [...keys].sort((a, b) => a.t - b.t);
|
|
157
|
-
for (let i = 1; i < sorted.length; i++) if (Math.abs(sorted[i].t - sorted[i - 1].t) < 1e-6) throw new Error(`Two keys are at ${sorted[i].t} ms; give each key its own time.`);
|
|
158
|
-
return sorted;
|
|
159
|
-
}
|
|
160
|
-
function setVideoKey(prop, key, fallback) {
|
|
161
|
-
const keys = isVideoKeyframes(prop) ? prop.keys.filter((k) => Math.abs(k.t - key.t) >= 1e-6) : [];
|
|
162
|
-
if (!isVideoKeyframes(prop)) {
|
|
163
|
-
const v = _nullishCoalesce(prop, () => ( fallback));
|
|
164
|
-
if (key.t !== 0) keys.push({ t: 0, v });
|
|
165
|
-
}
|
|
166
|
-
return { keys: sortVideoKeys([...keys, key]) };
|
|
167
|
-
}
|
|
168
|
-
function removeVideoKey(prop, t) {
|
|
169
|
-
const keys = prop.keys.filter((k) => Math.abs(k.t - t) >= 1e-6);
|
|
170
|
-
return keys.length ? { keys } : prop.keys[0].v;
|
|
171
|
-
}
|
|
172
|
-
var fmt = (v) => {
|
|
173
|
-
const r = Math.round(v * 1e4) / 1e4;
|
|
174
|
-
return Object.is(r, -0) ? "0" : String(r);
|
|
175
|
-
};
|
|
176
|
-
var signed = (v) => fmt(v).startsWith("-") ? fmt(v) : `+${fmt(v)}`;
|
|
177
|
-
function videoKeyframeBreakpoints(prop, step) {
|
|
178
|
-
const { keys } = prop;
|
|
179
|
-
const points = [];
|
|
180
|
-
const holds = /* @__PURE__ */ new Set();
|
|
181
|
-
for (let i = 0; i < keys.length; i++) {
|
|
182
|
-
const a = keys[i];
|
|
183
|
-
points.push([a.t, a.v]);
|
|
184
|
-
const b = keys[i + 1];
|
|
185
|
-
if (!b) break;
|
|
186
|
-
if (a.ease === "hold") {
|
|
187
|
-
holds.add(points.length - 1);
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
if (!videoEaseBezier(a.ease)) continue;
|
|
191
|
-
const n2 = Math.max(1, Math.ceil((b.t - a.t) / step));
|
|
192
|
-
for (let k = 1; k < n2; k++) {
|
|
193
|
-
const t = a.t + (b.t - a.t) * k / n2;
|
|
194
|
-
points.push([t, videoValueAt(prop, t)]);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return { points, holds };
|
|
198
|
-
}
|
|
199
|
-
function videoKeyframeFfmpegExpr(prop, time, fallback, step) {
|
|
200
|
-
if (!isVideoKeyframes(prop)) return fmt(_nullishCoalesce(prop, () => ( fallback)));
|
|
201
|
-
const { points, holds } = videoKeyframeBreakpoints(prop, step);
|
|
202
|
-
if (points.length === 1 || points.every(([, v]) => v === points[0][1])) return fmt(points[0][1]);
|
|
203
|
-
let expr = fmt(points[points.length - 1][1]);
|
|
204
|
-
for (let i = points.length - 2; i >= 0; i--) {
|
|
205
|
-
const [t0, v0] = points[i];
|
|
206
|
-
const [t1, v1] = points[i + 1];
|
|
207
|
-
const seg = holds.has(i) || v0 === v1 ? fmt(v0) : `${fmt(v0)}${signed((v1 - v0) / (t1 - t0))}*(${time}${signed(-t0)})`;
|
|
208
|
-
expr = `if(lt(${time},${fmt(t1)}),${seg},${expr})`;
|
|
209
|
-
}
|
|
210
|
-
return `if(lt(${time},${fmt(points[0][0])}),${fmt(points[0][1])},${expr})`;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// src/video-editor/lut.ts
|
|
214
|
-
var VIDEO_LUT_MAX_SIZE = 129;
|
|
215
|
-
function parseVideoCubeLut(text) {
|
|
216
|
-
let size = 0;
|
|
217
|
-
let size1 = 0;
|
|
218
|
-
let title;
|
|
219
|
-
const domainMin = [0, 0, 0];
|
|
220
|
-
const domainMax = [1, 1, 1];
|
|
221
|
-
let data = null;
|
|
222
|
-
let rows = 0;
|
|
223
|
-
const lines = text.split(/\r\n|\r|\n/);
|
|
224
|
-
const fail2 = (line, message) => {
|
|
225
|
-
throw new Error(`Line ${line + 1} of the .cube file: ${message}.`);
|
|
226
|
-
};
|
|
227
|
-
const numbers = (parts, line) => parts.map((p) => {
|
|
228
|
-
const v = Number(p);
|
|
229
|
-
if (!Number.isFinite(v)) fail2(line, `"${p}" is not a number`);
|
|
230
|
-
return v;
|
|
231
|
-
});
|
|
232
|
-
for (let i = 0; i < lines.length; i++) {
|
|
233
|
-
const line = lines[i].replace(/#.*/, "").trim();
|
|
234
|
-
if (!line) continue;
|
|
235
|
-
const parts = line.split(/\s+/);
|
|
236
|
-
const key = parts[0];
|
|
237
|
-
if (/^[A-Za-z]/.test(key)) {
|
|
238
|
-
if (rows) fail2(i, `"${key}" comes after the table; keywords go before it`);
|
|
239
|
-
if (key === "TITLE") title = line.slice(5).trim().replace(/^"|"$/g, "");
|
|
240
|
-
else if (key === "LUT_3D_SIZE") {
|
|
241
|
-
size = Number(parts[1]);
|
|
242
|
-
if (!Number.isInteger(size) || size < 2 || size > VIDEO_LUT_MAX_SIZE) fail2(i, `LUT_3D_SIZE must be a whole number from 2 to ${VIDEO_LUT_MAX_SIZE}, not "${_nullishCoalesce(parts[1], () => ( ""))}"`);
|
|
243
|
-
} else if (key === "LUT_1D_SIZE") size1 = Number(parts[1]) || 1;
|
|
244
|
-
else if (key === "DOMAIN_MIN" || key === "DOMAIN_MAX") {
|
|
245
|
-
const v2 = numbers(parts.slice(1), i);
|
|
246
|
-
if (v2.length !== 3) fail2(i, `${key} needs 3 numbers`);
|
|
247
|
-
(key === "DOMAIN_MIN" ? domainMin : domainMax).splice(0, 3, ...v2);
|
|
248
|
-
} else if (key === "LUT_3D_INPUT_RANGE") {
|
|
249
|
-
const v2 = numbers(parts.slice(1), i);
|
|
250
|
-
if (v2.length !== 2 || !(v2[1] > v2[0])) fail2(i, "LUT_3D_INPUT_RANGE needs a minimum and a larger maximum");
|
|
251
|
-
domainMin.fill(v2[0]);
|
|
252
|
-
domainMax.fill(v2[1]);
|
|
253
|
-
}
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
if (!size) fail2(i, size1 ? "this is a 1D LUT (LUT_1D_SIZE); only 3D LUTs (LUT_3D_SIZE) are supported" : "the table starts before LUT_3D_SIZE");
|
|
257
|
-
data ??= new Float32Array(size * size * size * 3);
|
|
258
|
-
const v = numbers(parts, i);
|
|
259
|
-
if (v.length !== 3) fail2(i, `a table row needs 3 numbers, not ${v.length}`);
|
|
260
|
-
if (rows >= size ** 3) fail2(i, `the table has more than the ${size ** 3} rows LUT_3D_SIZE ${size} needs`);
|
|
261
|
-
data.set(v, rows * 3);
|
|
262
|
-
rows++;
|
|
263
|
-
}
|
|
264
|
-
if (!size) throw new Error(size1 ? "The .cube file is a 1D LUT (LUT_1D_SIZE); only 3D LUTs (LUT_3D_SIZE) are supported." : "The .cube file has no LUT_3D_SIZE line, so it is not a 3D LUT.");
|
|
265
|
-
if (rows !== size ** 3) throw new Error(`The .cube file has ${rows} table rows; LUT_3D_SIZE ${size} needs ${size ** 3}.`);
|
|
266
|
-
for (let c = 0; c < 3; c++) if (!(domainMax[c] > domainMin[c])) throw new Error("The .cube file's DOMAIN_MAX must be larger than its DOMAIN_MIN on every channel.");
|
|
267
|
-
return { ...title ? { title } : {}, size, domainMin, domainMax, data };
|
|
268
|
-
}
|
|
269
|
-
function videoLutFromFunction(size, fn, title) {
|
|
270
|
-
const n2 = size - 1;
|
|
271
|
-
const data = new Float32Array(size ** 3 * 3);
|
|
272
|
-
let i = 0;
|
|
273
|
-
for (let b = 0; b < size; b++)
|
|
274
|
-
for (let g = 0; g < size; g++)
|
|
275
|
-
for (let r = 0; r < size; r++) {
|
|
276
|
-
data.set(fn([r / n2, g / n2, b / n2]), i);
|
|
277
|
-
i += 3;
|
|
278
|
-
}
|
|
279
|
-
return { ...title ? { title } : {}, size, domainMin: [0, 0, 0], domainMax: [1, 1, 1], data };
|
|
280
|
-
}
|
|
281
|
-
function videoLutToCube(lut) {
|
|
282
|
-
const f = (v) => (Math.round(v * 1e6) / 1e6).toString();
|
|
283
|
-
const head = [...lut.title ? [`TITLE "${lut.title.replace(/"/g, "'")}"`] : [], `LUT_3D_SIZE ${lut.size}`];
|
|
284
|
-
if (lut.domainMin.some((v) => v !== 0) || lut.domainMax.some((v) => v !== 1)) head.push(`DOMAIN_MIN ${lut.domainMin.map(f).join(" ")}`, `DOMAIN_MAX ${lut.domainMax.map(f).join(" ")}`);
|
|
285
|
-
const rows = [];
|
|
286
|
-
for (let i = 0; i < lut.data.length; i += 3) rows.push(`${f(lut.data[i])} ${f(lut.data[i + 1])} ${f(lut.data[i + 2])}`);
|
|
287
|
-
return `${head.join("\n")}
|
|
288
|
-
${rows.join("\n")}
|
|
289
|
-
`;
|
|
290
|
-
}
|
|
291
|
-
var clamp01 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
|
|
292
|
-
function applyVideoLut(lut, rgb, out = [0, 0, 0]) {
|
|
293
|
-
const { size, data, domainMin, domainMax } = lut;
|
|
294
|
-
const n2 = size - 1;
|
|
295
|
-
const x = clamp01((rgb[0] - domainMin[0]) / (domainMax[0] - domainMin[0])) * n2;
|
|
296
|
-
const y = clamp01((rgb[1] - domainMin[1]) / (domainMax[1] - domainMin[1])) * n2;
|
|
297
|
-
const z = clamp01((rgb[2] - domainMin[2]) / (domainMax[2] - domainMin[2])) * n2;
|
|
298
|
-
const r0 = Math.min(n2 - 1, Math.floor(x));
|
|
299
|
-
const g0 = Math.min(n2 - 1, Math.floor(y));
|
|
300
|
-
const b0 = Math.min(n2 - 1, Math.floor(z));
|
|
301
|
-
const fr = x - r0;
|
|
302
|
-
const fg = y - g0;
|
|
303
|
-
const fb = z - b0;
|
|
304
|
-
const sr = 3;
|
|
305
|
-
const sg = 3 * size;
|
|
306
|
-
const sb = 3 * size * size;
|
|
307
|
-
const o = r0 * sr + g0 * sg + b0 * sb;
|
|
308
|
-
let a, c, w0, w1, w2, w3;
|
|
309
|
-
if (fr > fg) {
|
|
310
|
-
if (fg > fb) [a, c, w0, w1, w2, w3] = [sr, sr + sg, 1 - fr, fr - fg, fg - fb, fb];
|
|
311
|
-
else if (fr > fb) [a, c, w0, w1, w2, w3] = [sr, sr + sb, 1 - fr, fr - fb, fb - fg, fg];
|
|
312
|
-
else [a, c, w0, w1, w2, w3] = [sb, sb + sr, 1 - fb, fb - fr, fr - fg, fg];
|
|
313
|
-
} else if (fb > fg) [a, c, w0, w1, w2, w3] = [sb, sb + sg, 1 - fb, fb - fg, fg - fr, fr];
|
|
314
|
-
else if (fb > fr) [a, c, w0, w1, w2, w3] = [sg, sg + sb, 1 - fg, fg - fb, fb - fr, fr];
|
|
315
|
-
else [a, c, w0, w1, w2, w3] = [sg, sg + sr, 1 - fg, fg - fr, fr - fb, fb];
|
|
316
|
-
const d = sr + sg + sb;
|
|
317
|
-
for (let k = 0; k < 3; k++) out[k] = clamp01(w0 * data[o + k] + w1 * data[o + a + k] + w2 * data[o + c + k] + w3 * data[o + d + k]);
|
|
318
|
-
return out;
|
|
319
|
-
}
|
|
320
|
-
function applyVideoLutToPixels(lut, data, strength = 1) {
|
|
321
|
-
const s = clamp01(strength);
|
|
322
|
-
if (!s) return;
|
|
323
|
-
const rgb = [0, 0, 0];
|
|
324
|
-
const out = [0, 0, 0];
|
|
325
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
326
|
-
if (!data[i + 3]) continue;
|
|
327
|
-
rgb[0] = data[i] / 255;
|
|
328
|
-
rgb[1] = data[i + 1] / 255;
|
|
329
|
-
rgb[2] = data[i + 2] / 255;
|
|
330
|
-
applyVideoLut(lut, rgb, out);
|
|
331
|
-
for (let k = 0; k < 3; k++) data[i + k] = Math.round((rgb[k] + (out[k] - rgb[k]) * s) * 255);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
var approximations = /* @__PURE__ */ new WeakMap();
|
|
335
|
-
function videoLutSvgApproximation(lut) {
|
|
336
|
-
const cached = approximations.get(lut);
|
|
337
|
-
if (cached) return cached;
|
|
338
|
-
const points = 17;
|
|
339
|
-
const tables = [[], [], []];
|
|
340
|
-
for (let i = 0; i < points; i++) {
|
|
341
|
-
const v = i / (points - 1);
|
|
342
|
-
const out = applyVideoLut(lut, [v, v, v]);
|
|
343
|
-
for (let k = 0; k < 3; k++) tables[k].push(out[k]);
|
|
344
|
-
}
|
|
345
|
-
const curve = (k, v) => {
|
|
346
|
-
const x = clamp01(v) * (points - 1);
|
|
347
|
-
const i = Math.min(points - 2, Math.floor(x));
|
|
348
|
-
return tables[k][i] + (tables[k][i + 1] - tables[k][i]) * (x - i);
|
|
349
|
-
};
|
|
350
|
-
const ata = Array.from({ length: 4 }, () => [0, 0, 0, 0]);
|
|
351
|
-
const atb = Array.from({ length: 3 }, () => [0, 0, 0, 0]);
|
|
352
|
-
const grid = 9;
|
|
353
|
-
for (let b = 0; b < grid; b++)
|
|
354
|
-
for (let g = 0; g < grid; g++)
|
|
355
|
-
for (let r = 0; r < grid; r++) {
|
|
356
|
-
const x = [r / (grid - 1), g / (grid - 1), b / (grid - 1)];
|
|
357
|
-
const z = [curve(0, x[0]), curve(1, x[1]), curve(2, x[2]), 1];
|
|
358
|
-
const y = applyVideoLut(lut, x);
|
|
359
|
-
for (let i = 0; i < 4; i++) {
|
|
360
|
-
for (let j = 0; j < 4; j++) ata[i][j] += z[i] * z[j];
|
|
361
|
-
for (let k = 0; k < 3; k++) atb[k][i] += z[i] * y[k];
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
const matrix = atb.map((rhs) => solve4(ata, rhs));
|
|
365
|
-
const result = { tables, matrix };
|
|
366
|
-
approximations.set(lut, result);
|
|
367
|
-
return result;
|
|
368
|
-
}
|
|
369
|
-
function solve4(a, b) {
|
|
370
|
-
const m = a.map((row, i) => [...row, b[i]]);
|
|
371
|
-
for (let col = 0; col < 4; col++) {
|
|
372
|
-
let pivot = col;
|
|
373
|
-
for (let r = col + 1; r < 4; r++) if (Math.abs(m[r][col]) > Math.abs(m[pivot][col])) pivot = r;
|
|
374
|
-
if (Math.abs(m[pivot][col]) < 1e-12) continue;
|
|
375
|
-
[m[col], m[pivot]] = [m[pivot], m[col]];
|
|
376
|
-
for (let r = 0; r < 4; r++) {
|
|
377
|
-
if (r === col) continue;
|
|
378
|
-
const f = m[r][col] / m[col][col];
|
|
379
|
-
for (let c = col; c < 5; c++) m[r][c] -= f * m[col][c];
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
return m.map((row, i) => Math.abs(row[i]) < 1e-12 ? 0 : row[4] / row[i]);
|
|
383
|
-
}
|
|
384
|
-
var VideoLutCache = (_class = class {
|
|
385
|
-
constructor(loader = async (src) => {
|
|
386
|
-
const res = await fetch(src);
|
|
387
|
-
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`.trim());
|
|
388
|
-
return res.text();
|
|
389
|
-
}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);
|
|
390
|
-
this.loader = loader;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
__init() {this.ready = /* @__PURE__ */ new Map()}
|
|
394
|
-
__init2() {this.pending = /* @__PURE__ */ new Map()}
|
|
395
|
-
__init3() {this.failed = /* @__PURE__ */ new Map()}
|
|
396
|
-
__init4() {this.listeners = /* @__PURE__ */ new Set()}
|
|
397
|
-
/** The LUT if loaded, without starting to load it. */
|
|
398
|
-
peek(src) {
|
|
399
|
-
return this.ready.get(src);
|
|
400
|
-
}
|
|
401
|
-
/** The LUT if loaded; otherwise `undefined`, and loading starts (once) unless it failed. */
|
|
402
|
-
get(src) {
|
|
403
|
-
const lut = this.ready.get(src);
|
|
404
|
-
if (!lut && !this.failed.has(src)) void this.load(src).catch(() => {
|
|
405
|
-
});
|
|
406
|
-
return lut;
|
|
407
|
-
}
|
|
408
|
-
/** Why loading a LUT failed, if it did. */
|
|
409
|
-
error(src) {
|
|
410
|
-
return this.failed.get(src);
|
|
411
|
-
}
|
|
412
|
-
/** The LUT, loading and reading it if needed. Rejects with a readable error. */
|
|
413
|
-
load(src) {
|
|
414
|
-
const ready = this.ready.get(src);
|
|
415
|
-
if (ready) return Promise.resolve(ready);
|
|
416
|
-
const failed = this.failed.get(src);
|
|
417
|
-
if (failed) return Promise.reject(new Error(failed));
|
|
418
|
-
let pending = this.pending.get(src);
|
|
419
|
-
if (!pending) {
|
|
420
|
-
pending = Promise.resolve().then(() => this.loader(src)).then((v) => typeof v === "string" ? parseVideoCubeLut(v) : v).then(
|
|
421
|
-
(lut) => {
|
|
422
|
-
this.pending.delete(src);
|
|
423
|
-
this.ready.set(src, lut);
|
|
424
|
-
this.emit();
|
|
425
|
-
return lut;
|
|
426
|
-
},
|
|
427
|
-
(e) => {
|
|
428
|
-
this.pending.delete(src);
|
|
429
|
-
const message = `The LUT "${src}" could not be read: ${e instanceof Error ? e.message : String(e)}`;
|
|
430
|
-
this.failed.set(src, message);
|
|
431
|
-
this.emit();
|
|
432
|
-
throw new Error(message);
|
|
433
|
-
}
|
|
434
|
-
);
|
|
435
|
-
this.pending.set(src, pending);
|
|
436
|
-
}
|
|
437
|
-
return pending;
|
|
438
|
-
}
|
|
439
|
-
/** Uses a LUT the host already has (`.cube` text or a parsed LUT), under `src`. */
|
|
440
|
-
set(src, lut) {
|
|
441
|
-
const parsed = typeof lut === "string" ? parseVideoCubeLut(lut) : lut;
|
|
442
|
-
this.ready.set(src, parsed);
|
|
443
|
-
this.failed.delete(src);
|
|
444
|
-
this.emit();
|
|
445
|
-
return parsed;
|
|
446
|
-
}
|
|
447
|
-
/** Forgets a failure so the next `get` tries again. */
|
|
448
|
-
retry(src) {
|
|
449
|
-
if (this.failed.delete(src)) this.emit();
|
|
450
|
-
}
|
|
451
|
-
subscribe(fn) {
|
|
452
|
-
this.listeners.add(fn);
|
|
453
|
-
return () => {
|
|
454
|
-
this.listeners.delete(fn);
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
emit() {
|
|
458
|
-
for (const l of [...this.listeners]) l();
|
|
459
|
-
}
|
|
460
|
-
}, _class);
|
|
461
|
-
|
|
462
|
-
// src/video-editor/grade.ts
|
|
463
|
-
var VIDEO_GRADE_CONTROLS = [
|
|
464
|
-
{ key: "exposure", label: "Exposure", min: -3, max: 3, step: 0.1, description: "Exposure in stops: +1 doubles every channel, -1 halves it (default 0)." },
|
|
465
|
-
{ key: "contrast", label: "Contrast", min: -1, max: 1, step: 0.05, description: "Contrast around mid grey, -1 (flat grey) to 1 (twice as steep); default 0." },
|
|
466
|
-
{ key: "saturation", label: "Saturation", min: -1, max: 1, step: 0.05, description: "Saturation, -1 (black and white) to 1 (twice as saturated); default 0." },
|
|
467
|
-
{ key: "hue", label: "Hue", min: -180, max: 180, step: 1, description: "Hue rotation in degrees (default 0)." },
|
|
468
|
-
{ key: "temperature", label: "Temperature", min: -1, max: 1, step: 0.05, description: "White balance, -1 (cool, bluer) to 1 (warm, more orange); default 0." },
|
|
469
|
-
{ key: "tint", label: "Tint", min: -1, max: 1, step: 0.05, description: "White balance, -1 (greener) to 1 (more magenta); default 0." }
|
|
470
|
-
];
|
|
471
|
-
var VIDEO_GRADE_PRESETS = {
|
|
472
|
-
warm: { temperature: 0.4, saturation: 0.1 },
|
|
473
|
-
cool: { temperature: -0.4, tint: -0.05 },
|
|
474
|
-
punchy: { contrast: 0.25, saturation: 0.3 },
|
|
475
|
-
faded: { exposure: 0.15, contrast: -0.3, saturation: -0.3 },
|
|
476
|
-
"black-and-white": { saturation: -1, contrast: 0.15 },
|
|
477
|
-
"bleach-bypass": { saturation: -0.6, contrast: 0.4 },
|
|
478
|
-
"day-for-night": { exposure: -1.5, saturation: -0.4, temperature: -0.6 }
|
|
479
|
-
};
|
|
480
|
-
var VIDEO_GRADE_PRESET_NAMES = Object.keys(VIDEO_GRADE_PRESETS);
|
|
481
|
-
var clampTo = (c, v) => Math.min(c.max, Math.max(c.min, v));
|
|
482
|
-
function normalizeVideoGradeLut(lut) {
|
|
483
|
-
if (!lut || typeof lut.src !== "string" || !lut.src) return void 0;
|
|
484
|
-
const strength = typeof lut.strength === "number" && Number.isFinite(lut.strength) ? Math.round(Math.min(1, Math.max(0, lut.strength)) * 1e3) / 1e3 : 1;
|
|
485
|
-
if (!strength) return void 0;
|
|
486
|
-
return { src: lut.src, ...strength !== 1 ? { strength } : {}, ...lut.name ? { name: lut.name } : {} };
|
|
487
|
-
}
|
|
488
|
-
function normalizeVideoGrade(grade) {
|
|
489
|
-
if (!grade) return void 0;
|
|
490
|
-
const out = {};
|
|
491
|
-
for (const c of VIDEO_GRADE_CONTROLS) {
|
|
492
|
-
const v = grade[c.key];
|
|
493
|
-
if (typeof v === "number" && Number.isFinite(v) && v !== 0) out[c.key] = Math.round(clampTo(c, v) * 1e3) / 1e3;
|
|
494
|
-
}
|
|
495
|
-
const lut = normalizeVideoGradeLut(grade.lut);
|
|
496
|
-
if (lut) out.lut = lut;
|
|
497
|
-
return Object.keys(out).length ? out : void 0;
|
|
498
|
-
}
|
|
499
|
-
function videoGradePreset(name, amount = 1) {
|
|
500
|
-
const preset = VIDEO_GRADE_PRESETS[name];
|
|
501
|
-
if (!preset) throw new Error(`There is no grade preset "${name}"; the presets are ${VIDEO_GRADE_PRESET_NAMES.join(", ")}.`);
|
|
502
|
-
const k = Math.min(1, Math.max(0, amount));
|
|
503
|
-
return normalizeVideoGrade(Object.fromEntries(Object.entries(preset).map(([key, v]) => [key, v * k])));
|
|
504
|
-
}
|
|
505
|
-
function videoGradeLook(current, name, amount = 1) {
|
|
506
|
-
return normalizeVideoGrade({ ...videoGradePreset(name, amount), ..._optionalChain([current, 'optionalAccess', _2 => _2.lut]) ? { lut: current.lut } : {} });
|
|
507
|
-
}
|
|
508
|
-
function videoGradeSteps(grade) {
|
|
509
|
-
const g = normalizeVideoGrade(grade);
|
|
510
|
-
if (!g) return [];
|
|
511
|
-
const steps = [];
|
|
512
|
-
if (g.exposure) steps.push({ kind: "brightness", amount: 2 ** g.exposure });
|
|
513
|
-
if (g.contrast) steps.push({ kind: "contrast", amount: 1 + g.contrast });
|
|
514
|
-
if (g.saturation) steps.push({ kind: "saturate", amount: 1 + g.saturation });
|
|
515
|
-
if (g.hue) steps.push({ kind: "hue-rotate", degrees: g.hue });
|
|
516
|
-
if (g.temperature || g.tint) {
|
|
517
|
-
const t = _nullishCoalesce(g.temperature, () => ( 0));
|
|
518
|
-
steps.push({ kind: "gains", r: 1 + 0.25 * t, g: 1 - 0.25 * (_nullishCoalesce(g.tint, () => ( 0))), b: 1 - 0.25 * t });
|
|
519
|
-
}
|
|
520
|
-
return steps;
|
|
521
|
-
}
|
|
522
|
-
function videoGradeStepMatrix(step) {
|
|
523
|
-
switch (step.kind) {
|
|
524
|
-
case "brightness":
|
|
525
|
-
return [
|
|
526
|
-
[step.amount, 0, 0, 0],
|
|
527
|
-
[0, step.amount, 0, 0],
|
|
528
|
-
[0, 0, step.amount, 0]
|
|
529
|
-
];
|
|
530
|
-
case "contrast": {
|
|
531
|
-
const c = step.amount;
|
|
532
|
-
const o = 0.5 - 0.5 * c;
|
|
533
|
-
return [
|
|
534
|
-
[c, 0, 0, o],
|
|
535
|
-
[0, c, 0, o],
|
|
536
|
-
[0, 0, c, o]
|
|
537
|
-
];
|
|
538
|
-
}
|
|
539
|
-
case "gains":
|
|
540
|
-
return [
|
|
541
|
-
[step.r, 0, 0, 0],
|
|
542
|
-
[0, step.g, 0, 0],
|
|
543
|
-
[0, 0, step.b, 0]
|
|
544
|
-
];
|
|
545
|
-
case "saturate": {
|
|
546
|
-
const s = step.amount;
|
|
547
|
-
return [
|
|
548
|
-
[0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s, 0],
|
|
549
|
-
[0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s, 0],
|
|
550
|
-
[0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s, 0]
|
|
551
|
-
];
|
|
552
|
-
}
|
|
553
|
-
case "hue-rotate": {
|
|
554
|
-
const a = step.degrees * Math.PI / 180;
|
|
555
|
-
const cos = Math.cos(a);
|
|
556
|
-
const sin = Math.sin(a);
|
|
557
|
-
return [
|
|
558
|
-
[0.213 + cos * 0.787 - sin * 0.213, 0.715 - cos * 0.715 - sin * 0.715, 0.072 - cos * 0.072 + sin * 0.928, 0],
|
|
559
|
-
[0.213 - cos * 0.213 + sin * 0.143, 0.715 + cos * 0.285 + sin * 0.14, 0.072 - cos * 0.072 - sin * 0.283, 0],
|
|
560
|
-
[0.213 - cos * 0.213 - sin * 0.787, 0.715 - cos * 0.715 + sin * 0.715, 0.072 + cos * 0.928 + sin * 0.072, 0]
|
|
561
|
-
];
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
function applyVideoGrade(grade, rgb, lut) {
|
|
566
|
-
let v = rgb.map((x) => x / 255);
|
|
567
|
-
for (const step of videoGradeSteps(grade)) {
|
|
568
|
-
const m = videoGradeStepMatrix(step);
|
|
569
|
-
v = m.map((row) => Math.min(1, Math.max(0, row[0] * v[0] + row[1] * v[1] + row[2] * v[2] + row[3])));
|
|
570
|
-
}
|
|
571
|
-
const setting = normalizeVideoGradeLut(_optionalChain([grade, 'optionalAccess', _3 => _3.lut]));
|
|
572
|
-
if (setting && lut) {
|
|
573
|
-
const out = applyVideoLut(lut, v);
|
|
574
|
-
const s = _nullishCoalesce(setting.strength, () => ( 1));
|
|
575
|
-
v = v.map((x, k) => x + (out[k] - x) * s);
|
|
576
|
-
}
|
|
577
|
-
return v.map((x) => Math.round(x * 255));
|
|
578
|
-
}
|
|
579
|
-
var fmt2 = (v) => String(Math.round(v * 1e5) / 1e5);
|
|
580
|
-
function videoGradeStepSvgValues(step) {
|
|
581
|
-
return videoGradeStepMatrix(step).map((row) => [row[0], row[1], row[2], 0, row[3]].map(fmt2).join(" ")).concat("0 0 0 1 0").join(" ");
|
|
582
|
-
}
|
|
583
|
-
function videoLutSvgPrimitives(lut, strength = 1) {
|
|
584
|
-
const { tables, matrix } = videoLutSvgApproximation(lut);
|
|
585
|
-
const table = (k) => tables[k].map(fmt2).join(" ");
|
|
586
|
-
const values = matrix.map((row) => [row[0], row[1], row[2], 0, row[3]].map(fmt2).join(" ")).concat("0 0 0 1 0").join(" ");
|
|
587
|
-
const s = Math.min(1, Math.max(0, strength));
|
|
588
|
-
return `<feComponentTransfer result="lutIn"><feFuncA type="identity"/></feComponentTransfer><feComponentTransfer><feFuncR type="table" tableValues="${table(0)}"/><feFuncG type="table" tableValues="${table(1)}"/><feFuncB type="table" tableValues="${table(2)}"/></feComponentTransfer><feColorMatrix type="matrix" values="${values}"/>` + (s < 1 ? `<feComposite in2="lutIn" operator="arithmetic" k1="0" k2="${fmt2(s)}" k3="${fmt2(1 - s)}" k4="0"/>` : "");
|
|
589
|
-
}
|
|
590
|
-
function videoGradeSvgFilter(id, grade, lut) {
|
|
591
|
-
const steps = videoGradeSteps(grade);
|
|
592
|
-
const setting = normalizeVideoGradeLut(_optionalChain([grade, 'optionalAccess', _4 => _4.lut]));
|
|
593
|
-
return `<filter id="${id}" color-interpolation-filters="sRGB" x="0" y="0" width="100%" height="100%">${steps.map((s) => `<feColorMatrix type="matrix" values="${videoGradeStepSvgValues(s)}"/>`).join("")}${setting && lut ? videoLutSvgPrimitives(lut, setting.strength) : ""}</filter>`;
|
|
594
|
-
}
|
|
595
|
-
var videoGradeGainsFilterId = (step) => `pixerate-wb-${[step.r, step.g, step.b].map((v) => Math.round(v * 1e3)).join("-")}`;
|
|
596
|
-
function videoGradeCssFilter(grade) {
|
|
597
|
-
return videoGradeSteps(grade).map((s) => s.kind === "brightness" ? `brightness(${fmt2(s.amount)})` : s.kind === "contrast" ? `contrast(${fmt2(s.amount)})` : s.kind === "saturate" ? `saturate(${fmt2(s.amount)})` : s.kind === "hue-rotate" ? `hue-rotate(${fmt2(s.degrees)}deg)` : `url(#${videoGradeGainsFilterId(s)})`).join(" ");
|
|
598
|
-
}
|
|
599
|
-
function videoGradeSvgDefs(grade) {
|
|
600
|
-
return videoGradeSteps(grade).filter((s) => s.kind === "gains").map((s) => {
|
|
601
|
-
const id = videoGradeGainsFilterId(s);
|
|
602
|
-
return { id, markup: `<filter id="${id}" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="${videoGradeStepSvgValues(s)}"/></filter>` };
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
function videoGradeFfmpegFilters(grade) {
|
|
606
|
-
return videoGradeSteps(grade).map((step) => {
|
|
607
|
-
const m = videoGradeStepMatrix(step);
|
|
608
|
-
if (step.kind === "brightness" || step.kind === "contrast") {
|
|
609
|
-
const lut = (i) => `clip(val*${fmt2(m[i][i])}+${fmt2(m[i][3] * 255)},0,255)`;
|
|
610
|
-
return `lutrgb=r='${lut(0)}':g='${lut(1)}':b='${lut(2)}'`;
|
|
611
|
-
}
|
|
612
|
-
const k = ["r", "g", "b"];
|
|
613
|
-
return `colorchannelmixer=${m.flatMap((row, i) => row.slice(0, 3).map((v, j) => `${k[i]}${k[j]}=${fmt2(v)}`)).join(":")}`;
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// src/video-editor/remap.ts
|
|
618
|
-
function videoClipSourceTime(clip, clipTime) {
|
|
619
|
-
const base = _nullishCoalesce(clip.in, () => ( 0));
|
|
620
|
-
return clip.timeRemap ? base + videoValueAt(clip.timeRemap, clipTime, 0) : base + clipTime * (_nullishCoalesce(clip.speed, () => ( 1)));
|
|
621
|
-
}
|
|
622
|
-
function videoClipSpeedAt(clip, clipTime) {
|
|
623
|
-
if (clip.type !== "media") return 1;
|
|
624
|
-
if (!clip.timeRemap) return _nullishCoalesce(clip.speed, () => ( 1));
|
|
625
|
-
const t = Math.min(Math.max(clipTime, 0), Math.max(0, clip.duration - 1));
|
|
626
|
-
return Math.max(0, videoClipSourceTime(clip, t + 1) - videoClipSourceTime(clip, t));
|
|
627
|
-
}
|
|
628
|
-
function videoSpeedRampKeys(segments) {
|
|
629
|
-
if (!segments.length) throw new Error("Give at least one stretch { duration, speed }.");
|
|
630
|
-
const keys = [];
|
|
631
|
-
let t = 0;
|
|
632
|
-
let v = 0;
|
|
633
|
-
segments.forEach((s, i) => {
|
|
634
|
-
if (!(s.duration > 0)) throw new Error(`Stretch ${i + 1} needs a duration above 0 ms.`);
|
|
635
|
-
for (const [name, x] of [["speed", s.speed], ["toSpeed", s.toSpeed]])
|
|
636
|
-
if (x !== void 0 && !(x >= 0 && x <= 20)) throw new Error(`Stretch ${i + 1}'s ${name} must be from 0 (a freeze) to 20; got ${x}.`);
|
|
637
|
-
const a = s.speed;
|
|
638
|
-
const b = _nullishCoalesce(s.toSpeed, () => ( s.speed));
|
|
639
|
-
const avg = (a + b) / 2;
|
|
640
|
-
let ease = "linear";
|
|
641
|
-
if (a !== b && avg > 0) {
|
|
642
|
-
ease = [1 / 3, 2 * a / (3 * (a + b)), 2 / 3, 1 - 2 * b / (3 * (a + b))].map((n2) => Math.round(n2 * 1e6) / 1e6);
|
|
643
|
-
}
|
|
644
|
-
keys.push({ t, v, ...ease === "linear" ? {} : { ease } });
|
|
645
|
-
t += s.duration;
|
|
646
|
-
v += avg * s.duration;
|
|
647
|
-
});
|
|
648
|
-
keys.push({ t, v });
|
|
649
|
-
return { keys: mergeLinear(keys), duration: t, source: v };
|
|
650
|
-
}
|
|
651
|
-
function mergeLinear(keys) {
|
|
652
|
-
const out = [keys[0]];
|
|
653
|
-
for (let i = 1; i < keys.length; i++) {
|
|
654
|
-
const prev = out[out.length - 1];
|
|
655
|
-
const k = keys[i];
|
|
656
|
-
const before = out.length > 1 ? out[out.length - 2] : null;
|
|
657
|
-
if (before && !before.ease && !prev.ease) {
|
|
658
|
-
const s1 = (prev.v - before.v) / (prev.t - before.t);
|
|
659
|
-
const s2 = (k.v - prev.v) / (k.t - prev.t);
|
|
660
|
-
if (Math.abs(s1 - s2) < 1e-9) {
|
|
661
|
-
out[out.length - 1] = k;
|
|
662
|
-
continue;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
out.push(k);
|
|
666
|
-
}
|
|
667
|
-
return out;
|
|
668
|
-
}
|
|
669
|
-
function checkVideoTimeRemap(remap, path = "timeRemap") {
|
|
670
|
-
const { keys } = remap;
|
|
671
|
-
if (!keys.length) throw new Error(`${path} needs at least one key.`);
|
|
672
|
-
keys.forEach((k, i) => {
|
|
673
|
-
if (k.v < 0) throw new Error(`${path}.keys[${i}].v must be at least 0 (ms after the in point).`);
|
|
674
|
-
const next = keys[i + 1];
|
|
675
|
-
if (!next) return;
|
|
676
|
-
if (next.v < k.v - 1e-6) throw new Error(`${path}.keys[${i + 1}] goes back in the source (${next.v} ms after ${k.v} ms); a ramp only plays forwards, so make each value at least the one before.`);
|
|
677
|
-
if (!videoEaseBezier(k.ease)) return;
|
|
678
|
-
let prev = k.v;
|
|
679
|
-
for (let n2 = 1; n2 <= 32; n2++) {
|
|
680
|
-
const v = videoValueAt(remap, k.t + (next.t - k.t) * n2 / 32);
|
|
681
|
-
if (v < prev - 1e-3) throw new Error(`${path}.keys[${i}].ease overshoots, which would play backwards; use a curve that only moves forwards (or linear).`);
|
|
682
|
-
prev = v;
|
|
683
|
-
}
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
function videoTimeRemapSpan(remap) {
|
|
687
|
-
return { from: remap.keys[0].v, to: remap.keys[remap.keys.length - 1].v };
|
|
688
|
-
}
|
|
689
|
-
function videoTimeRemapBreakpoints(remap, step) {
|
|
690
|
-
const { points, holds } = videoKeyframeBreakpoints(remap, step);
|
|
691
|
-
const out = [];
|
|
692
|
-
points.forEach(([t, v], i) => {
|
|
693
|
-
out.push({ t, v });
|
|
694
|
-
if (holds.has(i) && points[i + 1]) out.push({ t: points[i + 1][0], v });
|
|
695
|
-
});
|
|
696
|
-
return out;
|
|
697
|
-
}
|
|
698
|
-
function videoSpeedRampEdit(clip, segments, ripple = true) {
|
|
699
|
-
const ramp = videoSpeedRampKeys(segments);
|
|
700
|
-
const offset = videoClipSourceTime(clip, 0) - (_nullishCoalesce(clip.in, () => ( 0)));
|
|
701
|
-
return { op: "set_time_remap", clip: clip.id, keys: ramp.keys.map((k) => ({ ...k, v: k.v + offset })), duration: ramp.duration, ripple };
|
|
702
|
-
}
|
|
703
|
-
function videoFreezeFrameEdit(clip, at, duration, ripple = true) {
|
|
704
|
-
if (at < 0 || at > clip.duration) throw new Error(`${Math.round(at)} ms is outside clip "${clip.id}" (0\u2013${clip.duration} ms of clip time).`);
|
|
705
|
-
const remap = _nullishCoalesce(clip.timeRemap, () => ( { keys: [{ t: 0, v: 0 }, { t: clip.duration, v: clip.duration * (_nullishCoalesce(clip.speed, () => ( 1))) }] }));
|
|
706
|
-
const [left, right] = splitVideoAnimatable(remap, at);
|
|
707
|
-
const keys = [...left.keys.slice(0, -1), { ...left.keys[left.keys.length - 1], ease: "linear" }, ...right.keys.map((k) => ({ ...k, t: k.t + at + duration }))];
|
|
708
|
-
return { op: "set_time_remap", clip: clip.id, keys, duration: clip.duration + duration, ripple };
|
|
709
|
-
}
|
|
710
|
-
var videoSlowMotionRamp = (duration) => [
|
|
711
|
-
{ duration: Math.max(1, duration / 2), speed: 1 },
|
|
712
|
-
{ duration: 500, speed: 1, toSpeed: 0.3 },
|
|
713
|
-
{ duration: 1500, speed: 0.3 }
|
|
714
|
-
];
|
|
715
|
-
|
|
716
136
|
// src/video-editor/parse.ts
|
|
717
137
|
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
718
138
|
var fail = (path, what) => {
|
|
@@ -745,11 +165,11 @@ var compact = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !=
|
|
|
745
165
|
function parseVideoEase(v, path) {
|
|
746
166
|
if (v === void 0) return void 0;
|
|
747
167
|
if (Array.isArray(v)) {
|
|
748
|
-
if (v.length !== 4 || !v.every((
|
|
168
|
+
if (v.length !== 4 || !v.every((n) => typeof n === "number" && Number.isFinite(n))) fail(path, "must be four numbers [x1, y1, x2, y2] (CSS cubic-bezier)");
|
|
749
169
|
if (v[0] < 0 || v[0] > 1 || v[2] < 0 || v[2] > 1) fail(path, "must have x1 and x2 between 0 and 1");
|
|
750
170
|
return [v[0], v[1], v[2], v[3]];
|
|
751
171
|
}
|
|
752
|
-
return oneOf(v, VIDEO_EASE_NAMES, path);
|
|
172
|
+
return oneOf(v, _chunkSMJGE7HMcjs.VIDEO_EASE_NAMES, path);
|
|
753
173
|
}
|
|
754
174
|
function parseVideoKeyframes(v, path, { min, max } = {}) {
|
|
755
175
|
if (!isObject(v)) return fail(path, "must be a number or keyframes { keys: [{ t, v, ease }] }");
|
|
@@ -787,7 +207,7 @@ function parseVideoTimeRemap(v, speed, path) {
|
|
|
787
207
|
if (typeof remap === "number" || remap === void 0) return fail(path, "must be keyframes { keys: [{ t, v, ease }] } (v: ms of source after the in point)");
|
|
788
208
|
if (speed !== void 0 && speed !== 1) fail(path, 'cannot be used with a speed; a ramp sets the speed itself (remove "speed")');
|
|
789
209
|
try {
|
|
790
|
-
checkVideoTimeRemap(remap, path);
|
|
210
|
+
_chunkSMJGE7HMcjs.checkVideoTimeRemap.call(void 0, remap, path);
|
|
791
211
|
} catch (e) {
|
|
792
212
|
throw new Error(e.message.replace(/\.?$/, "."));
|
|
793
213
|
}
|
|
@@ -797,17 +217,17 @@ function parseVideoClipAnimation(v, path) {
|
|
|
797
217
|
if (v === void 0) return void 0;
|
|
798
218
|
if (!isObject(v)) return fail(path, "must be an object { effect, duration }");
|
|
799
219
|
return compact({
|
|
800
|
-
effect: oneOf(v.effect, VIDEO_CLIP_ANIMATION_EFFECTS, `${path}.effect`, false),
|
|
220
|
+
effect: oneOf(v.effect, _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_EFFECTS, `${path}.effect`, false),
|
|
801
221
|
duration: num(v.duration, `${path}.duration`, { optional: true, positive: true })
|
|
802
222
|
});
|
|
803
223
|
}
|
|
804
224
|
function parseVideoGrade(v, path) {
|
|
805
225
|
if (v === void 0) return void 0;
|
|
806
226
|
if (!isObject(v)) return fail(path, "must be an object such as { exposure, contrast, saturation }");
|
|
807
|
-
const known = /* @__PURE__ */ new Set([...VIDEO_GRADE_CONTROLS.map((c) => c.key), "lut"]);
|
|
227
|
+
const known = /* @__PURE__ */ new Set([..._chunkSMJGE7HMcjs.VIDEO_GRADE_CONTROLS.map((c) => c.key), "lut"]);
|
|
808
228
|
const unknown = Object.keys(v).find((k) => !known.has(k));
|
|
809
229
|
if (unknown) fail(`${path}.${unknown}`, `is not a grade setting; use ${[...known].join(", ")}`);
|
|
810
|
-
return compact({ ...Object.fromEntries(VIDEO_GRADE_CONTROLS.map((c) => [c.key, num(v[c.key], `${path}.${c.key}`, { optional: true, min: c.min, max: c.max })])), lut: parseVideoGradeLut(v.lut, `${path}.lut`) });
|
|
230
|
+
return compact({ ...Object.fromEntries(_chunkSMJGE7HMcjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, num(v[c.key], `${path}.${c.key}`, { optional: true, min: c.min, max: c.max })])), lut: parseVideoGradeLut(v.lut, `${path}.lut`) });
|
|
811
231
|
}
|
|
812
232
|
function parseVideoGradeLut(v, path) {
|
|
813
233
|
if (v === void 0) return void 0;
|
|
@@ -820,11 +240,11 @@ function parseVideoTransition(v, path) {
|
|
|
820
240
|
if (v === void 0) return void 0;
|
|
821
241
|
if (!isObject(v)) return fail(path, "must be an object { type, duration }");
|
|
822
242
|
return compact({
|
|
823
|
-
type: oneOf(v.type, VIDEO_TRANSITION_TYPES, `${path}.type`, false),
|
|
243
|
+
type: oneOf(v.type, _chunkSMJGE7HMcjs.VIDEO_TRANSITION_TYPES, `${path}.type`, false),
|
|
824
244
|
duration: num(v.duration, `${path}.duration`, { positive: true }),
|
|
825
245
|
color: str(v.color, `${path}.color`, true),
|
|
826
|
-
direction: oneOf(v.direction, VIDEO_WIPE_DIRECTIONS, `${path}.direction`),
|
|
827
|
-
audioCurve: oneOf(v.audioCurve, VIDEO_FADE_CURVES, `${path}.audioCurve`)
|
|
246
|
+
direction: oneOf(v.direction, _chunkSMJGE7HMcjs.VIDEO_WIPE_DIRECTIONS, `${path}.direction`),
|
|
247
|
+
audioCurve: oneOf(v.audioCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.audioCurve`)
|
|
828
248
|
});
|
|
829
249
|
}
|
|
830
250
|
function parseVideoTranscriptWords(v, path) {
|
|
@@ -881,7 +301,7 @@ function parseVideoAssetProxies(v, path) {
|
|
|
881
301
|
}
|
|
882
302
|
function parseVideoClip(v, path = "clip") {
|
|
883
303
|
if (!isObject(v)) return fail(path, "must be an object");
|
|
884
|
-
const type = oneOf(_nullishCoalesce(v.type, () => ( "media")), VIDEO_CLIP_TYPES, `${path}.type`, false);
|
|
304
|
+
const type = oneOf(_nullishCoalesce(v.type, () => ( "media")), _chunkSMJGE7HMcjs.VIDEO_CLIP_TYPES, `${path}.type`, false);
|
|
885
305
|
const base = {
|
|
886
306
|
id: str(v.id, `${path}.id`),
|
|
887
307
|
name: str(v.name, `${path}.name`, true),
|
|
@@ -889,8 +309,8 @@ function parseVideoClip(v, path = "clip") {
|
|
|
889
309
|
duration: num(v.duration, `${path}.duration`, { positive: true }),
|
|
890
310
|
opacity: parseVideoAnimatable(v.opacity, `${path}.opacity`, { optional: true, min: 0, max: 1 }),
|
|
891
311
|
transform: parseVideoTransform(v.transform, `${path}.transform`),
|
|
892
|
-
fit: oneOf(v.fit, VIDEO_FITS, `${path}.fit`),
|
|
893
|
-
blend: oneOf(v.blend, VIDEO_BLEND_MODES, `${path}.blend`),
|
|
312
|
+
fit: oneOf(v.fit, _chunkSMJGE7HMcjs.VIDEO_FITS, `${path}.fit`),
|
|
313
|
+
blend: oneOf(v.blend, _chunkSMJGE7HMcjs.VIDEO_BLEND_MODES, `${path}.blend`),
|
|
894
314
|
grade: parseVideoGrade(v.grade, `${path}.grade`),
|
|
895
315
|
animateIn: parseVideoClipAnimation(v.animateIn, `${path}.animateIn`),
|
|
896
316
|
animateOut: parseVideoClipAnimation(v.animateOut, `${path}.animateOut`),
|
|
@@ -908,8 +328,8 @@ function parseVideoClip(v, path = "clip") {
|
|
|
908
328
|
volume: parseVideoAnimatable(v.volume, `${path}.volume`, { optional: true, min: 0, max: 4 }),
|
|
909
329
|
muted: bool(v.muted, `${path}.muted`),
|
|
910
330
|
timeRemap: parseVideoTimeRemap(v.timeRemap, v.speed, `${path}.timeRemap`),
|
|
911
|
-
fadeInCurve: oneOf(v.fadeInCurve, VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
|
|
912
|
-
fadeOutCurve: oneOf(v.fadeOutCurve, VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
|
|
331
|
+
fadeInCurve: oneOf(v.fadeInCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
|
|
332
|
+
fadeOutCurve: oneOf(v.fadeOutCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
|
|
913
333
|
});
|
|
914
334
|
if (type === "sequence") {
|
|
915
335
|
for (const key of ["speed", "timeRemap"])
|
|
@@ -921,8 +341,8 @@ function parseVideoClip(v, path = "clip") {
|
|
|
921
341
|
in: num(v.in, `${path}.in`, { optional: true, min: 0 }),
|
|
922
342
|
volume: parseVideoAnimatable(v.volume, `${path}.volume`, { optional: true, min: 0, max: 4 }),
|
|
923
343
|
muted: bool(v.muted, `${path}.muted`),
|
|
924
|
-
fadeInCurve: oneOf(v.fadeInCurve, VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
|
|
925
|
-
fadeOutCurve: oneOf(v.fadeOutCurve, VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
|
|
344
|
+
fadeInCurve: oneOf(v.fadeInCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
|
|
345
|
+
fadeOutCurve: oneOf(v.fadeOutCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
|
|
926
346
|
});
|
|
927
347
|
}
|
|
928
348
|
if (type === "text")
|
|
@@ -1026,264 +446,12 @@ function createVideoProject(options = {}) {
|
|
|
1026
446
|
});
|
|
1027
447
|
}
|
|
1028
448
|
|
|
1029
|
-
// src/video-editor/timeline.ts
|
|
1030
|
-
var VIDEO_TIME_EPSILON = 0.5;
|
|
1031
|
-
var videoClipEnd = (clip) => clip.start + clip.duration;
|
|
1032
|
-
var videoTrackSyncLocked = (track) => track.syncLocked !== false;
|
|
1033
|
-
var videoClipSpeed = (clip) => clip.type === "media" ? _nullishCoalesce(clip.speed, () => ( 1)) : 1;
|
|
1034
|
-
function videoClipSourceRange(clip) {
|
|
1035
|
-
if (clip.type === "sequence") return { in: _nullishCoalesce(clip.in, () => ( 0)), out: (_nullishCoalesce(clip.in, () => ( 0))) + clip.duration };
|
|
1036
|
-
if (clip.type !== "media") return null;
|
|
1037
|
-
const start = _nullishCoalesce(clip.in, () => ( 0));
|
|
1038
|
-
if (_optionalChain([clip, 'access', _5 => _5.timeRemap, 'optionalAccess', _6 => _6.keys, 'access', _7 => _7.length])) return { in: start + clip.timeRemap.keys[0].v, out: start + clip.timeRemap.keys[clip.timeRemap.keys.length - 1].v };
|
|
1039
|
-
return { in: start, out: start + clip.duration * videoClipSpeed(clip) };
|
|
1040
|
-
}
|
|
1041
|
-
var videoFrameDuration = (fps) => 1e3 / fps;
|
|
1042
|
-
function snapToVideoFrame(time, fps) {
|
|
1043
|
-
const frame = Math.round(time * fps / 1e3);
|
|
1044
|
-
return Math.round(frame * 1e3 / fps * 1e3) / 1e3;
|
|
1045
|
-
}
|
|
1046
|
-
var videoFrames = (time, fps) => Math.round(time * fps / 1e3);
|
|
1047
|
-
function isVideoDropFrameRate(fps) {
|
|
1048
|
-
const nominal = Math.round(fps);
|
|
1049
|
-
return (nominal === 30 || nominal === 60) && Math.abs(fps - nominal * 1e3 / 1001) < 5e-3;
|
|
1050
|
-
}
|
|
1051
|
-
var exactVideoRate = (fps) => {
|
|
1052
|
-
const nominal = Math.round(fps);
|
|
1053
|
-
return nominal !== fps && Math.abs(fps - nominal * 1e3 / 1001) < 5e-3 ? nominal * 1e3 / 1001 : fps;
|
|
1054
|
-
};
|
|
1055
|
-
var videoTimecodeFrames = (time, fps) => Math.max(0, Math.round(time * exactVideoRate(fps) / 1e3));
|
|
1056
|
-
function formatVideoTimecode(time, fps, dropFrame = isVideoDropFrameRate(fps)) {
|
|
1057
|
-
return formatVideoTimecodeFrames(videoTimecodeFrames(time, fps), fps, dropFrame);
|
|
1058
|
-
}
|
|
1059
|
-
function formatVideoTimecodeFrames(frames, fps, dropFrame = isVideoDropFrameRate(fps)) {
|
|
1060
|
-
const base = Math.round(fps);
|
|
1061
|
-
let total = Math.max(0, Math.round(frames));
|
|
1062
|
-
const drop = dropFrame && isVideoDropFrameRate(fps);
|
|
1063
|
-
if (drop) {
|
|
1064
|
-
const skip = base / 15;
|
|
1065
|
-
const perMinute = base * 60 - skip;
|
|
1066
|
-
const perTen = perMinute * 10 + skip;
|
|
1067
|
-
const tens = Math.floor(total / perTen);
|
|
1068
|
-
const rest = total % perTen;
|
|
1069
|
-
total += skip * 9 * tens + (rest > skip ? skip * Math.floor((rest - skip) / perMinute) : 0);
|
|
1070
|
-
}
|
|
1071
|
-
const ff = total % base;
|
|
1072
|
-
const secs = Math.floor(total / base);
|
|
1073
|
-
const pad = (n2) => String(n2).padStart(2, "0");
|
|
1074
|
-
return `${pad(Math.floor(secs / 3600))}:${pad(Math.floor(secs / 60) % 60)}:${pad(secs % 60)}${drop ? ";" : ":"}${pad(ff)}`;
|
|
1075
|
-
}
|
|
1076
|
-
var videoHourFrames = (fps, dropFrame = isVideoDropFrameRate(fps)) => {
|
|
1077
|
-
const base = Math.round(fps);
|
|
1078
|
-
return dropFrame && isVideoDropFrameRate(fps) ? base * 3600 - base / 15 * 54 : base * 3600;
|
|
1079
|
-
};
|
|
1080
|
-
var formatVideoSeconds = (time) => `${(time / 1e3).toFixed(2)} s`;
|
|
1081
|
-
var videoAssetHasSound = (asset) => !!asset && (asset.kind === "audio" || asset.kind === "video" && asset.hasAudio !== false);
|
|
1082
|
-
function videoAssetMap(project) {
|
|
1083
|
-
return new Map(project.assets.map((a) => [a.id, a]));
|
|
1084
|
-
}
|
|
1085
|
-
function videoSequenceMap(project) {
|
|
1086
|
-
return new Map((_nullishCoalesce(project.sequences, () => ( []))).map((q) => [q.id, q]));
|
|
1087
|
-
}
|
|
1088
|
-
function videoSequenceDuration(sequence) {
|
|
1089
|
-
let end = 0;
|
|
1090
|
-
for (const track of sequence.tracks) for (const clip of track.clips) end = Math.max(end, videoClipEnd(clip));
|
|
1091
|
-
return end;
|
|
1092
|
-
}
|
|
1093
|
-
var videoSequenceChildren = (sequence) => [...new Set(sequence.tracks.flatMap((t) => t.clips.flatMap((c) => c.type === "sequence" ? [c.sequence] : [])))];
|
|
1094
|
-
function findVideoSequenceCycle(project, id) {
|
|
1095
|
-
const sequences = videoSequenceMap(project);
|
|
1096
|
-
const walk = (at, path) => {
|
|
1097
|
-
const seq = sequences.get(at);
|
|
1098
|
-
if (!seq) return null;
|
|
1099
|
-
for (const child of videoSequenceChildren(seq)) {
|
|
1100
|
-
if (child === id) return [...path, child];
|
|
1101
|
-
if (path.includes(child)) continue;
|
|
1102
|
-
const found = walk(child, [...path, child]);
|
|
1103
|
-
if (found) return found;
|
|
1104
|
-
}
|
|
1105
|
-
return null;
|
|
1106
|
-
};
|
|
1107
|
-
return walk(id, [id]);
|
|
1108
|
-
}
|
|
1109
|
-
function allVideoTracks(project) {
|
|
1110
|
-
return [...project.tracks.map((track) => ({ track })), ...(_nullishCoalesce(project.sequences, () => ( []))).flatMap((q) => q.tracks.map((track) => ({ sequence: q.id, track })))];
|
|
1111
|
-
}
|
|
1112
|
-
function sortedVideoClips(track) {
|
|
1113
|
-
return [...track.clips].sort((a, b) => a.start - b.start || a.duration - b.duration);
|
|
1114
|
-
}
|
|
1115
|
-
function findVideoClip(project, id) {
|
|
1116
|
-
for (let trackIndex = 0; trackIndex < project.tracks.length; trackIndex++) {
|
|
1117
|
-
const track = project.tracks[trackIndex];
|
|
1118
|
-
const index = track.clips.findIndex((c) => c.id === id);
|
|
1119
|
-
if (index >= 0) return { track, trackIndex, clip: track.clips[index], index };
|
|
1120
|
-
}
|
|
1121
|
-
return null;
|
|
1122
|
-
}
|
|
1123
|
-
function allVideoClipIds(project) {
|
|
1124
|
-
return allVideoTracks(project).flatMap(({ track }) => track.clips.map((c) => c.id));
|
|
1125
|
-
}
|
|
1126
|
-
function findVideoSequenceClip(project, id) {
|
|
1127
|
-
for (const sequence of _nullishCoalesce(project.sequences, () => ( [])))
|
|
1128
|
-
for (const track of sequence.tracks) {
|
|
1129
|
-
const clip = track.clips.find((c) => c.id === id);
|
|
1130
|
-
if (clip) return { sequence, track, clip };
|
|
1131
|
-
}
|
|
1132
|
-
return null;
|
|
1133
|
-
}
|
|
1134
|
-
function videoProjectDuration(project) {
|
|
1135
|
-
let end = 0;
|
|
1136
|
-
for (const track of project.tracks) for (const clip of track.clips) end = Math.max(end, videoClipEnd(clip));
|
|
1137
|
-
return end;
|
|
1138
|
-
}
|
|
1139
|
-
function videoClipBefore(track, clip) {
|
|
1140
|
-
let best = null;
|
|
1141
|
-
for (const c of track.clips) if (c !== clip && Math.abs(videoClipEnd(c) - clip.start) <= VIDEO_TIME_EPSILON) best = c;
|
|
1142
|
-
return best;
|
|
1143
|
-
}
|
|
1144
|
-
function videoClipAfter(track, clip) {
|
|
1145
|
-
for (const c of track.clips) if (c !== clip && Math.abs(c.start - videoClipEnd(clip)) <= VIDEO_TIME_EPSILON) return c;
|
|
1146
|
-
return null;
|
|
1147
|
-
}
|
|
1148
|
-
function videoClipHandles(clip, assets, sequences) {
|
|
1149
|
-
if (clip.type === "sequence") {
|
|
1150
|
-
const seq = _optionalChain([sequences, 'optionalAccess', _8 => _8.get, 'call', _9 => _9(clip.sequence)]);
|
|
1151
|
-
const range2 = videoClipSourceRange(clip);
|
|
1152
|
-
return { before: range2.in, after: seq ? Math.max(0, videoSequenceDuration(seq) - range2.out) : Infinity };
|
|
1153
|
-
}
|
|
1154
|
-
if (clip.type !== "media") return { before: Infinity, after: Infinity };
|
|
1155
|
-
const asset = assets.get(clip.asset);
|
|
1156
|
-
const speed = videoClipSpeed(clip);
|
|
1157
|
-
const range = videoClipSourceRange(clip);
|
|
1158
|
-
const before = range.in / speed;
|
|
1159
|
-
if (!asset || asset.kind === "image" || asset.duration === void 0) return { before: _optionalChain([asset, 'optionalAccess', _10 => _10.kind]) === "image" ? Infinity : before, after: Infinity };
|
|
1160
|
-
return { before, after: Math.max(0, (asset.duration - range.out) / speed) };
|
|
1161
|
-
}
|
|
1162
|
-
function videoClipOverhang(track, clip) {
|
|
1163
|
-
const lead = clip.transition && clip.transition.type !== "dip" && videoClipBefore(track, clip) ? clip.transition.duration / 2 : 0;
|
|
1164
|
-
const next = videoClipAfter(track, clip);
|
|
1165
|
-
const tail = _optionalChain([next, 'optionalAccess', _11 => _11.transition]) && next.transition.type !== "dip" ? next.transition.duration / 2 : 0;
|
|
1166
|
-
return { lead, tail };
|
|
1167
|
-
}
|
|
1168
|
-
function videoSnapPoints(project, options = {}) {
|
|
1169
|
-
const exclude = new Set(_nullishCoalesce(options.exclude, () => ( [])));
|
|
1170
|
-
const points = /* @__PURE__ */ new Set([0]);
|
|
1171
|
-
for (const track of project.tracks)
|
|
1172
|
-
for (const clip of track.clips) {
|
|
1173
|
-
if (exclude.has(clip.id)) continue;
|
|
1174
|
-
points.add(clip.start);
|
|
1175
|
-
points.add(videoClipEnd(clip));
|
|
1176
|
-
}
|
|
1177
|
-
for (const marker of _nullishCoalesce(project.markers, () => ( []))) points.add(marker.time);
|
|
1178
|
-
if (options.playhead !== void 0) points.add(options.playhead);
|
|
1179
|
-
return [...points].sort((a, b) => a - b);
|
|
1180
|
-
}
|
|
1181
|
-
function snapVideoTime(time, points, threshold) {
|
|
1182
|
-
let best = null;
|
|
1183
|
-
for (const p of points) if (Math.abs(p - time) <= threshold && (best === null || Math.abs(p - time) < Math.abs(best - time))) best = p;
|
|
1184
|
-
return best === null ? { time, snapped: null } : { time: best, snapped: best };
|
|
1185
|
-
}
|
|
1186
|
-
function findVideoGaps(project, trackId) {
|
|
1187
|
-
const gaps = [];
|
|
1188
|
-
for (const track of project.tracks) {
|
|
1189
|
-
if (trackId !== void 0 && track.id !== trackId) continue;
|
|
1190
|
-
let at = 0;
|
|
1191
|
-
for (const clip of sortedVideoClips(track)) {
|
|
1192
|
-
if (clip.start - at > VIDEO_TIME_EPSILON) gaps.push({ track: track.id, start: at, end: clip.start });
|
|
1193
|
-
at = Math.max(at, videoClipEnd(clip));
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
return gaps;
|
|
1197
|
-
}
|
|
1198
|
-
function videoOverlap(track, start, end, ignore = /* @__PURE__ */ new Set()) {
|
|
1199
|
-
for (const c of sortedVideoClips(track)) {
|
|
1200
|
-
if (ignore.has(c.id)) continue;
|
|
1201
|
-
if (c.start < end - VIDEO_TIME_EPSILON && videoClipEnd(c) > start + VIDEO_TIME_EPSILON) return c;
|
|
1202
|
-
}
|
|
1203
|
-
return null;
|
|
1204
|
-
}
|
|
1205
|
-
function nextFreeVideoSlot(track, from, duration, ignore = /* @__PURE__ */ new Set()) {
|
|
1206
|
-
let at = from;
|
|
1207
|
-
for (const c of sortedVideoClips(track)) {
|
|
1208
|
-
if (ignore.has(c.id)) continue;
|
|
1209
|
-
if (videoClipEnd(c) <= at + VIDEO_TIME_EPSILON) continue;
|
|
1210
|
-
if (c.start >= at + duration - VIDEO_TIME_EPSILON) break;
|
|
1211
|
-
at = videoClipEnd(c);
|
|
1212
|
-
}
|
|
1213
|
-
return at;
|
|
1214
|
-
}
|
|
1215
|
-
function videoClipsAt(project, time) {
|
|
1216
|
-
const out = [];
|
|
1217
|
-
for (const track of project.tracks) for (const clip of track.clips) if (time >= clip.start && time < videoClipEnd(clip)) out.push({ track: track.id, clip });
|
|
1218
|
-
return out;
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
// src/video-editor/clip-animation.ts
|
|
1222
|
-
var VIDEO_CLIP_ANIMATION_DURATION = 500;
|
|
1223
|
-
var EFFECTS = {
|
|
1224
|
-
fade: { easeIn: "linear", easeOut: "linear" },
|
|
1225
|
-
rise: { y: 0.06, easeIn: "ease-out", easeOut: "ease-in" },
|
|
1226
|
-
drop: { y: -0.06, easeIn: "ease-out", easeOut: "ease-in" },
|
|
1227
|
-
"slide-left": { x: 0.15, easeIn: "ease-out", easeOut: "ease-in" },
|
|
1228
|
-
"slide-right": { x: -0.15, easeIn: "ease-out", easeOut: "ease-in" },
|
|
1229
|
-
zoom: { scale: 0.6, easeIn: "ease-out", easeOut: "ease-in" },
|
|
1230
|
-
// Overshoots past full size, then settles (a "back" curve).
|
|
1231
|
-
pop: { scale: 0.3, easeIn: [0.34, 1.56, 0.64, 1], easeOut: [0.36, 0, 0.66, -0.56] }
|
|
1232
|
-
};
|
|
1233
|
-
var PROPS = ["opacity", "x", "y", "scale"];
|
|
1234
|
-
function videoClipAnimationProperties(animation) {
|
|
1235
|
-
const spec = EFFECTS[animation.effect];
|
|
1236
|
-
return PROPS.filter((p) => p === "opacity" || spec[p] !== void 0);
|
|
1237
|
-
}
|
|
1238
|
-
function videoClipAnimationSpans(clip) {
|
|
1239
|
-
const a = clip.animateIn ? _nullishCoalesce(clip.animateIn.duration, () => ( VIDEO_CLIP_ANIMATION_DURATION)) : 0;
|
|
1240
|
-
const b = clip.animateOut ? _nullishCoalesce(clip.animateOut.duration, () => ( VIDEO_CLIP_ANIMATION_DURATION)) : 0;
|
|
1241
|
-
const k = a + b > clip.duration ? clip.duration / (a + b) : 1;
|
|
1242
|
-
return { in: a * k, out: b * k };
|
|
1243
|
-
}
|
|
1244
|
-
function videoClipAnimated(clip, project) {
|
|
1245
|
-
if (!clip.animateIn && !clip.animateOut) return clip;
|
|
1246
|
-
const spans = videoClipAnimationSpans(clip);
|
|
1247
|
-
const out = { ...clip, transform: { ...clip.transform } };
|
|
1248
|
-
for (const prop of PROPS) {
|
|
1249
|
-
const current = prop === "opacity" ? clip.opacity : _optionalChain([clip, 'access', _12 => _12.transform, 'optionalAccess', _13 => _13[prop]]);
|
|
1250
|
-
if (isVideoKeyframes(current)) continue;
|
|
1251
|
-
const base = _nullishCoalesce(current, () => ( (prop === "opacity" || prop === "scale" ? 1 : 0)));
|
|
1252
|
-
const away = (spec) => {
|
|
1253
|
-
if (prop === "opacity") return 0;
|
|
1254
|
-
const v = spec[prop];
|
|
1255
|
-
if (v === void 0) return void 0;
|
|
1256
|
-
return prop === "scale" ? base * v : base + v * (prop === "x" ? project.width : project.height);
|
|
1257
|
-
};
|
|
1258
|
-
const keys = [];
|
|
1259
|
-
if (clip.animateIn) {
|
|
1260
|
-
const spec = EFFECTS[clip.animateIn.effect];
|
|
1261
|
-
const from = away(spec);
|
|
1262
|
-
if (from !== void 0) keys.push({ t: 0, v: from, ease: spec.easeIn }, { t: spans.in, v: base });
|
|
1263
|
-
}
|
|
1264
|
-
if (clip.animateOut) {
|
|
1265
|
-
const spec = EFFECTS[clip.animateOut.effect];
|
|
1266
|
-
const to = away(spec);
|
|
1267
|
-
if (to !== void 0) {
|
|
1268
|
-
const start = clip.duration - spans.out;
|
|
1269
|
-
if (!keys.length || keys[keys.length - 1].t < start) keys.push({ t: start, v: base, ease: spec.easeOut });
|
|
1270
|
-
else keys[keys.length - 1] = { ...keys[keys.length - 1], ease: spec.easeOut };
|
|
1271
|
-
keys.push({ t: clip.duration, v: to });
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
if (!keys.length) continue;
|
|
1275
|
-
if (prop === "opacity") out.opacity = { keys };
|
|
1276
|
-
else out.transform[prop] = { keys };
|
|
1277
|
-
}
|
|
1278
|
-
return out;
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
449
|
// src/video-editor/check.ts
|
|
1282
450
|
function videoClipKeyframes(clip) {
|
|
1283
451
|
const out = [
|
|
1284
|
-
{ property: "opacity", keys: videoKeysOf(clip.opacity) },
|
|
1285
|
-
{ property: "volume", keys: clip.type === "media" || clip.type === "sequence" ? videoKeysOf(clip.volume) : [] },
|
|
1286
|
-
...VIDEO_TRANSFORM_PROPERTIES.map((p) => ({ property: p, keys: videoKeysOf(_optionalChain([clip, 'access',
|
|
452
|
+
{ property: "opacity", keys: _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, clip.opacity) },
|
|
453
|
+
{ property: "volume", keys: clip.type === "media" || clip.type === "sequence" ? _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, clip.volume) : [] },
|
|
454
|
+
..._chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.map((p) => ({ property: p, keys: _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, _optionalChain([clip, 'access', _2 => _2.transform, 'optionalAccess', _3 => _3[p]])) }))
|
|
1287
455
|
];
|
|
1288
456
|
return out.filter((o) => o.keys.length);
|
|
1289
457
|
}
|
|
@@ -1310,8 +478,8 @@ var VIDEO_ISSUE_CODES = [
|
|
|
1310
478
|
var videoIssueKey = (i) => [i.code, _nullishCoalesce(i.sequence, () => ( "")), _nullishCoalesce(i.track, () => ( "")), _nullishCoalesce(i.clip, () => ( "")), _nullishCoalesce(i.asset, () => ( "")), _nullishCoalesce(i.marker, () => ( ""))].join("|");
|
|
1311
479
|
function checkVideoProject(project) {
|
|
1312
480
|
const issues = [];
|
|
1313
|
-
const assets = videoAssetMap(project);
|
|
1314
|
-
const sequences = videoSequenceMap(project);
|
|
481
|
+
const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project);
|
|
482
|
+
const sequences = _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, project);
|
|
1315
483
|
const used = /* @__PURE__ */ new Set();
|
|
1316
484
|
const usedSequences = /* @__PURE__ */ new Set();
|
|
1317
485
|
const cycles = /* @__PURE__ */ new Map();
|
|
@@ -1319,7 +487,7 @@ function checkVideoProject(project) {
|
|
|
1319
487
|
if ((asset.kind === "video" || asset.kind === "audio") && asset.duration === void 0)
|
|
1320
488
|
issues.push({ code: "unknown-duration", severity: "warning", asset: asset.id, message: `Asset "${asset.id}" has no duration, so clips of it cannot be checked against its length; set "duration" in ms.` });
|
|
1321
489
|
const checkTrack = (track, sequence) => {
|
|
1322
|
-
const clips = sortedVideoClips(track);
|
|
490
|
+
const clips = _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track);
|
|
1323
491
|
const where = sequence ? ` in sequence "${sequence}"` : "";
|
|
1324
492
|
for (let i = 0; i < clips.length; i++) {
|
|
1325
493
|
const clip = clips[i];
|
|
@@ -1329,13 +497,13 @@ function checkVideoProject(project) {
|
|
|
1329
497
|
const seq = sequences.get(clip.sequence);
|
|
1330
498
|
if (!seq) issues.push({ code: "missing-sequence", severity: "error", ...at, message: `Compound clip "${clip.id}" plays sequence "${clip.sequence}", which is not in the project; add the sequence or delete the clip.` });
|
|
1331
499
|
else {
|
|
1332
|
-
if (!cycles.has(seq.id)) cycles.set(seq.id, findVideoSequenceCycle(project, seq.id));
|
|
500
|
+
if (!cycles.has(seq.id)) cycles.set(seq.id, _chunkSMJGE7HMcjs.findVideoSequenceCycle.call(void 0, project, seq.id));
|
|
1333
501
|
const cycle = cycles.get(seq.id);
|
|
1334
502
|
if (cycle) issues.push({ code: "sequence-cycle", severity: "error", ...at, message: `Compound clip "${clip.id}" plays sequence "${seq.id}", which contains itself (${cycle.join(" \u2192 ")}), so it is left out of the picture and sound; remove the compound clip that closes the loop.` });
|
|
1335
|
-
const length = videoSequenceDuration(seq);
|
|
1336
|
-
const range = videoClipSourceRange(clip);
|
|
1337
|
-
if (range.out > length + VIDEO_TIME_EPSILON)
|
|
1338
|
-
issues.push({ code: "source-overrun", severity: "error", ...at, message: `Compound clip "${clip.id}" plays to ${formatVideoSeconds(range.out)} of sequence "${seq.id}", which is only ${formatVideoSeconds(length)} long; shorten the clip or move its in point.` });
|
|
503
|
+
const length = _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, seq);
|
|
504
|
+
const range = _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, clip);
|
|
505
|
+
if (range.out > length + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
506
|
+
issues.push({ code: "source-overrun", severity: "error", ...at, message: `Compound clip "${clip.id}" plays to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, range.out)} of sequence "${seq.id}", which is only ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, length)} long; shorten the clip or move its in point.` });
|
|
1339
507
|
}
|
|
1340
508
|
} else if (clip.type === "media") {
|
|
1341
509
|
used.add(clip.asset);
|
|
@@ -1344,28 +512,28 @@ function checkVideoProject(project) {
|
|
|
1344
512
|
else {
|
|
1345
513
|
if (track.kind === "audio" && asset.kind === "image") issues.push({ code: "wrong-track", severity: "error", ...at, message: `Clip "${clip.id}" is an image on audio track "${track.id}"; move it to a video track.` });
|
|
1346
514
|
if (track.kind === "video" && asset.kind === "audio") issues.push({ code: "wrong-track", severity: "error", ...at, message: `Clip "${clip.id}" is audio on video track "${track.id}"; move it to an audio track.` });
|
|
1347
|
-
const range = videoClipSourceRange(clip);
|
|
1348
|
-
if (asset.duration !== void 0 && range.out > asset.duration + VIDEO_TIME_EPSILON)
|
|
1349
|
-
issues.push({ code: "source-overrun", severity: "error", ...at, message: `Clip "${clip.id}" plays to ${formatVideoSeconds(range.out)} of "${asset.id}", which is only ${formatVideoSeconds(asset.duration)} long; shorten the clip or move its in point.` });
|
|
515
|
+
const range = _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, clip);
|
|
516
|
+
if (asset.duration !== void 0 && range.out > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
517
|
+
issues.push({ code: "source-overrun", severity: "error", ...at, message: `Clip "${clip.id}" plays to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, range.out)} of "${asset.id}", which is only ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, asset.duration)} long; shorten the clip or move its in point.` });
|
|
1350
518
|
}
|
|
1351
519
|
} else if (track.kind === "audio") issues.push({ code: "wrong-track", severity: "error", ...at, message: `Clip "${clip.id}" is a ${clip.type} clip on audio track "${track.id}"; move it to a video track.` });
|
|
1352
520
|
const next = clips[i + 1];
|
|
1353
|
-
if (next && next.start < videoClipEnd(clip) - VIDEO_TIME_EPSILON)
|
|
1354
|
-
issues.push({ code: "overlap", severity: "error", ...at, message: `Clips "${clip.id}" and "${next.id}" overlap on track "${track.id}"${where} from ${formatVideoSeconds(next.start)}; move one of them.` });
|
|
1355
|
-
if ((_nullishCoalesce(clip.fadeIn, () => ( 0))) + (_nullishCoalesce(clip.fadeOut, () => ( 0))) > clip.duration + VIDEO_TIME_EPSILON)
|
|
521
|
+
if (next && next.start < _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
522
|
+
issues.push({ code: "overlap", severity: "error", ...at, message: `Clips "${clip.id}" and "${next.id}" overlap on track "${track.id}"${where} from ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, next.start)}; move one of them.` });
|
|
523
|
+
if ((_nullishCoalesce(clip.fadeIn, () => ( 0))) + (_nullishCoalesce(clip.fadeOut, () => ( 0))) > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
1356
524
|
issues.push({ code: "fades-too-long", severity: "warning", ...at, message: `Clip "${clip.id}"'s fades (${_nullishCoalesce(clip.fadeIn, () => ( 0))} + ${_nullishCoalesce(clip.fadeOut, () => ( 0))} ms) are longer than the clip (${clip.duration} ms); shorten them.` });
|
|
1357
|
-
const anim = (clip.animateIn ? _nullishCoalesce(clip.animateIn.duration, () => ( VIDEO_CLIP_ANIMATION_DURATION)) : 0) + (clip.animateOut ? _nullishCoalesce(clip.animateOut.duration, () => ( VIDEO_CLIP_ANIMATION_DURATION)) : 0);
|
|
1358
|
-
if (anim > clip.duration + VIDEO_TIME_EPSILON)
|
|
525
|
+
const anim = (clip.animateIn ? _nullishCoalesce(clip.animateIn.duration, () => ( _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0) + (clip.animateOut ? _nullishCoalesce(clip.animateOut.duration, () => ( _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0);
|
|
526
|
+
if (anim > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
1359
527
|
issues.push({ code: "animations-too-long", severity: "warning", ...at, message: `Clip "${clip.id}"'s entrance and exit (${anim} ms together) are longer than the clip (${clip.duration} ms), so both are shortened; give them shorter durations.` });
|
|
1360
528
|
for (const which of ["animateIn", "animateOut"]) {
|
|
1361
529
|
const a = clip[which];
|
|
1362
530
|
if (!a) continue;
|
|
1363
|
-
const keyed = videoClipAnimationProperties(a).filter((p) => videoKeysOf(p === "opacity" ? clip.opacity : _optionalChain([clip, 'access',
|
|
531
|
+
const keyed = _chunkSMJGE7HMcjs.videoClipAnimationProperties.call(void 0, a).filter((p) => _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, p === "opacity" ? clip.opacity : _optionalChain([clip, 'access', _4 => _4.transform, 'optionalAccess', _5 => _5[p]])).length);
|
|
1364
532
|
if (keyed.length)
|
|
1365
533
|
issues.push({ code: "animation-keyed", severity: "note", ...at, message: `Clip "${clip.id}"'s ${a.effect} ${which === "animateIn" ? "entrance" : "exit"} leaves ${keyed.join(", ")} alone, because the clip keys ${keyed.length > 1 ? "them" : "it"} itself; remove those keyframes or the animation.` });
|
|
1366
534
|
}
|
|
1367
535
|
for (const { property, keys } of videoClipKeyframes(clip)) {
|
|
1368
|
-
const outside = keys.filter((k) => k.t < -VIDEO_TIME_EPSILON || k.t > clip.duration + VIDEO_TIME_EPSILON);
|
|
536
|
+
const outside = keys.filter((k) => k.t < -_chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || k.t > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON);
|
|
1369
537
|
if (outside.length)
|
|
1370
538
|
issues.push({
|
|
1371
539
|
code: "keyframes-outside-clip",
|
|
@@ -1376,20 +544,20 @@ function checkVideoProject(project) {
|
|
|
1376
544
|
}
|
|
1377
545
|
if (clip.transition) {
|
|
1378
546
|
const d = clip.transition.duration;
|
|
1379
|
-
const before = videoClipBefore(track, clip);
|
|
547
|
+
const before = _chunkSMJGE7HMcjs.videoClipBefore.call(void 0, track, clip);
|
|
1380
548
|
if (!before) {
|
|
1381
549
|
issues.push({ code: "transition-without-cut", severity: "warning", ...at, message: `Clip "${clip.id}" has a transition but no clip ends where it starts on track "${track.id}", so it plays as nothing; butt a clip up against it or remove the transition.` });
|
|
1382
550
|
continue;
|
|
1383
551
|
}
|
|
1384
|
-
if (d > clip.duration + VIDEO_TIME_EPSILON || d > before.duration + VIDEO_TIME_EPSILON) {
|
|
552
|
+
if (d > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || d > before.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
|
|
1385
553
|
issues.push({ code: "transition-too-long", severity: "error", ...at, message: `The ${d} ms transition into "${clip.id}" is longer than "${clip.id}" (${clip.duration} ms) or "${before.id}" (${before.duration} ms); make it at most ${Math.min(clip.duration, before.duration)} ms.` });
|
|
1386
554
|
continue;
|
|
1387
555
|
}
|
|
1388
556
|
if (clip.transition.type === "dip") continue;
|
|
1389
|
-
const outgoing = videoClipHandles(before, assets, sequences).after;
|
|
1390
|
-
const incoming = videoClipHandles(clip, assets, sequences).before;
|
|
557
|
+
const outgoing = _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, before, assets, sequences).after;
|
|
558
|
+
const incoming = _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, clip, assets, sequences).before;
|
|
1391
559
|
const half = d / 2;
|
|
1392
|
-
if (outgoing < half - VIDEO_TIME_EPSILON || incoming < half - VIDEO_TIME_EPSILON) {
|
|
560
|
+
if (outgoing < half - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || incoming < half - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
|
|
1393
561
|
const fits = 2 * Math.min(outgoing, incoming);
|
|
1394
562
|
issues.push({
|
|
1395
563
|
code: "transition-handles",
|
|
@@ -1406,9 +574,9 @@ function checkVideoProject(project) {
|
|
|
1406
574
|
for (const sequence of _nullishCoalesce(project.sequences, () => ( [])))
|
|
1407
575
|
if (!usedSequences.has(sequence.id)) issues.push({ code: "unused-sequence", severity: "note", sequence: sequence.id, message: `Sequence "${sequence.id}" is not played by any compound clip.` });
|
|
1408
576
|
for (const asset of project.assets) if (!used.has(asset.id)) issues.push({ code: "unused-asset", severity: "note", asset: asset.id, message: `Asset "${asset.id}" is not used by any clip.` });
|
|
1409
|
-
const end = videoProjectDuration(project);
|
|
577
|
+
const end = _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, project);
|
|
1410
578
|
for (const marker of _nullishCoalesce(project.markers, () => ( [])))
|
|
1411
|
-
if (marker.time > end + VIDEO_TIME_EPSILON) issues.push({ code: "marker-past-end", severity: "note", marker: marker.id, message: `Marker "${marker.id}" at ${formatVideoSeconds(marker.time)} is past the end (${formatVideoSeconds(end)}).` });
|
|
579
|
+
if (marker.time > end + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) issues.push({ code: "marker-past-end", severity: "note", marker: marker.id, message: `Marker "${marker.id}" at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, marker.time)} is past the end (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, end)}).` });
|
|
1412
580
|
if (!project.tracks.some((t) => t.clips.length)) issues.push({ code: "empty", severity: "note", message: "The project has no clips yet; add assets and then clips." });
|
|
1413
581
|
const rank = { error: 0, warning: 1, note: 2 };
|
|
1414
582
|
return issues.sort((a, b) => rank[a.severity] - rank[b.severity]);
|
|
@@ -1455,14 +623,14 @@ var refuse = (message) => {
|
|
|
1455
623
|
};
|
|
1456
624
|
function freshId(prefix, taken) {
|
|
1457
625
|
const used = new Set(taken);
|
|
1458
|
-
for (let
|
|
626
|
+
for (let n = 1; ; n++) if (!used.has(`${prefix}${n}`)) return `${prefix}${n}`;
|
|
1459
627
|
}
|
|
1460
628
|
var slug = (s) => s.replace(/^.*[\\/]/, "").replace(/\.[a-z0-9]+(\?.*)?$/i, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 32);
|
|
1461
629
|
function mergeSpans(spans) {
|
|
1462
630
|
const out = [];
|
|
1463
631
|
for (const [from, to] of [...spans].sort((a, b) => a[0] - b[0])) {
|
|
1464
632
|
const last = out[out.length - 1];
|
|
1465
|
-
if (last && from <= last[1] + VIDEO_TIME_EPSILON) last[1] = Math.max(last[1], to);
|
|
633
|
+
if (last && from <= last[1] + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) last[1] = Math.max(last[1], to);
|
|
1466
634
|
else out.push([from, to]);
|
|
1467
635
|
}
|
|
1468
636
|
return out;
|
|
@@ -1476,31 +644,31 @@ function clipAnimatables(clip) {
|
|
|
1476
644
|
// A speed ramp is keys in clip time too, so trims and splits keep it on the same frames of source.
|
|
1477
645
|
{ get: () => c.timeRemap, set: (v) => c.timeRemap = v }
|
|
1478
646
|
];
|
|
1479
|
-
for (const p of VIDEO_TRANSFORM_PROPERTIES) out.push({ get: () => _optionalChain([c, 'access',
|
|
647
|
+
for (const p of _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES) out.push({ get: () => _optionalChain([c, 'access', _6 => _6.transform, 'optionalAccess', _7 => _7[p]]), set: (v) => c.transform && (c.transform[p] = v) });
|
|
1480
648
|
return out;
|
|
1481
649
|
}
|
|
1482
650
|
function retimeClipKeys(clip, fn) {
|
|
1483
651
|
for (const a of clipAnimatables(clip)) {
|
|
1484
652
|
const v = a.get();
|
|
1485
|
-
if (isVideoKeyframes(v)) a.set(fn(v));
|
|
653
|
+
if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, v)) a.set(fn(v));
|
|
1486
654
|
}
|
|
1487
655
|
}
|
|
1488
656
|
var OPTIONAL_CLIP_FIELDS = ["name", "opacity", "transform", "fit", "blend", "grade", "animateIn", "animateOut", "fadeIn", "fadeOut", "fadeInCurve", "fadeOutCurve", "transition", "in", "speed", "timeRemap", "volume", "muted", "color", "fontSize", "fontFamily", "fontWeight", "background"];
|
|
1489
657
|
var TIME_FIELDS = { slip_clip: ["delta"], roll_edit: ["delta"], slide_clip: ["delta"], lift_range: ["from", "to"], extract_range: ["from", "to"], split_at: ["at"] };
|
|
1490
|
-
var Editor = (
|
|
1491
|
-
constructor(p) {;
|
|
658
|
+
var Editor = (_class = class {
|
|
659
|
+
constructor(p) {;_class.prototype.__init.call(this);
|
|
1492
660
|
this.p = p;
|
|
1493
661
|
}
|
|
1494
662
|
|
|
1495
|
-
|
|
663
|
+
__init() {this.outcomes = []}
|
|
1496
664
|
track(id) {
|
|
1497
665
|
const t = this.p.tracks.find((x) => x.id === id);
|
|
1498
666
|
if (!t) refuse(`There is no track ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, this.p.tracks.map((x) => x.id))}; the tracks are ${this.p.tracks.map((x) => `"${x.id}" (${x.kind})`).join(", ") || "none"}.`);
|
|
1499
667
|
return t;
|
|
1500
668
|
}
|
|
1501
669
|
clip(id) {
|
|
1502
|
-
const at = findVideoClip(this.p, id);
|
|
1503
|
-
const nested = at ? null : findVideoSequenceClip(this.p, id);
|
|
670
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, this.p, id);
|
|
671
|
+
const nested = at ? null : _chunkSMJGE7HMcjs.findVideoSequenceClip.call(void 0, this.p, id);
|
|
1504
672
|
if (nested) refuse(`Clip "${id}" is inside sequence "${nested.sequence.id}", and clips inside sequences cannot be edited yet; edit the compound clip that plays the sequence instead (list_video_sequences shows which).`);
|
|
1505
673
|
if (!at) {
|
|
1506
674
|
const ids = this.p.tracks.flatMap((t) => t.clips.map((c) => c.id));
|
|
@@ -1517,10 +685,10 @@ var Editor = (_class2 = class {
|
|
|
1517
685
|
return a;
|
|
1518
686
|
}
|
|
1519
687
|
fits(track, start, duration, ignore, what) {
|
|
1520
|
-
const hit = videoOverlap(track, start, start + duration, ignore);
|
|
688
|
+
const hit = _chunkSMJGE7HMcjs.videoOverlap.call(void 0, track, start, start + duration, ignore);
|
|
1521
689
|
if (hit) {
|
|
1522
|
-
const free = nextFreeVideoSlot(track, start, duration, ignore);
|
|
1523
|
-
refuse(`${what} at ${formatVideoSeconds(start)}\u2013${formatVideoSeconds(start + duration)} would overlap clip "${hit.id}" (${formatVideoSeconds(hit.start)}\u2013${formatVideoSeconds(videoClipEnd(hit))}) on track "${track.id}"; the next free place is ${formatVideoSeconds(free)}, or use mode "insert" to push later clips along or "overwrite" to replace what is there.`);
|
|
690
|
+
const free = _chunkSMJGE7HMcjs.nextFreeVideoSlot.call(void 0, track, start, duration, ignore);
|
|
691
|
+
refuse(`${what} at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, start + duration)} would overlap clip "${hit.id}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, hit))}) on track "${track.id}"; the next free place is ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, free)}, or use mode "insert" to push later clips along or "overwrite" to replace what is there.`);
|
|
1524
692
|
}
|
|
1525
693
|
}
|
|
1526
694
|
kindFits(track, clip) {
|
|
@@ -1531,19 +699,19 @@ var Editor = (_class2 = class {
|
|
|
1531
699
|
return;
|
|
1532
700
|
}
|
|
1533
701
|
if (track.kind === "audio" && (clip.type !== "media" || asset.kind === "image")) refuse(`Track "${track.id}" is an audio track; ${clip.type === "media" ? "images" : `${clip.type} clips`} go on a video track.`);
|
|
1534
|
-
if (track.kind === "video" && _optionalChain([asset, 'optionalAccess',
|
|
702
|
+
if (track.kind === "video" && _optionalChain([asset, 'optionalAccess', _8 => _8.kind]) === "audio") refuse(`Track "${track.id}" is a video track; audio asset "${asset.id}" goes on an audio track.`);
|
|
1535
703
|
}
|
|
1536
704
|
/** Moves every clip on `track` starting at or after `from` by `delta`. */
|
|
1537
705
|
shift(track, from, delta, except = /* @__PURE__ */ new Set()) {
|
|
1538
706
|
if (!delta) return;
|
|
1539
|
-
for (const c of track.clips) if (!except.has(c.id) && c.start >= from - VIDEO_TIME_EPSILON) c.start = Math.max(0, c.start + delta);
|
|
707
|
+
for (const c of track.clips) if (!except.has(c.id) && c.start >= from - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) c.start = Math.max(0, c.start + delta);
|
|
1540
708
|
track.clips.sort((a, b) => a.start - b.start);
|
|
1541
709
|
}
|
|
1542
710
|
get frame() {
|
|
1543
711
|
return 1e3 / this.p.fps;
|
|
1544
712
|
}
|
|
1545
713
|
ids() {
|
|
1546
|
-
return allVideoClipIds(this.p);
|
|
714
|
+
return _chunkSMJGE7HMcjs.allVideoClipIds.call(void 0, this.p);
|
|
1547
715
|
}
|
|
1548
716
|
/**
|
|
1549
717
|
* The tracks a ripple on `sources` moves, top to bottom: the sources, and every unlocked
|
|
@@ -1551,8 +719,8 @@ var Editor = (_class2 = class {
|
|
|
1551
719
|
*/
|
|
1552
720
|
rippleTracks(sources) {
|
|
1553
721
|
const set = new Set(sources);
|
|
1554
|
-
if ([...set].some(videoTrackSyncLocked)) {
|
|
1555
|
-
for (const t of this.p.tracks) if (videoTrackSyncLocked(t) && !t.locked) set.add(t);
|
|
722
|
+
if ([...set].some(_chunkSMJGE7HMcjs.videoTrackSyncLocked)) {
|
|
723
|
+
for (const t of this.p.tracks) if (_chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, t) && !t.locked) set.add(t);
|
|
1556
724
|
}
|
|
1557
725
|
return this.p.tracks.filter((t) => set.has(t));
|
|
1558
726
|
}
|
|
@@ -1569,7 +737,7 @@ var Editor = (_class2 = class {
|
|
|
1569
737
|
return open;
|
|
1570
738
|
}
|
|
1571
739
|
range(from, to) {
|
|
1572
|
-
if (!(to - from > VIDEO_TIME_EPSILON)) refuse(`"to" (${formatVideoSeconds(to)}) must be after "from" (${formatVideoSeconds(from)}).`);
|
|
740
|
+
if (!(to - from > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)) refuse(`"to" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, to)}) must be after "from" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, from)}).`);
|
|
1573
741
|
}
|
|
1574
742
|
/** Moves a media or compound clip's in point by `delta` of timeline time (stills, titles and colours have none). */
|
|
1575
743
|
moveIn(clip, delta) {
|
|
@@ -1578,18 +746,18 @@ var Editor = (_class2 = class {
|
|
|
1578
746
|
if (clip.in < 1e-9) delete clip.in;
|
|
1579
747
|
return;
|
|
1580
748
|
}
|
|
1581
|
-
if (clip.type !== "media" || _optionalChain([videoAssetMap
|
|
1582
|
-
clip.in = Math.max(0, (_nullishCoalesce(clip.in, () => ( 0))) + delta * videoClipSpeed(clip));
|
|
749
|
+
if (clip.type !== "media" || _optionalChain([_chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p), 'access', _9 => _9.get, 'call', _10 => _10(clip.asset), 'optionalAccess', _11 => _11.kind]) === "image") return;
|
|
750
|
+
clip.in = Math.max(0, (_nullishCoalesce(clip.in, () => ( 0))) + delta * _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip));
|
|
1583
751
|
if (clip.in < 1e-9) delete clip.in;
|
|
1584
752
|
}
|
|
1585
753
|
/** Moves a clip's head `delta` later in time (start, in point and keys); the caller sets start and duration. */
|
|
1586
754
|
trimHead(clip, delta) {
|
|
1587
755
|
if (!isRamped(clip)) this.moveIn(clip, delta);
|
|
1588
|
-
retimeClipKeys(clip, (v) => retimeVideoAnimatable(v, -delta));
|
|
756
|
+
retimeClipKeys(clip, (v) => _chunkSMJGE7HMcjs.retimeVideoAnimatable.call(void 0, v, -delta));
|
|
1589
757
|
}
|
|
1590
758
|
/** Cuts `clip` at `at` (inside it): the left part keeps the id, the right part is returned. */
|
|
1591
759
|
cut(track, clip, at, id) {
|
|
1592
|
-
const end = videoClipEnd(clip);
|
|
760
|
+
const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
|
|
1593
761
|
const right = { ...structuredClone(clip), id: _nullishCoalesce(id, () => ( freshId(`${clip.id}-`, this.ids()))), start: at, duration: end - at };
|
|
1594
762
|
delete right.transition;
|
|
1595
763
|
delete right.fadeIn;
|
|
@@ -1597,9 +765,9 @@ var Editor = (_class2 = class {
|
|
|
1597
765
|
delete right.animateIn;
|
|
1598
766
|
const leftValues = clipAnimatables(clip);
|
|
1599
767
|
clipAnimatables(right).forEach((r, i) => {
|
|
1600
|
-
const [l, rr] = splitVideoAnimatable(leftValues[i].get(), at - clip.start);
|
|
1601
|
-
if (isVideoKeyframes(l)) leftValues[i].set(l);
|
|
1602
|
-
if (isVideoKeyframes(rr)) r.set(rr);
|
|
768
|
+
const [l, rr] = _chunkSMJGE7HMcjs.splitVideoAnimatable.call(void 0, leftValues[i].get(), at - clip.start);
|
|
769
|
+
if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, l)) leftValues[i].set(l);
|
|
770
|
+
if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, rr)) r.set(rr);
|
|
1603
771
|
});
|
|
1604
772
|
if (!isRamped(right)) this.moveIn(right, at - clip.start);
|
|
1605
773
|
clip.duration = at - clip.start;
|
|
@@ -1613,7 +781,7 @@ var Editor = (_class2 = class {
|
|
|
1613
781
|
/** Cuts every clip on `tracks` that runs across `at`; returns the new right-hand parts. */
|
|
1614
782
|
cutAcross(tracks, at) {
|
|
1615
783
|
const made = [];
|
|
1616
|
-
for (const t of tracks) for (const c of [...t.clips]) if (c.start < at - VIDEO_TIME_EPSILON && videoClipEnd(c) > at + VIDEO_TIME_EPSILON) made.push(this.cut(t, c, at));
|
|
784
|
+
for (const t of tracks) for (const c of [...t.clips]) if (c.start < at - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c) > at + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) made.push(this.cut(t, c, at));
|
|
1617
785
|
return made;
|
|
1618
786
|
}
|
|
1619
787
|
/**
|
|
@@ -1631,10 +799,10 @@ var Editor = (_class2 = class {
|
|
|
1631
799
|
*/
|
|
1632
800
|
close(tracks, from, to) {
|
|
1633
801
|
for (const t of tracks) {
|
|
1634
|
-
const hit = videoOverlap(t, from, to);
|
|
802
|
+
const hit = _chunkSMJGE7HMcjs.videoOverlap.call(void 0, t, from, to);
|
|
1635
803
|
if (hit)
|
|
1636
804
|
refuse(
|
|
1637
|
-
`Rippling out ${formatVideoSeconds(from)}\u2013${formatVideoSeconds(to)} would pull track "${t.id}" out of sync: clip "${hit.id}" (${formatVideoSeconds(hit.start)}\u2013${formatVideoSeconds(videoClipEnd(hit))}) is in that stretch. Extract the range across "${t.id}" too (extract_range with its id in "tracks"), turn its sync lock off (update_track with syncLocked false) or lock it, or lift instead of rippling.`
|
|
805
|
+
`Rippling out ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, from)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, to)} would pull track "${t.id}" out of sync: clip "${hit.id}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, hit))}) is in that stretch. Extract the range across "${t.id}" too (extract_range with its id in "tracks"), turn its sync lock off (update_track with syncLocked false) or lock it, or lift instead of rippling.`
|
|
1638
806
|
);
|
|
1639
807
|
}
|
|
1640
808
|
for (const t of tracks) this.shift(t, to, from - to);
|
|
@@ -1646,10 +814,10 @@ var Editor = (_class2 = class {
|
|
|
1646
814
|
clear(track, from, to, report) {
|
|
1647
815
|
for (const c of [...track.clips]) {
|
|
1648
816
|
const start = c.start;
|
|
1649
|
-
const end = videoClipEnd(c);
|
|
1650
|
-
if (end <= from + VIDEO_TIME_EPSILON || start >= to - VIDEO_TIME_EPSILON) continue;
|
|
1651
|
-
const coversHead = start >= from - VIDEO_TIME_EPSILON;
|
|
1652
|
-
const coversTail = end <= to + VIDEO_TIME_EPSILON;
|
|
817
|
+
const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c);
|
|
818
|
+
if (end <= from + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || start >= to - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) continue;
|
|
819
|
+
const coversHead = start >= from - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON;
|
|
820
|
+
const coversTail = end <= to + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON;
|
|
1653
821
|
if (coversHead && coversTail) {
|
|
1654
822
|
track.clips = track.clips.filter((x) => x !== c);
|
|
1655
823
|
report.removed.push(c.id);
|
|
@@ -1672,8 +840,8 @@ var Editor = (_class2 = class {
|
|
|
1672
840
|
/** Clamps a slip, roll or slide to `[lo, hi]`, refusing when it cannot move that way at all. */
|
|
1673
841
|
clamp(delta, lo, hi, why) {
|
|
1674
842
|
const applied = Math.min(Math.max(delta, Math.min(0, lo)), Math.max(0, hi));
|
|
1675
|
-
if (Math.abs(delta) > VIDEO_TIME_EPSILON && Math.abs(applied) <= VIDEO_TIME_EPSILON) refuse(why());
|
|
1676
|
-
return Math.abs(applied) <= VIDEO_TIME_EPSILON ? 0 : applied;
|
|
843
|
+
if (Math.abs(delta) > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && Math.abs(applied) <= _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(why());
|
|
844
|
+
return Math.abs(applied) <= _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON ? 0 : applied;
|
|
1677
845
|
}
|
|
1678
846
|
/** Places a clip on a track by `mode`, returning what it cut, trimmed, removed and rippled. */
|
|
1679
847
|
place(track, clip, mode, outcome) {
|
|
@@ -1683,14 +851,14 @@ var Editor = (_class2 = class {
|
|
|
1683
851
|
outcome.rippled = tracks.map((t) => t.id);
|
|
1684
852
|
} else if (mode === "overwrite") {
|
|
1685
853
|
const report = { removed: [], trimmed: [], created: [] };
|
|
1686
|
-
this.clear(track, clip.start, videoClipEnd(clip), report);
|
|
854
|
+
this.clear(track, clip.start, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip), report);
|
|
1687
855
|
Object.assign(outcome, report);
|
|
1688
856
|
} else this.fits(track, clip.start, clip.duration, /* @__PURE__ */ new Set([clip.id]), `Clip "${clip.id}"`);
|
|
1689
857
|
track.clips.push(clip);
|
|
1690
858
|
track.clips.sort((a, b) => a.start - b.start);
|
|
1691
859
|
}
|
|
1692
860
|
placement(mode, ripple) {
|
|
1693
|
-
if (mode !== void 0 && !VIDEO_PLACEMENT_MODES.includes(mode)) refuse(`"mode" must be ${VIDEO_PLACEMENT_MODES.map((m) => `"${m}"`).join(", ")}.`);
|
|
861
|
+
if (mode !== void 0 && !_chunkSMJGE7HMcjs.VIDEO_PLACEMENT_MODES.includes(mode)) refuse(`"mode" must be ${_chunkSMJGE7HMcjs.VIDEO_PLACEMENT_MODES.map((m) => `"${m}"`).join(", ")}.`);
|
|
1694
862
|
if (ripple && mode !== void 0 && mode !== "insert") refuse(`"ripple" means mode "insert", so it cannot go with mode "${mode}"; pass one or the other.`);
|
|
1695
863
|
return _nullishCoalesce(mode, () => ( (ripple ? "insert" : "refuse")));
|
|
1696
864
|
}
|
|
@@ -1727,7 +895,7 @@ var Editor = (_class2 = class {
|
|
|
1727
895
|
}
|
|
1728
896
|
case "remove_asset": {
|
|
1729
897
|
const asset = this.asset(e.asset);
|
|
1730
|
-
const users = allVideoTracks(this.p).flatMap(({ track: t }) => t.clips.filter((c) => c.type === "media" && c.asset === asset.id).map((c) => c.id));
|
|
898
|
+
const users = _chunkSMJGE7HMcjs.allVideoTracks.call(void 0, this.p).flatMap(({ track: t }) => t.clips.filter((c) => c.type === "media" && c.asset === asset.id).map((c) => c.id));
|
|
1731
899
|
if (users.length) refuse(`Asset "${asset.id}" is used by clip${users.length > 1 ? "s" : ""} ${users.map((u) => `"${u}"`).join(", ")}; delete ${users.length > 1 ? "them" : "it"} first.`);
|
|
1732
900
|
this.p.assets = this.p.assets.filter((a) => a !== asset);
|
|
1733
901
|
return this.outcomes.push({ op: e.op, asset: asset.id });
|
|
@@ -1736,8 +904,8 @@ var Editor = (_class2 = class {
|
|
|
1736
904
|
const ids = this.p.tracks.map((t) => t.id);
|
|
1737
905
|
if (e.track.id && ids.includes(e.track.id)) refuse(`There is already a track "${e.track.id}".`);
|
|
1738
906
|
const id = _nullishCoalesce(e.track.id, () => ( freshId(e.track.kind === "video" ? "v" : "a", ids)));
|
|
1739
|
-
const
|
|
1740
|
-
const track = { name: `${e.track.kind === "video" ? "Video" : "Audio"} ${
|
|
907
|
+
const n = this.p.tracks.filter((t) => t.kind === e.track.kind).length + 1;
|
|
908
|
+
const track = { name: `${e.track.kind === "video" ? "Video" : "Audio"} ${n}`, ...e.track, id, clips: [] };
|
|
1741
909
|
const at = _nullishCoalesce(e.at, () => ( (e.track.kind === "video" ? 0 : this.p.tracks.length)));
|
|
1742
910
|
if (at > this.p.tracks.length) refuse(`"at" is ${at} but there are only ${this.p.tracks.length} tracks; use 0\u2013${this.p.tracks.length}.`);
|
|
1743
911
|
this.p.tracks.splice(at, 0, track);
|
|
@@ -1780,12 +948,12 @@ var Editor = (_class2 = class {
|
|
|
1780
948
|
else draft.duration = (asset.duration - (_nullishCoalesce(draft.in, () => ( 0)))) / (_nullishCoalesce(draft.speed, () => ( 1)));
|
|
1781
949
|
if (!(draft.duration > 0)) refuse(`"in" (${draft.in} ms) is at or past the end of "${asset.id}" (${asset.duration} ms).`);
|
|
1782
950
|
} else if (draft.type === "sequence") {
|
|
1783
|
-
const length = videoSequenceDuration(videoSequenceMap(this.p).get(draft.sequence)) - (_nullishCoalesce(draft.in, () => ( 0)));
|
|
951
|
+
const length = _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p).get(draft.sequence)) - (_nullishCoalesce(draft.in, () => ( 0)));
|
|
1784
952
|
if (!(length > 0)) refuse(`"in" (${_nullishCoalesce(draft.in, () => ( 0))} ms) is at or past the end of sequence "${draft.sequence}".`);
|
|
1785
953
|
draft.duration = length;
|
|
1786
954
|
} else draft.duration = VIDEO_DEFAULT_TITLE_DURATION;
|
|
1787
955
|
}
|
|
1788
|
-
const end = sortedVideoClips(track).reduce((m, c) => Math.max(m, videoClipEnd(c)), 0);
|
|
956
|
+
const end = _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track).reduce((m, c) => Math.max(m, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c)), 0);
|
|
1789
957
|
draft.start ??= end;
|
|
1790
958
|
const clip = parseVideoClip(draft, "clip");
|
|
1791
959
|
const outcome = { op: e.op, clip: clip.id, track: track.id };
|
|
@@ -1810,20 +978,20 @@ var Editor = (_class2 = class {
|
|
|
1810
978
|
case "trim_clip": {
|
|
1811
979
|
const { track, clip } = this.clip(e.clip);
|
|
1812
980
|
this.unlocked(track);
|
|
1813
|
-
const speed = videoClipSpeed(clip);
|
|
1814
|
-
const end = videoClipEnd(clip);
|
|
981
|
+
const speed = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip);
|
|
982
|
+
const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
|
|
1815
983
|
const minimum = 1e3 / this.p.fps;
|
|
1816
|
-
const assets = videoAssetMap(this.p);
|
|
984
|
+
const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p);
|
|
1817
985
|
if (e.edge === "start") {
|
|
1818
986
|
const delta = e.to - clip.start;
|
|
1819
|
-
if (clip.duration - delta < minimum - VIDEO_TIME_EPSILON) refuse(`Trimming the start to ${formatVideoSeconds(e.to)} would leave "${clip.id}" shorter than a frame; it ends at ${formatVideoSeconds(end)}.`);
|
|
987
|
+
if (clip.duration - delta < minimum - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the start to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it ends at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, end)}.`);
|
|
1820
988
|
if (clip.type === "media" && !isRamped(clip) || clip.type === "sequence") {
|
|
1821
989
|
const sourceIn = (_nullishCoalesce(clip.in, () => ( 0))) + delta * speed;
|
|
1822
|
-
if (sourceIn < -VIDEO_TIME_EPSILON) refuse(`"${clip.id}" starts ${Math.round((_nullishCoalesce(clip.in, () => ( 0))) / speed)} ms into its source, so its start can move at most that far earlier (to ${formatVideoSeconds(clip.start - (_nullishCoalesce(clip.in, () => ( 0))) / speed)}).`);
|
|
990
|
+
if (sourceIn < -_chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" starts ${Math.round((_nullishCoalesce(clip.in, () => ( 0))) / speed)} ms into its source, so its start can move at most that far earlier (to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start - (_nullishCoalesce(clip.in, () => ( 0))) / speed)}).`);
|
|
1823
991
|
clip.in = Math.max(0, sourceIn);
|
|
1824
992
|
if (clip.in === 0) delete clip.in;
|
|
1825
993
|
}
|
|
1826
|
-
retimeClipKeys(clip, (v) => retimeVideoAnimatable(v, -delta));
|
|
994
|
+
retimeClipKeys(clip, (v) => _chunkSMJGE7HMcjs.retimeVideoAnimatable.call(void 0, v, -delta));
|
|
1827
995
|
if (e.ripple) {
|
|
1828
996
|
const tracks = this.rippleTracks([track]);
|
|
1829
997
|
if (delta > 0) {
|
|
@@ -1844,17 +1012,17 @@ var Editor = (_class2 = class {
|
|
|
1844
1012
|
}
|
|
1845
1013
|
} else {
|
|
1846
1014
|
const duration = e.to - clip.start;
|
|
1847
|
-
if (duration < minimum - VIDEO_TIME_EPSILON) refuse(`Trimming the end to ${formatVideoSeconds(e.to)} would leave "${clip.id}" shorter than a frame; it starts at ${formatVideoSeconds(clip.start)}.`);
|
|
1015
|
+
if (duration < minimum - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the end to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it starts at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start)}.`);
|
|
1848
1016
|
if (clip.type === "media" && !isRamped(clip)) {
|
|
1849
1017
|
const asset = assets.get(clip.asset);
|
|
1850
1018
|
const out = (_nullishCoalesce(clip.in, () => ( 0))) + duration * speed;
|
|
1851
|
-
if (_optionalChain([asset, 'optionalAccess',
|
|
1852
|
-
refuse(`"${clip.id}" can end at most at ${formatVideoSeconds(clip.start + (asset.duration - (_nullishCoalesce(clip.in, () => ( 0)))) / speed)}, where "${asset.id}" runs out.`);
|
|
1019
|
+
if (_optionalChain([asset, 'optionalAccess', _12 => _12.duration]) !== void 0 && out > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
1020
|
+
refuse(`"${clip.id}" can end at most at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start + (asset.duration - (_nullishCoalesce(clip.in, () => ( 0)))) / speed)}, where "${asset.id}" runs out.`);
|
|
1853
1021
|
}
|
|
1854
1022
|
if (clip.type === "sequence") {
|
|
1855
|
-
const seq = videoSequenceMap(this.p).get(clip.sequence);
|
|
1856
|
-
const length = seq ? videoSequenceDuration(seq) : Infinity;
|
|
1857
|
-
if ((_nullishCoalesce(clip.in, () => ( 0))) + duration > length + VIDEO_TIME_EPSILON) refuse(`"${clip.id}" can end at most at ${formatVideoSeconds(clip.start + length - (_nullishCoalesce(clip.in, () => ( 0))))}, where sequence "${clip.sequence}" ends.`);
|
|
1023
|
+
const seq = _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p).get(clip.sequence);
|
|
1024
|
+
const length = seq ? _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, seq) : Infinity;
|
|
1025
|
+
if ((_nullishCoalesce(clip.in, () => ( 0))) + duration > length + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" can end at most at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start + length - (_nullishCoalesce(clip.in, () => ( 0))))}, where sequence "${clip.sequence}" ends.`);
|
|
1858
1026
|
}
|
|
1859
1027
|
if (e.ripple) {
|
|
1860
1028
|
const tracks = this.rippleTracks([track]);
|
|
@@ -1876,9 +1044,9 @@ var Editor = (_class2 = class {
|
|
|
1876
1044
|
case "split_clip": {
|
|
1877
1045
|
const { track, clip } = this.clip(e.clip);
|
|
1878
1046
|
this.unlocked(track);
|
|
1879
|
-
const end = videoClipEnd(clip);
|
|
1047
|
+
const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
|
|
1880
1048
|
const minimum = 1e3 / this.p.fps;
|
|
1881
|
-
if (e.at < clip.start + minimum - VIDEO_TIME_EPSILON || e.at > end - minimum + VIDEO_TIME_EPSILON) refuse(`${formatVideoSeconds(e.at)} is not inside "${clip.id}" (${formatVideoSeconds(clip.start)}\u2013${formatVideoSeconds(end)}), at least a frame from either end.`);
|
|
1049
|
+
if (e.at < clip.start + minimum - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || e.at > end - minimum + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, e.at)} is not inside "${clip.id}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, end)}), at least a frame from either end.`);
|
|
1882
1050
|
if (e.id !== void 0 && this.ids().includes(e.id)) refuse(`There is already a clip "${e.id}".`);
|
|
1883
1051
|
const right = this.cut(track, clip, e.at, e.id);
|
|
1884
1052
|
return this.outcomes.push({ op: e.op, clips: [clip.id, right.id], clip: right.id, track: track.id });
|
|
@@ -1889,12 +1057,12 @@ var Editor = (_class2 = class {
|
|
|
1889
1057
|
for (const track of new Set(found.map((f) => f.track))) track.clips = track.clips.filter((c) => !found.some((f) => f.clip === c));
|
|
1890
1058
|
if (!e.ripple) return this.outcomes.push({ op: e.op, clips: found.map((f) => f.clip.id) });
|
|
1891
1059
|
const rippled = /* @__PURE__ */ new Set();
|
|
1892
|
-
const groups = [...new Set(found.map((f) => f.track))].filter((t) => !videoTrackSyncLocked(t)).map((t) => [t]);
|
|
1893
|
-
if (found.some((f) => videoTrackSyncLocked(f.track))) groups.push(found.filter((f) => videoTrackSyncLocked(f.track)).map((f) => f.track));
|
|
1060
|
+
const groups = [...new Set(found.map((f) => f.track))].filter((t) => !_chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, t)).map((t) => [t]);
|
|
1061
|
+
if (found.some((f) => _chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, f.track))) groups.push(found.filter((f) => _chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, f.track)).map((f) => f.track));
|
|
1894
1062
|
for (const sources of groups) {
|
|
1895
1063
|
const tracks = this.rippleTracks(sources);
|
|
1896
1064
|
tracks.forEach((t) => rippled.add(t));
|
|
1897
|
-
const spans = mergeSpans(found.filter((f) => sources.includes(f.track)).map((f) => [f.clip.start, videoClipEnd(f.clip)]));
|
|
1065
|
+
const spans = mergeSpans(found.filter((f) => sources.includes(f.track)).map((f) => [f.clip.start, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, f.clip)]));
|
|
1898
1066
|
for (const [from, to] of spans.reverse()) this.close(tracks, from, to);
|
|
1899
1067
|
}
|
|
1900
1068
|
return this.outcomes.push({ op: e.op, clips: found.map((f) => f.clip.id), rippled: this.p.tracks.filter((t) => rippled.has(t)).map((t) => t.id) });
|
|
@@ -1910,15 +1078,15 @@ var Editor = (_class2 = class {
|
|
|
1910
1078
|
if ("timeRemap" in set) refuse("Set a speed ramp with set_time_remap, which checks it against the media and moves later clips if asked.");
|
|
1911
1079
|
let stretch = 1;
|
|
1912
1080
|
if (at.clip.type === "media" && !("duration" in set)) {
|
|
1913
|
-
const was = videoClipSpeed(at.clip);
|
|
1914
|
-
const now = "speed" in set ? set.speed : _optionalChain([e, 'access',
|
|
1081
|
+
const was = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, at.clip);
|
|
1082
|
+
const now = "speed" in set ? set.speed : _optionalChain([e, 'access', _13 => _13.remove, 'optionalAccess', _14 => _14.includes, 'call', _15 => _15("speed")]) ? 1 : was;
|
|
1915
1083
|
if (now !== was) {
|
|
1916
1084
|
set.duration = at.clip.duration * was / now;
|
|
1917
1085
|
stretch = was / now;
|
|
1918
1086
|
}
|
|
1919
1087
|
}
|
|
1920
1088
|
const next = { ...structuredClone(at.clip), ...set };
|
|
1921
|
-
if (stretch !== 1) retimeClipKeys(next, (v) => retimeVideoAnimatable(v, 0, stretch));
|
|
1089
|
+
if (stretch !== 1) retimeClipKeys(next, (v) => _chunkSMJGE7HMcjs.retimeVideoAnimatable.call(void 0, v, 0, stretch));
|
|
1922
1090
|
for (const k of _nullishCoalesce(e.remove, () => ( []))) delete next[k];
|
|
1923
1091
|
const clip = parseVideoClip(next, "set");
|
|
1924
1092
|
if (clip.type === "media" && clip.asset !== at.clip.asset) this.kindFits(at.track, clip);
|
|
@@ -1935,13 +1103,13 @@ var Editor = (_class2 = class {
|
|
|
1935
1103
|
const asset = this.asset(clip.asset);
|
|
1936
1104
|
if (asset.kind === "image") refuse(`Clip "${clip.id}" is a still ("${asset.id}"), so it has no motion to ramp.`);
|
|
1937
1105
|
const media = clip;
|
|
1938
|
-
const end = videoClipEnd(media);
|
|
1106
|
+
const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, media);
|
|
1939
1107
|
const duration = _nullishCoalesce(e.duration, () => ( media.duration));
|
|
1940
|
-
if (!(duration >= 1e3 / this.p.fps - VIDEO_TIME_EPSILON)) refuse(`"duration" must be at least a frame (${Math.ceil(1e3 / this.p.fps)} ms).`);
|
|
1108
|
+
if (!(duration >= 1e3 / this.p.fps - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)) refuse(`"duration" must be at least a frame (${Math.ceil(1e3 / this.p.fps)} ms).`);
|
|
1941
1109
|
if (e.keys === null) {
|
|
1942
1110
|
if (!media.timeRemap) refuse(`Clip "${clip.id}" has no speed ramp to remove.`);
|
|
1943
1111
|
const from = (_nullishCoalesce(media.in, () => ( 0))) + media.timeRemap.keys[0].v;
|
|
1944
|
-
if (asset.duration !== void 0 && from + duration > asset.duration + VIDEO_TIME_EPSILON)
|
|
1112
|
+
if (asset.duration !== void 0 && from + duration > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
1945
1113
|
refuse(`At normal speed from ${Math.round(from)} ms, "${clip.id}" would run past the end of "${asset.id}" (${asset.duration} ms); give a duration of at most ${Math.floor(asset.duration - from)} ms.`);
|
|
1946
1114
|
delete media.timeRemap;
|
|
1947
1115
|
media.in = from;
|
|
@@ -1949,17 +1117,17 @@ var Editor = (_class2 = class {
|
|
|
1949
1117
|
} else {
|
|
1950
1118
|
if (!Array.isArray(e.keys) || !e.keys.length) refuse('"keys" must be a list of at least one { t, v, ease } (or null to remove the ramp).');
|
|
1951
1119
|
const remap = parseVideoTimeRemap({ keys: e.keys }, void 0, "keys");
|
|
1952
|
-
remap.keys = sortVideoKeys(remap.keys);
|
|
1953
|
-
checkVideoTimeRemap(remap, "keys");
|
|
1954
|
-
const span = videoTimeRemapSpan(remap);
|
|
1955
|
-
if (asset.duration !== void 0 && (_nullishCoalesce(media.in, () => ( 0))) + span.to > asset.duration + VIDEO_TIME_EPSILON)
|
|
1120
|
+
remap.keys = _chunkSMJGE7HMcjs.sortVideoKeys.call(void 0, remap.keys);
|
|
1121
|
+
_chunkSMJGE7HMcjs.checkVideoTimeRemap.call(void 0, remap, "keys");
|
|
1122
|
+
const span = _chunkSMJGE7HMcjs.videoTimeRemapSpan.call(void 0, remap);
|
|
1123
|
+
if (asset.duration !== void 0 && (_nullishCoalesce(media.in, () => ( 0))) + span.to > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
|
|
1956
1124
|
refuse(`The ramp plays ${Math.round(span.to)} ms of source from the in point (${_nullishCoalesce(media.in, () => ( 0))} ms), past the end of "${asset.id}" (${asset.duration} ms); it can use at most ${Math.floor(asset.duration - (_nullishCoalesce(media.in, () => ( 0))))} ms.`);
|
|
1957
1125
|
media.timeRemap = remap;
|
|
1958
1126
|
delete media.speed;
|
|
1959
1127
|
}
|
|
1960
1128
|
const newEnd = media.start + duration;
|
|
1961
1129
|
const outcome = { op: e.op, clip: clip.id, track: track.id };
|
|
1962
|
-
if (Math.abs(newEnd - end) > VIDEO_TIME_EPSILON) {
|
|
1130
|
+
if (Math.abs(newEnd - end) > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
|
|
1963
1131
|
if (e.ripple) {
|
|
1964
1132
|
const tracks = this.rippleTracks([track]);
|
|
1965
1133
|
if (newEnd < end) {
|
|
@@ -1991,8 +1159,8 @@ var Editor = (_class2 = class {
|
|
|
1991
1159
|
if (clip.type !== "media" && clip.type !== "sequence") refuse(`Clip "${clip.id}" is a ${clip.type === "text" ? "title" : "colour"}, so it has no source to slip; only video, audio and compound clips slip.`);
|
|
1992
1160
|
const source = clip.type === "sequence" ? `sequence "${clip.sequence}"` : `"${this.asset(clip.asset).id}"`;
|
|
1993
1161
|
if (clip.type === "media" && this.asset(clip.asset).kind === "image") refuse(`Clip "${clip.id}" is a still ("${clip.asset}"), so it has no source to slip; only video and audio clips slip.`);
|
|
1994
|
-
const handles = videoClipHandles(clip, videoAssetMap(this.p), videoSequenceMap(this.p));
|
|
1995
|
-
const { lead, tail } = videoClipOverhang(track, clip);
|
|
1162
|
+
const handles = _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, clip, _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p), _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p));
|
|
1163
|
+
const { lead, tail } = _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, clip);
|
|
1996
1164
|
const delta = this.clamp(
|
|
1997
1165
|
e.delta,
|
|
1998
1166
|
lead - handles.before,
|
|
@@ -2010,13 +1178,13 @@ var Editor = (_class2 = class {
|
|
|
2010
1178
|
this.unlocked(track);
|
|
2011
1179
|
const L = left.clip;
|
|
2012
1180
|
const R = right.clip;
|
|
2013
|
-
if (Math.abs(videoClipEnd(L) - R.start) > VIDEO_TIME_EPSILON) {
|
|
2014
|
-
if (Math.abs(videoClipEnd(R) - L.start) <= VIDEO_TIME_EPSILON) refuse(`"${R.id}" comes before "${L.id}"; pass left "${R.id}" and right "${L.id}".`);
|
|
2015
|
-
refuse(`"${L.id}" ends at ${formatVideoSeconds(videoClipEnd(L))} but "${R.id}" starts at ${formatVideoSeconds(R.start)}; a roll needs two clips that meet at a cut (use trim_clip to move one edge).`);
|
|
1181
|
+
if (Math.abs(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, L) - R.start) > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
|
|
1182
|
+
if (Math.abs(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, R) - L.start) <= _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`"${R.id}" comes before "${L.id}"; pass left "${R.id}" and right "${L.id}".`);
|
|
1183
|
+
refuse(`"${L.id}" ends at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, L))} but "${R.id}" starts at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, R.start)}; a roll needs two clips that meet at a cut (use trim_clip to move one edge).`);
|
|
2016
1184
|
}
|
|
2017
|
-
const assets = videoAssetMap(this.p);
|
|
2018
|
-
const lo = Math.max(-(L.duration - this.frame), -(videoClipHandles(R, assets, videoSequenceMap(this.p)).before - videoClipOverhang(track, R).lead));
|
|
2019
|
-
const hi = Math.min(R.duration - this.frame, videoClipHandles(L, assets, videoSequenceMap(this.p)).after - videoClipOverhang(track, L).tail);
|
|
1185
|
+
const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p);
|
|
1186
|
+
const lo = Math.max(-(L.duration - this.frame), -(_chunkSMJGE7HMcjs.videoClipHandles.call(void 0, R, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).before - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, R).lead));
|
|
1187
|
+
const hi = Math.min(R.duration - this.frame, _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, L, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).after - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, L).tail);
|
|
2020
1188
|
const delta = this.clamp(
|
|
2021
1189
|
e.delta,
|
|
2022
1190
|
lo,
|
|
@@ -2032,18 +1200,18 @@ var Editor = (_class2 = class {
|
|
|
2032
1200
|
case "slide_clip": {
|
|
2033
1201
|
const { track, clip } = this.clip(e.clip);
|
|
2034
1202
|
this.unlocked(track);
|
|
2035
|
-
const before = videoClipBefore(track, clip);
|
|
2036
|
-
const after = videoClipAfter(track, clip);
|
|
1203
|
+
const before = _chunkSMJGE7HMcjs.videoClipBefore.call(void 0, track, clip);
|
|
1204
|
+
const after = _chunkSMJGE7HMcjs.videoClipAfter.call(void 0, track, clip);
|
|
2037
1205
|
if (!before && !after) refuse(`"${clip.id}" has no clip right before or after it on track "${track.id}", so there is nothing to slide against; use move_clip.`);
|
|
2038
|
-
const assets = videoAssetMap(this.p);
|
|
2039
|
-
const end = videoClipEnd(clip);
|
|
1206
|
+
const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p);
|
|
1207
|
+
const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
|
|
2040
1208
|
const others = track.clips.filter((c) => c !== clip);
|
|
2041
1209
|
const room = {
|
|
2042
|
-
earlier: before ? before.duration - this.frame : clip.start - others.filter((c) => videoClipEnd(c) <= clip.start + VIDEO_TIME_EPSILON).reduce((m, c) => Math.max(m, videoClipEnd(c)), 0),
|
|
2043
|
-
later: after ? after.duration - this.frame : others.filter((c) => c.start >= end - VIDEO_TIME_EPSILON).reduce((m, c) => Math.min(m, c.start - end), Infinity)
|
|
1210
|
+
earlier: before ? before.duration - this.frame : clip.start - others.filter((c) => _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c) <= clip.start + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.max(m, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c)), 0),
|
|
1211
|
+
later: after ? after.duration - this.frame : others.filter((c) => c.start >= end - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.min(m, c.start - end), Infinity)
|
|
2044
1212
|
};
|
|
2045
|
-
const lo = -Math.min(room.earlier, after ? videoClipHandles(after, assets, videoSequenceMap(this.p)).before - videoClipOverhang(track, after).lead : Infinity);
|
|
2046
|
-
const hi = Math.min(room.later, before ? videoClipHandles(before, assets, videoSequenceMap(this.p)).after - videoClipOverhang(track, before).tail : Infinity);
|
|
1213
|
+
const lo = -Math.min(room.earlier, after ? _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, after, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).before - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, after).lead : Infinity);
|
|
1214
|
+
const hi = Math.min(room.later, before ? _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, before, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).after - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, before).tail : Infinity);
|
|
2047
1215
|
const delta = this.clamp(
|
|
2048
1216
|
e.delta,
|
|
2049
1217
|
lo,
|
|
@@ -2058,7 +1226,7 @@ var Editor = (_class2 = class {
|
|
|
2058
1226
|
this.trimHead(after, delta);
|
|
2059
1227
|
}
|
|
2060
1228
|
track.clips.sort((a, b) => a.start - b.start);
|
|
2061
|
-
return this.outcomes.push({ op: e.op, clip: clip.id, clips: [_optionalChain([before, 'optionalAccess',
|
|
1229
|
+
return this.outcomes.push({ op: e.op, clip: clip.id, clips: [_optionalChain([before, 'optionalAccess', _16 => _16.id]), clip.id, _optionalChain([after, 'optionalAccess', _17 => _17.id])].filter((x) => !!x), track: track.id, delta });
|
|
2062
1230
|
}
|
|
2063
1231
|
case "lift_range":
|
|
2064
1232
|
case "extract_range": {
|
|
@@ -2076,29 +1244,29 @@ var Editor = (_class2 = class {
|
|
|
2076
1244
|
}
|
|
2077
1245
|
case "split_at": {
|
|
2078
1246
|
const tracks = this.rangeTracks(e.tracks);
|
|
2079
|
-
const lefts = tracks.flatMap((t) => t.clips.filter((c) => c.start < e.at - VIDEO_TIME_EPSILON && videoClipEnd(c) > e.at + VIDEO_TIME_EPSILON).map((c) => c.id));
|
|
2080
|
-
if (!lefts.length) refuse(`No clip runs across ${formatVideoSeconds(e.at)} on ${e.tracks ? `track${tracks.length > 1 ? "s" : ""} ${tracks.map((t) => `"${t.id}"`).join(", ")}` : "the unlocked tracks"}, so there is nothing to split there.`);
|
|
1247
|
+
const lefts = tracks.flatMap((t) => t.clips.filter((c) => c.start < e.at - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c) > e.at + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).map((c) => c.id));
|
|
1248
|
+
if (!lefts.length) refuse(`No clip runs across ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, e.at)} on ${e.tracks ? `track${tracks.length > 1 ? "s" : ""} ${tracks.map((t) => `"${t.id}"`).join(", ")}` : "the unlocked tracks"}, so there is nothing to split there.`);
|
|
2081
1249
|
const created = this.cutAcross(tracks, e.at).map((c) => c.id);
|
|
2082
1250
|
return this.outcomes.push({ op: e.op, clips: lefts, created });
|
|
2083
1251
|
}
|
|
2084
1252
|
case "set_keyframes": {
|
|
2085
1253
|
const { track, clip } = this.clip(e.clip);
|
|
2086
1254
|
this.unlocked(track);
|
|
2087
|
-
if (!VIDEO_KEYFRAME_PROPERTIES.includes(e.property)) refuse(`"${e.property}" cannot be keyframed; use one of ${VIDEO_KEYFRAME_PROPERTIES.join(", ")}.`);
|
|
1255
|
+
if (!_chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES.includes(e.property)) refuse(`"${e.property}" cannot be keyframed; use one of ${_chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES.join(", ")}.`);
|
|
2088
1256
|
if (e.property === "volume" && clip.type !== "media" && clip.type !== "sequence") refuse(`Clip "${clip.id}" is a ${clip.type} clip and has no volume; volume keys go on media and compound clips.`);
|
|
2089
|
-
const limits = VIDEO_KEYFRAME_LIMITS[e.property];
|
|
2090
|
-
const transform = VIDEO_TRANSFORM_PROPERTIES.includes(e.property);
|
|
1257
|
+
const limits = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[e.property];
|
|
1258
|
+
const transform = _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(e.property);
|
|
2091
1259
|
const c = clip;
|
|
2092
|
-
const current = transform ? _optionalChain([c, 'access',
|
|
1260
|
+
const current = transform ? _optionalChain([c, 'access', _18 => _18.transform, 'optionalAccess', _19 => _19[e.property]]) : c[e.property];
|
|
2093
1261
|
let value;
|
|
2094
1262
|
if (e.keys === null) {
|
|
2095
|
-
const v = videoValueAt(current, 0, limits.default);
|
|
2096
|
-
value = isVideoKeyframes(current) ? v === limits.default ? void 0 : v : current;
|
|
1263
|
+
const v = _chunkSMJGE7HMcjs.videoValueAt.call(void 0, current, 0, limits.default);
|
|
1264
|
+
value = _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, current) ? v === limits.default ? void 0 : v : current;
|
|
2097
1265
|
} else {
|
|
2098
1266
|
if (!Array.isArray(e.keys) || !e.keys.length) refuse('"keys" must list at least one key { t, v }; pass null to remove the keyframes.');
|
|
2099
1267
|
let sorted = [];
|
|
2100
1268
|
try {
|
|
2101
|
-
sorted = sortVideoKeys(e.keys);
|
|
1269
|
+
sorted = _chunkSMJGE7HMcjs.sortVideoKeys.call(void 0, e.keys);
|
|
2102
1270
|
} catch (error) {
|
|
2103
1271
|
refuse(error.message);
|
|
2104
1272
|
}
|
|
@@ -2117,12 +1285,12 @@ var Editor = (_class2 = class {
|
|
|
2117
1285
|
this.unlocked(track);
|
|
2118
1286
|
let at = 0;
|
|
2119
1287
|
const moved = [];
|
|
2120
|
-
for (const clip of sortedVideoClips(track)) {
|
|
2121
|
-
if (clip.start >= (_nullishCoalesce(e.from, () => ( 0))) - VIDEO_TIME_EPSILON && clip.start > at + VIDEO_TIME_EPSILON) {
|
|
1288
|
+
for (const clip of _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track)) {
|
|
1289
|
+
if (clip.start >= (_nullishCoalesce(e.from, () => ( 0))) - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && clip.start > at + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
|
|
2122
1290
|
clip.start = Math.max(at, _nullishCoalesce(e.from, () => ( 0)));
|
|
2123
1291
|
moved.push(clip.id);
|
|
2124
1292
|
}
|
|
2125
|
-
at = Math.max(at, videoClipEnd(clip));
|
|
1293
|
+
at = Math.max(at, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip));
|
|
2126
1294
|
}
|
|
2127
1295
|
return this.outcomes.push({ op: e.op, track: track.id, clips: moved });
|
|
2128
1296
|
}
|
|
@@ -2160,7 +1328,7 @@ var Editor = (_class2 = class {
|
|
|
2160
1328
|
refuse(`Unknown op ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, String(e.op), VIDEO_EDIT_OPS)}; the ops are ${VIDEO_EDIT_OPS.join(", ")}.`);
|
|
2161
1329
|
}
|
|
2162
1330
|
}
|
|
2163
|
-
},
|
|
1331
|
+
}, _class);
|
|
2164
1332
|
function applyVideoEdits(project, edits) {
|
|
2165
1333
|
const list = Array.isArray(edits) ? edits : [edits];
|
|
2166
1334
|
if (!list.length) return { ok: true, project, issues: checkVideoProject(project), outcomes: [] };
|
|
@@ -2171,7 +1339,7 @@ function applyVideoEdits(project, edits) {
|
|
|
2171
1339
|
editor.run(edit);
|
|
2172
1340
|
} catch (error) {
|
|
2173
1341
|
const message = error.message;
|
|
2174
|
-
return { ok: false, error: `${list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess',
|
|
1342
|
+
return { ok: false, error: `${list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _20 => _20.op])}): ` : ""}${message}${/Nothing was changed\.$/.test(message) ? "" : " Nothing was changed."}` };
|
|
2175
1343
|
}
|
|
2176
1344
|
}
|
|
2177
1345
|
let next;
|
|
@@ -2188,169 +1356,11 @@ function applyVideoEdits(project, edits) {
|
|
|
2188
1356
|
return { ok: true, project: next, issues, outcomes: editor.outcomes };
|
|
2189
1357
|
}
|
|
2190
1358
|
|
|
2191
|
-
// src/video-editor/evaluate.ts
|
|
2192
|
-
function videoTransformAt(transform, clipTime = 0) {
|
|
2193
|
-
return { x: videoValueAt(_optionalChain([transform, 'optionalAccess', _34 => _34.x]), clipTime, 0), y: videoValueAt(_optionalChain([transform, 'optionalAccess', _35 => _35.y]), clipTime, 0), scale: videoValueAt(_optionalChain([transform, 'optionalAccess', _36 => _36.scale]), clipTime, 1), rotation: videoValueAt(_optionalChain([transform, 'optionalAccess', _37 => _37.rotation]), clipTime, 0) };
|
|
2194
|
-
}
|
|
2195
|
-
function placeVideoRect(frame, size, fit = "contain", transform = {}, clipTime = 0) {
|
|
2196
|
-
let w = size.width;
|
|
2197
|
-
let h = size.height;
|
|
2198
|
-
if (fit === "fill") {
|
|
2199
|
-
w = frame.width;
|
|
2200
|
-
h = frame.height;
|
|
2201
|
-
} else if (fit !== "none") {
|
|
2202
|
-
const k = fit === "cover" ? Math.max(frame.width / w, frame.height / h) : Math.min(frame.width / w, frame.height / h);
|
|
2203
|
-
w *= k;
|
|
2204
|
-
h *= k;
|
|
2205
|
-
}
|
|
2206
|
-
const t = videoTransformAt(transform, clipTime);
|
|
2207
|
-
w *= t.scale;
|
|
2208
|
-
h *= t.scale;
|
|
2209
|
-
const cx = frame.width / 2 + t.x;
|
|
2210
|
-
const cy = frame.height / 2 + t.y;
|
|
2211
|
-
return { x: cx - w / 2, y: cy - h / 2, width: w, height: h };
|
|
2212
|
-
}
|
|
2213
|
-
function videoTextStyle(clip) {
|
|
2214
|
-
return { text: clip.text, color: _nullishCoalesce(clip.color, () => ( "#ffffff")), fontSize: _nullishCoalesce(clip.fontSize, () => ( 64)), fontFamily: _nullishCoalesce(clip.fontFamily, () => ( "sans-serif")), fontWeight: _nullishCoalesce(clip.fontWeight, () => ( 700)), ...clip.background ? { background: clip.background } : {} };
|
|
2215
|
-
}
|
|
2216
|
-
function videoTitleFrame(project, clip, clipTime = 0) {
|
|
2217
|
-
const layer = { clip: clip.id, track: "", type: "text", opacity: 1, rect: placeVideoRect(project, project, "fill", clip.transform, clipTime), rotation: videoTransformAt(clip.transform, clipTime).rotation, text: videoTextStyle(clip) };
|
|
2218
|
-
return { time: clip.start, width: project.width, height: project.height, background: "rgba(0,0,0,0)", layers: [layer], audio: [] };
|
|
2219
|
-
}
|
|
2220
|
-
var clamp012 = (v) => Math.min(1, Math.max(0, v));
|
|
2221
|
-
var videoTransitionEase = (progress) => (1 - Math.cos(Math.PI * clamp012(progress))) / 2;
|
|
2222
|
-
function videoFadeCurveGain(curve, x) {
|
|
2223
|
-
const t = clamp012(x);
|
|
2224
|
-
switch (curve) {
|
|
2225
|
-
case "equal-power":
|
|
2226
|
-
return Math.sin(t * Math.PI / 2);
|
|
2227
|
-
case "s-curve":
|
|
2228
|
-
return (1 - Math.cos(t * Math.PI)) / 2;
|
|
2229
|
-
case "exponential":
|
|
2230
|
-
return t * t * t;
|
|
2231
|
-
case "logarithmic":
|
|
2232
|
-
return 1 - (1 - t) * (1 - t);
|
|
2233
|
-
default:
|
|
2234
|
-
return t;
|
|
2235
|
-
}
|
|
2236
|
-
}
|
|
2237
|
-
function fadeGain(clip, time, sound = false) {
|
|
2238
|
-
let g = 1;
|
|
2239
|
-
const shape = sound && (clip.type === "media" || clip.type === "sequence") ? clip : void 0;
|
|
2240
|
-
if (clip.fadeIn) g *= videoFadeCurveGain(_optionalChain([shape, 'optionalAccess', _38 => _38.fadeInCurve]), (time - clip.start) / clip.fadeIn);
|
|
2241
|
-
if (clip.fadeOut) g *= videoFadeCurveGain(_optionalChain([shape, 'optionalAccess', _39 => _39.fadeOutCurve]), (videoClipEnd(clip) - time) / clip.fadeOut);
|
|
2242
|
-
return g;
|
|
2243
|
-
}
|
|
2244
|
-
function videoClipSoundGain(clip, clipTime) {
|
|
2245
|
-
const volume = clip.type === "media" || clip.type === "sequence" ? videoValueAt(clip.volume, clipTime, 1) : 1;
|
|
2246
|
-
return volume * fadeGain(clip, clip.start + Math.min(Math.max(clipTime, 0), clip.duration), true);
|
|
2247
|
-
}
|
|
2248
|
-
function activeOnTrack(track, time) {
|
|
2249
|
-
const out = [];
|
|
2250
|
-
for (const clip of sortedVideoClips(track)) {
|
|
2251
|
-
const before = clip.transition ? videoClipBefore(track, clip) : null;
|
|
2252
|
-
const lead = before ? clip.transition.duration / 2 : 0;
|
|
2253
|
-
const next = videoClipAfter(track, clip);
|
|
2254
|
-
const tail = _optionalChain([next, 'optionalAccess', _40 => _40.transition]) ? next.transition.duration / 2 : 0;
|
|
2255
|
-
if (time < clip.start - lead || time >= videoClipEnd(clip) + tail) continue;
|
|
2256
|
-
const a = { clip };
|
|
2257
|
-
if (lead && time < clip.start + lead) a.incoming = { progress: clamp012((time - (clip.start - lead)) / (2 * lead)), type: clip.transition.type, transition: clip.transition };
|
|
2258
|
-
if (tail && time >= videoClipEnd(clip) - tail) a.outgoing = { progress: clamp012((time - (videoClipEnd(clip) - tail)) / (2 * tail)), type: next.transition.type, next };
|
|
2259
|
-
out.push(a);
|
|
2260
|
-
}
|
|
2261
|
-
return out;
|
|
2262
|
-
}
|
|
2263
|
-
var sourceTimeAt = (clip, time) => clip.type === "media" ? videoClipSourceTime(clip, time - clip.start) : 0;
|
|
2264
|
-
function videoFrameAt(project, time) {
|
|
2265
|
-
const { layers, audio } = tracksAt(project, project.tracks, time, { assets: videoAssetMap(project), sequences: videoSequenceMap(project), within: [], prefix: "" });
|
|
2266
|
-
return { time, width: project.width, height: project.height, background: _nullishCoalesce(project.background, () => ( "#000000")), layers, audio };
|
|
2267
|
-
}
|
|
2268
|
-
function tracksAt(project, tracks, time, scope) {
|
|
2269
|
-
const { assets, prefix } = scope;
|
|
2270
|
-
const layers = [];
|
|
2271
|
-
const audio = [];
|
|
2272
|
-
for (let ti = tracks.length - 1; ti >= 0; ti--) {
|
|
2273
|
-
const track = tracks[ti];
|
|
2274
|
-
for (const { clip, incoming, outgoing } of activeOnTrack(track, time)) {
|
|
2275
|
-
if (_optionalChain([incoming, 'optionalAccess', _41 => _41.type]) === "dip" && incoming.progress < 0.5) continue;
|
|
2276
|
-
if (_optionalChain([outgoing, 'optionalAccess', _42 => _42.type]) === "dip" && outgoing.progress >= 0.5) continue;
|
|
2277
|
-
const inside = Math.min(Math.max(time, clip.start), videoClipEnd(clip));
|
|
2278
|
-
const fade = fadeGain(clip, inside);
|
|
2279
|
-
const level = (t, transition, into) => videoFadeCurveGain(videoTransitionAudioCurve(transition), t.type === "dip" ? Math.abs(1 - 2 * t.progress) : into ? t.progress : 1 - t.progress);
|
|
2280
|
-
const mix = (incoming ? level(incoming, incoming.transition, true) : 1) * (outgoing ? level(outgoing, outgoing.next.transition, false) : 1);
|
|
2281
|
-
const asset = clip.type === "media" ? assets.get(clip.asset) : void 0;
|
|
2282
|
-
const sourceTime = clip.type === "sequence" ? (_nullishCoalesce(clip.in, () => ( 0))) + time - clip.start : sourceTimeAt(clip, time);
|
|
2283
|
-
const clipTime = time - clip.start;
|
|
2284
|
-
let nested = null;
|
|
2285
|
-
if (clip.type === "sequence") {
|
|
2286
|
-
const seq = scope.sequences.get(clip.sequence);
|
|
2287
|
-
if (!seq || scope.within.includes(seq.id)) continue;
|
|
2288
|
-
nested = tracksAt(project, seq.tracks, sourceTime, { ...scope, within: [...scope.within, seq.id], prefix: `${prefix}${clip.id}/` });
|
|
2289
|
-
}
|
|
2290
|
-
const audible = videoAssetHasSound(asset);
|
|
2291
|
-
if (audible && clip.type === "media" && !clip.muted && !track.muted) {
|
|
2292
|
-
const gain = videoValueAt(clip.volume, clipTime, 1) * (_nullishCoalesce(track.volume, () => ( 1))) * fadeGain(clip, inside, true) * mix;
|
|
2293
|
-
audio.push({ clip: prefix + clip.id, track: track.id, asset: asset.id, src: asset.src, sourceTime, gain, speed: videoClipSpeedAt(clip, clipTime) });
|
|
2294
|
-
}
|
|
2295
|
-
if (nested && clip.type === "sequence" && !clip.muted && !track.muted) {
|
|
2296
|
-
const gain = videoValueAt(clip.volume, clipTime, 1) * (_nullishCoalesce(track.volume, () => ( 1))) * fadeGain(clip, inside, true) * mix;
|
|
2297
|
-
for (const a of nested.audio) audio.push({ ...a, gain: a.gain * gain });
|
|
2298
|
-
}
|
|
2299
|
-
if (track.kind !== "video" || track.hidden) continue;
|
|
2300
|
-
if (clip.type === "media" && (!asset || asset.kind === "audio")) continue;
|
|
2301
|
-
if (nested && !nested.layers.length) continue;
|
|
2302
|
-
const shown = videoClipAnimated(clip, project);
|
|
2303
|
-
let opacity = videoValueAt(shown.opacity, clipTime, 1) * fade;
|
|
2304
|
-
let wipe;
|
|
2305
|
-
let dip = null;
|
|
2306
|
-
let iris;
|
|
2307
|
-
let shift = 0;
|
|
2308
|
-
let shiftDirection = "right";
|
|
2309
|
-
if (incoming) {
|
|
2310
|
-
if (incoming.type === "crossfade") opacity *= incoming.progress;
|
|
2311
|
-
else if (incoming.type === "wipe") wipe = { direction: _nullishCoalesce(incoming.transition.direction, () => ( "right")), progress: incoming.progress };
|
|
2312
|
-
else if (incoming.type === "iris") iris = { progress: incoming.progress };
|
|
2313
|
-
else if (incoming.type === "push" || incoming.type === "slide") {
|
|
2314
|
-
shiftDirection = _nullishCoalesce(incoming.transition.direction, () => ( "right"));
|
|
2315
|
-
shift = videoTransitionEase(incoming.progress) - 1;
|
|
2316
|
-
} else dip = { color: _nullishCoalesce(incoming.transition.color, () => ( "#000000")), opacity: (1 - incoming.progress) * 2 };
|
|
2317
|
-
}
|
|
2318
|
-
if (_optionalChain([outgoing, 'optionalAccess', _43 => _43.type]) === "dip") dip = { color: _nullishCoalesce(outgoing.next.transition.color, () => ( "#000000")), opacity: outgoing.progress * 2 };
|
|
2319
|
-
if (_optionalChain([outgoing, 'optionalAccess', _44 => _44.type]) === "push") {
|
|
2320
|
-
shiftDirection = _nullishCoalesce(outgoing.next.transition.direction, () => ( "right"));
|
|
2321
|
-
shift = videoTransitionEase(outgoing.progress);
|
|
2322
|
-
}
|
|
2323
|
-
const size = clip.type === "media" ? { width: _nullishCoalesce(asset.width, () => ( project.width)), height: _nullishCoalesce(asset.height, () => ( project.height)) } : { width: project.width, height: project.height };
|
|
2324
|
-
const fit = _nullishCoalesce(clip.fit, () => ( (clip.type === "media" || clip.type === "sequence" ? "contain" : "fill")));
|
|
2325
|
-
const placed = placeVideoRect(project, size, clip.type === "text" ? "fill" : fit, shown.transform, clipTime);
|
|
2326
|
-
const across = shiftDirection === "left" || shiftDirection === "right";
|
|
2327
|
-
const sign = shiftDirection === "left" || shiftDirection === "up" ? -1 : 1;
|
|
2328
|
-
const rect = shift ? { ...placed, ...across ? { x: placed.x + sign * shift * project.width } : { y: placed.y + sign * shift * project.height } } : placed;
|
|
2329
|
-
const layer = { clip: prefix + clip.id, track: track.id, type: clip.type, opacity: clamp012(opacity), rect, rotation: videoValueAt(_optionalChain([shown, 'access', _45 => _45.transform, 'optionalAccess', _46 => _46.rotation]), clipTime, 0) };
|
|
2330
|
-
if (wipe) layer.wipe = wipe;
|
|
2331
|
-
if (iris) layer.iris = iris;
|
|
2332
|
-
if (clip.blend && clip.blend !== "normal") layer.blend = clip.blend;
|
|
2333
|
-
const grade = normalizeVideoGrade(clip.grade);
|
|
2334
|
-
if (grade) layer.grade = grade;
|
|
2335
|
-
if (clip.type === "media") Object.assign(layer, { asset: asset.id, assetKind: asset.kind, src: asset.src, sourceTime });
|
|
2336
|
-
if (clip.type === "sequence") Object.assign(layer, { sequence: clip.sequence, sourceTime, layers: nested.layers });
|
|
2337
|
-
if (clip.type === "text") layer.text = videoTextStyle(clip);
|
|
2338
|
-
if (clip.type === "color") layer.color = clip.color;
|
|
2339
|
-
if (layer.opacity > 0) layers.push(layer);
|
|
2340
|
-
if (dip && dip.opacity > 0) layers.push({ clip: `transition:${prefix}${incoming ? clip.id : outgoing.next.id}`, track: track.id, type: "color", color: dip.color, opacity: clamp012(dip.opacity), rect: { x: 0, y: 0, width: project.width, height: project.height }, rotation: 0 });
|
|
2341
|
-
}
|
|
2342
|
-
}
|
|
2343
|
-
return { layers, audio };
|
|
2344
|
-
}
|
|
2345
|
-
function videoFrameLeafLayers(layers) {
|
|
2346
|
-
return layers.flatMap((l) => l.layers ? videoFrameLeafLayers(l.layers) : [l]);
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
1359
|
// src/video-editor/audio.ts
|
|
2350
1360
|
var VIDEO_PEAK_BLOCK = 32;
|
|
2351
1361
|
function buildVideoAudioPeaks(channels, sampleRate, blockSize = VIDEO_PEAK_BLOCK) {
|
|
2352
1362
|
if (!(sampleRate > 0)) throw new Error("The sample rate must be above 0.");
|
|
2353
|
-
const length = channels.reduce((
|
|
1363
|
+
const length = channels.reduce((n, c) => Math.max(n, c.length), 0);
|
|
2354
1364
|
const blocks = Math.max(1, Math.ceil(length / blockSize));
|
|
2355
1365
|
const level0 = new Float32Array(blocks * 2);
|
|
2356
1366
|
for (let b = 0; b < blocks; b++) {
|
|
@@ -2371,12 +1381,12 @@ function buildVideoAudioPeaks(channels, sampleRate, blockSize = VIDEO_PEAK_BLOCK
|
|
|
2371
1381
|
const levels = [level0];
|
|
2372
1382
|
while (levels[levels.length - 1].length > 2) {
|
|
2373
1383
|
const below = levels[levels.length - 1];
|
|
2374
|
-
const
|
|
2375
|
-
const up = new Float32Array(Math.ceil(
|
|
1384
|
+
const n = below.length / 2;
|
|
1385
|
+
const up = new Float32Array(Math.ceil(n / 4) * 2);
|
|
2376
1386
|
for (let j = 0; j < up.length / 2; j++) {
|
|
2377
1387
|
let lo = Infinity;
|
|
2378
1388
|
let hi = -Infinity;
|
|
2379
|
-
for (let i = 4 * j; i < Math.min(
|
|
1389
|
+
for (let i = 4 * j; i < Math.min(n, 4 * j + 4); i++) {
|
|
2380
1390
|
lo = Math.min(lo, below[2 * i]);
|
|
2381
1391
|
hi = Math.max(hi, below[2 * i + 1]);
|
|
2382
1392
|
}
|
|
@@ -2417,10 +1427,10 @@ function videoAudioPeakRange(peaks, from, to) {
|
|
|
2417
1427
|
return min === Infinity ? { min: 0, max: 0 } : { min, max };
|
|
2418
1428
|
}
|
|
2419
1429
|
function videoAudioPeakSpans(peaks, from, to, columns) {
|
|
2420
|
-
const
|
|
2421
|
-
const out = new Float32Array(
|
|
2422
|
-
const step = (to - from) / Math.max(1,
|
|
2423
|
-
for (let c = 0; c <
|
|
1430
|
+
const n = Math.max(0, Math.floor(columns));
|
|
1431
|
+
const out = new Float32Array(n * 2);
|
|
1432
|
+
const step = (to - from) / Math.max(1, n);
|
|
1433
|
+
for (let c = 0; c < n; c++) {
|
|
2424
1434
|
const { min, max } = videoAudioPeakRange(peaks, from + c * step, from + (c + 1) * step);
|
|
2425
1435
|
out[2 * c] = min;
|
|
2426
1436
|
out[2 * c + 1] = max;
|
|
@@ -2428,30 +1438,30 @@ function videoAudioPeakSpans(peaks, from, to, columns) {
|
|
|
2428
1438
|
return out;
|
|
2429
1439
|
}
|
|
2430
1440
|
function videoClipWaveform(clip, peaks, columns) {
|
|
2431
|
-
const
|
|
2432
|
-
const out = new Float32Array(
|
|
1441
|
+
const n = Math.max(0, Math.floor(columns));
|
|
1442
|
+
const out = new Float32Array(n * 2);
|
|
2433
1443
|
const speed = _nullishCoalesce(clip.speed, () => ( 1));
|
|
2434
1444
|
const start = _nullishCoalesce(clip.in, () => ( 0));
|
|
2435
|
-
const step = clip.duration / Math.max(1,
|
|
2436
|
-
for (let c = 0; c <
|
|
1445
|
+
const step = clip.duration / Math.max(1, n);
|
|
1446
|
+
for (let c = 0; c < n; c++) {
|
|
2437
1447
|
const { min, max } = videoAudioPeakRange(peaks, start + c * step * speed, start + (c + 1) * step * speed);
|
|
2438
|
-
const gain = videoClipSoundGain(clip, (c + 0.5) * step);
|
|
1448
|
+
const gain = _chunkSMJGE7HMcjs.videoClipSoundGain.call(void 0, clip, (c + 0.5) * step);
|
|
2439
1449
|
out[2 * c] = min * gain;
|
|
2440
1450
|
out[2 * c + 1] = max * gain;
|
|
2441
1451
|
}
|
|
2442
1452
|
return out;
|
|
2443
1453
|
}
|
|
2444
1454
|
function videoWaveformPath(spans, width, height) {
|
|
2445
|
-
const
|
|
2446
|
-
if (!
|
|
1455
|
+
const n = spans.length / 2;
|
|
1456
|
+
if (!n || width <= 0 || height <= 0) return "";
|
|
2447
1457
|
const mid = height / 2;
|
|
2448
1458
|
const y = (v) => (mid - Math.max(-1, Math.min(1, v)) * mid).toFixed(1);
|
|
2449
|
-
const x = (i) => ((i + 0.5) * (width /
|
|
1459
|
+
const x = (i) => ((i + 0.5) * (width / n)).toFixed(1);
|
|
2450
1460
|
const floor = 0.5 / mid;
|
|
2451
1461
|
const top = [];
|
|
2452
1462
|
const bottom = [];
|
|
2453
|
-
for (let i = 0; i <
|
|
2454
|
-
for (let i =
|
|
1463
|
+
for (let i = 0; i < n; i++) top.push(`${i ? "L" : "M"}${x(i)} ${y(Math.max(spans[2 * i + 1], floor))}`);
|
|
1464
|
+
for (let i = n - 1; i >= 0; i--) bottom.push(`L${x(i)} ${y(Math.min(spans[2 * i], -floor))}`);
|
|
2455
1465
|
return `${top.join("")}${bottom.join("")}Z`;
|
|
2456
1466
|
}
|
|
2457
1467
|
function videoClipWaveformPath(clip, peaks, width, height) {
|
|
@@ -2497,15 +1507,15 @@ async function decodeVideoAudioPeaks(src, options = {}) {
|
|
|
2497
1507
|
}
|
|
2498
1508
|
return buildVideoAudioPeaks(Array.from({ length: buffer.numberOfChannels }, (_, i) => buffer.getChannelData(i)), buffer.sampleRate);
|
|
2499
1509
|
}
|
|
2500
|
-
var VideoAudioPeaksCache = (
|
|
2501
|
-
constructor(loader = (asset) => decodeVideoAudioPeaks(asset.src)) {;
|
|
1510
|
+
var VideoAudioPeaksCache = (_class2 = class {
|
|
1511
|
+
constructor(loader = (asset) => decodeVideoAudioPeaks(asset.src)) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);_class2.prototype.__init5.call(this);
|
|
2502
1512
|
this.loader = loader;
|
|
2503
1513
|
}
|
|
2504
1514
|
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
1515
|
+
__init2() {this.ready = /* @__PURE__ */ new Map()}
|
|
1516
|
+
__init3() {this.pending = /* @__PURE__ */ new Map()}
|
|
1517
|
+
__init4() {this.failed = /* @__PURE__ */ new Map()}
|
|
1518
|
+
__init5() {this.listeners = /* @__PURE__ */ new Set()}
|
|
2509
1519
|
/** The peaks if ready, without starting to load them. */
|
|
2510
1520
|
peek(asset) {
|
|
2511
1521
|
return this.ready.get(asset.src);
|
|
@@ -2561,7 +1571,7 @@ var VideoAudioPeaksCache = (_class3 = class {
|
|
|
2561
1571
|
emit() {
|
|
2562
1572
|
for (const fn of this.listeners) fn();
|
|
2563
1573
|
}
|
|
2564
|
-
},
|
|
1574
|
+
}, _class2);
|
|
2565
1575
|
|
|
2566
1576
|
// src/video-editor/scopes.ts
|
|
2567
1577
|
var VIDEO_SCOPE_KINDS = ["histogram", "waveform", "vectorscope"];
|
|
@@ -2708,7 +1718,7 @@ function summarizeVideoScopes(pixels, options = {}) {
|
|
|
2708
1718
|
const w = videoLumaWaveform(pixels, { ...options, columns, levels: 256 });
|
|
2709
1719
|
const waveform = Array.from({ length: w.columns }, (_, c) => {
|
|
2710
1720
|
const counts = w.data.subarray(c * 256, c * 256 + 256);
|
|
2711
|
-
const
|
|
1721
|
+
const n = counts.reduce((a, b) => a + b, 0);
|
|
2712
1722
|
let lo = 0;
|
|
2713
1723
|
while (lo < 255 && !counts[lo]) lo++;
|
|
2714
1724
|
let hi = 255;
|
|
@@ -2717,7 +1727,7 @@ function summarizeVideoScopes(pixels, options = {}) {
|
|
|
2717
1727
|
let median = 0;
|
|
2718
1728
|
for (let i = 0; i < 256; i++) {
|
|
2719
1729
|
seen += counts[i];
|
|
2720
|
-
if (seen >=
|
|
1730
|
+
if (seen >= n / 2 && n) {
|
|
2721
1731
|
median = i;
|
|
2722
1732
|
break;
|
|
2723
1733
|
}
|
|
@@ -2847,10 +1857,10 @@ function videoScopeImage(kind, pixels, width = 256, height = 128, options = {})
|
|
|
2847
1857
|
const size = Math.min(width, height);
|
|
2848
1858
|
return videoVectorscopeImage(videoVectorscope(pixels, { ...options, size }), size);
|
|
2849
1859
|
}
|
|
2850
|
-
var VideoPreviewPixels = (
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
1860
|
+
var VideoPreviewPixels = (_class3 = class {constructor() { _class3.prototype.__init6.call(this);_class3.prototype.__init7.call(this);_class3.prototype.__init8.call(this); }
|
|
1861
|
+
__init6() {this.reader = null}
|
|
1862
|
+
__init7() {this.drawnAt = null}
|
|
1863
|
+
__init8() {this.listeners = /* @__PURE__ */ new Set()}
|
|
2854
1864
|
/** Gives the canvas to read (the latest preview wins). Returns a function that takes it away again. */
|
|
2855
1865
|
attach(reader) {
|
|
2856
1866
|
this.reader = reader;
|
|
@@ -2918,7 +1928,7 @@ var VideoPreviewPixels = (_class4 = class {constructor() { _class4.prototype.__i
|
|
|
2918
1928
|
emit() {
|
|
2919
1929
|
for (const l of [...this.listeners]) l();
|
|
2920
1930
|
}
|
|
2921
|
-
},
|
|
1931
|
+
}, _class3);
|
|
2922
1932
|
function readVideoScopesPanel(feed, kinds = VIDEO_SCOPE_KINDS, options = {}) {
|
|
2923
1933
|
let snap;
|
|
2924
1934
|
try {
|
|
@@ -3000,24 +2010,24 @@ function videoTranscriptTrack(project, track) {
|
|
|
3000
2010
|
if (!project.tracks.some((t) => t.id === track)) throw new Error(`There is no track "${track}"; the tracks are ${project.tracks.map((t) => `"${t.id}"`).join(", ")}.`);
|
|
3001
2011
|
return track;
|
|
3002
2012
|
}
|
|
3003
|
-
const assets = videoAssetMap(project);
|
|
3004
|
-
const transcribed = (t) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access',
|
|
3005
|
-
return _nullishCoalesce(_optionalChain([(_nullishCoalesce(project.tracks.find((t) => t.kind === "audio" && transcribed(t)), () => ( project.tracks.find(transcribed)))), 'optionalAccess',
|
|
2013
|
+
const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project);
|
|
2014
|
+
const transcribed = (t) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _21 => _21.get, 'call', _22 => _22(c.asset), 'optionalAccess', _23 => _23.transcript, 'optionalAccess', _24 => _24.length]));
|
|
2015
|
+
return _nullishCoalesce(_optionalChain([(_nullishCoalesce(project.tracks.find((t) => t.kind === "audio" && transcribed(t)), () => ( project.tracks.find(transcribed)))), 'optionalAccess', _25 => _25.id]), () => ( null));
|
|
3006
2016
|
}
|
|
3007
2017
|
function videoTimelineTranscript(project, options = {}) {
|
|
3008
2018
|
const id = videoTranscriptTrack(project, options.track);
|
|
3009
2019
|
if (!id) return [];
|
|
3010
2020
|
const track = project.tracks.find((t) => t.id === id);
|
|
3011
|
-
const assets = videoAssetMap(project);
|
|
2021
|
+
const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project);
|
|
3012
2022
|
const out = [];
|
|
3013
|
-
for (const clip of sortedVideoClips(track)) {
|
|
2023
|
+
for (const clip of _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track)) {
|
|
3014
2024
|
if (clip.type !== "media") continue;
|
|
3015
|
-
const words = _optionalChain([assets, 'access',
|
|
3016
|
-
if (!_optionalChain([words, 'optionalAccess',
|
|
3017
|
-
const speed = videoClipSpeed(clip);
|
|
2025
|
+
const words = _optionalChain([assets, 'access', _26 => _26.get, 'call', _27 => _27(clip.asset), 'optionalAccess', _28 => _28.transcript]);
|
|
2026
|
+
if (!_optionalChain([words, 'optionalAccess', _29 => _29.length])) continue;
|
|
2027
|
+
const speed = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip);
|
|
3018
2028
|
const from = _nullishCoalesce(clip.in, () => ( 0));
|
|
3019
2029
|
const to = from + clip.duration * speed;
|
|
3020
|
-
const toTimeline = (s) => Math.min(videoClipEnd(clip), Math.max(clip.start, clip.start + (s - from) / speed));
|
|
2030
|
+
const toTimeline = (s) => Math.min(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip), Math.max(clip.start, clip.start + (s - from) / speed));
|
|
3021
2031
|
words.forEach((w, index) => {
|
|
3022
2032
|
const mid = (w.start + w.end) / 2;
|
|
3023
2033
|
if (mid < from || mid >= to) return;
|
|
@@ -3027,7 +2037,7 @@ function videoTimelineTranscript(project, options = {}) {
|
|
|
3027
2037
|
return out;
|
|
3028
2038
|
}
|
|
3029
2039
|
var normalizeVideoWord = (word) => word.toLowerCase().replace(/^[^\p{L}\p{N}']+|[^\p{L}\p{N}']+$/gu, "");
|
|
3030
|
-
var rangeOf = (words, i,
|
|
2040
|
+
var rangeOf = (words, i, n) => ({ from: words[i].start, to: words[i + n - 1].end, text: words.slice(i, i + n).map((w) => w.word).join(" ") });
|
|
3031
2041
|
function findVideoTranscriptText(words, query) {
|
|
3032
2042
|
const q = query.split(/\s+/).map(normalizeVideoWord).filter(Boolean);
|
|
3033
2043
|
if (!q.length) throw new Error("Search for at least one word.");
|
|
@@ -3062,19 +2072,19 @@ function findVideoTranscriptPauses(words, options = {}) {
|
|
|
3062
2072
|
let to = b.start - keep;
|
|
3063
2073
|
if (options.fps) {
|
|
3064
2074
|
const f = 1e3 / options.fps;
|
|
3065
|
-
from = snapToVideoFrame(Math.ceil(from / f - 1e-9) * f, options.fps);
|
|
3066
|
-
to = snapToVideoFrame(Math.floor(to / f + 1e-9) * f, options.fps);
|
|
2075
|
+
from = _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, Math.ceil(from / f - 1e-9) * f, options.fps);
|
|
2076
|
+
to = _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, Math.floor(to / f + 1e-9) * f, options.fps);
|
|
3067
2077
|
}
|
|
3068
|
-
if (to - from > VIDEO_TIME_EPSILON) out.push({ from, to, text: `(pause after "${a.word}")` });
|
|
2078
|
+
if (to - from > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) out.push({ from, to, text: `(pause after "${a.word}")` });
|
|
3069
2079
|
}
|
|
3070
2080
|
return out;
|
|
3071
2081
|
}
|
|
3072
2082
|
function mergeVideoRanges(ranges) {
|
|
3073
|
-
const sorted = ranges.filter((r) => r.to - r.from > VIDEO_TIME_EPSILON).map((r) => ({ from: r.from, to: r.to })).sort((a, b) => a.from - b.from);
|
|
2083
|
+
const sorted = ranges.filter((r) => r.to - r.from > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).map((r) => ({ from: r.from, to: r.to })).sort((a, b) => a.from - b.from);
|
|
3074
2084
|
const out = [];
|
|
3075
2085
|
for (const r of sorted) {
|
|
3076
2086
|
const last = out[out.length - 1];
|
|
3077
|
-
if (last && r.from <= last.to + VIDEO_TIME_EPSILON) last.to = Math.max(last.to, r.to);
|
|
2087
|
+
if (last && r.from <= last.to + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) last.to = Math.max(last.to, r.to);
|
|
3078
2088
|
else out.push(r);
|
|
3079
2089
|
}
|
|
3080
2090
|
return out;
|
|
@@ -3101,688 +2111,15 @@ function videoWordAt(words, time) {
|
|
|
3101
2111
|
return -1;
|
|
3102
2112
|
}
|
|
3103
2113
|
|
|
3104
|
-
// src/video-editor/render.ts
|
|
3105
|
-
var esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3106
|
-
var n = (v) => String(Math.round(v * 100) / 100);
|
|
3107
|
-
var n4 = (v) => String(Math.round(v * 1e4) / 1e4);
|
|
3108
|
-
var videoIrisRadius = (frame, progress) => progress * Math.hypot(frame.width / 2, frame.height / 2);
|
|
3109
|
-
function videoWipeRect(rect, wipe) {
|
|
3110
|
-
const { direction, progress } = wipe;
|
|
3111
|
-
const w = rect.width * progress;
|
|
3112
|
-
const h = rect.height * progress;
|
|
3113
|
-
if (direction === "right") return { ...rect, width: w };
|
|
3114
|
-
if (direction === "left") return { ...rect, x: rect.x + rect.width - w, width: w };
|
|
3115
|
-
if (direction === "down") return { ...rect, height: h };
|
|
3116
|
-
return { ...rect, y: rect.y + rect.height - h, height: h };
|
|
3117
|
-
}
|
|
3118
|
-
function videoFrameToSvg(frame, options = {}, assets = []) {
|
|
3119
|
-
const defs = [];
|
|
3120
|
-
const posters = new Map(assets.map((a) => [a.id, a.poster]));
|
|
3121
|
-
const draw = (layers, prefix) => layers.map((layer, index) => {
|
|
3122
|
-
const i = `${prefix}${index}`;
|
|
3123
|
-
const { rect } = layer;
|
|
3124
|
-
const attrs = [];
|
|
3125
|
-
const style = [];
|
|
3126
|
-
if (layer.opacity < 1) attrs.push(`opacity="${n(layer.opacity)}"`);
|
|
3127
|
-
if (layer.blend) style.push(`mix-blend-mode:${layer.blend === "add" ? "plus-lighter" : layer.blend}`);
|
|
3128
|
-
if (layer.layers) style.push("isolation:isolate");
|
|
3129
|
-
if (style.length) attrs.push(`style="${style.join(";")}"`);
|
|
3130
|
-
if (layer.grade) {
|
|
3131
|
-
defs.push(videoGradeSvgFilter(`g${i}`, layer.grade, layer.grade.lut ? _optionalChain([options, 'access', _56 => _56.lutFor, 'optionalCall', _57 => _57(layer.grade.lut.src)]) : null));
|
|
3132
|
-
attrs.push(`filter="url(#g${i})"`);
|
|
3133
|
-
}
|
|
3134
|
-
if (layer.rotation) attrs.push(`transform="rotate(${n(layer.rotation)} ${n(rect.x + rect.width / 2)} ${n(rect.y + rect.height / 2)})"`);
|
|
3135
|
-
if (layer.wipe) {
|
|
3136
|
-
const r = videoWipeRect(rect, layer.wipe);
|
|
3137
|
-
defs.push(`<clipPath id="w${i}"><rect x="${n(r.x)}" y="${n(r.y)}" width="${n(r.width)}" height="${n(r.height)}"/></clipPath>`);
|
|
3138
|
-
attrs.push(`clip-path="url(#w${i})"`);
|
|
3139
|
-
}
|
|
3140
|
-
const box = `x="${n(rect.x)}" y="${n(rect.y)}" width="${n(rect.width)}" height="${n(rect.height)}"`;
|
|
3141
|
-
let inner = "";
|
|
3142
|
-
if (layer.layers) {
|
|
3143
|
-
inner = `<g transform="translate(${n(rect.x)} ${n(rect.y)}) scale(${n4(rect.width / frame.width)} ${n4(rect.height / frame.height)})">${draw(layer.layers, `${i}-`)}</g>`;
|
|
3144
|
-
} else if (layer.type === "color") inner = `<rect ${box} fill="${esc(_nullishCoalesce(layer.color, () => ( "#000000")))}"/>`;
|
|
3145
|
-
else if (layer.type === "text" && layer.text) {
|
|
3146
|
-
const t = layer.text;
|
|
3147
|
-
const lines = t.text.split("\n");
|
|
3148
|
-
const lh = t.fontSize * 1.2;
|
|
3149
|
-
const cx = rect.x + rect.width / 2;
|
|
3150
|
-
const cy = rect.y + rect.height / 2;
|
|
3151
|
-
const top = cy - lh * (lines.length - 1) / 2;
|
|
3152
|
-
if (t.background) {
|
|
3153
|
-
const w = Math.max(...lines.map((l) => l.length)) * t.fontSize * 0.6 + t.fontSize;
|
|
3154
|
-
const h = lh * lines.length + t.fontSize * 0.4;
|
|
3155
|
-
inner += `<rect x="${n(cx - w / 2)}" y="${n(cy - h / 2)}" width="${n(w)}" height="${n(h)}" fill="${esc(t.background)}"/>`;
|
|
3156
|
-
}
|
|
3157
|
-
inner += `<text x="${n(cx)}" text-anchor="middle" dominant-baseline="central" font-family="${esc(t.fontFamily)}" font-size="${n(t.fontSize)}" font-weight="${t.fontWeight}" fill="${esc(t.color)}">${lines.map((l, k) => `<tspan x="${n(cx)}" y="${n(top + k * lh)}">${esc(l)}</tspan>`).join("")}</text>`;
|
|
3158
|
-
} else {
|
|
3159
|
-
const href = options.imageFor ? options.imageFor(layer, frame) : layer.assetKind === "image" ? _nullishCoalesce(layer.src, () => ( null)) : _nullishCoalesce(posters.get(_nullishCoalesce(layer.asset, () => ( ""))), () => ( null));
|
|
3160
|
-
if (href) inner = `<image href="${esc(href)}" ${box} preserveAspectRatio="none"/>`;
|
|
3161
|
-
else {
|
|
3162
|
-
const label = `${_nullishCoalesce(layer.asset, () => ( layer.clip))} \xB7 ${formatVideoTimecode(_nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(options.fps, () => ( 30)))}`;
|
|
3163
|
-
const size = Math.max(10, Math.min(rect.height / 8, rect.width / Math.max(8, label.length * 0.6)));
|
|
3164
|
-
inner = `<rect ${box} fill="#334155" stroke="#94a3b8" stroke-width="2"/><text x="${n(rect.x + rect.width / 2)}" y="${n(rect.y + rect.height / 2)}" text-anchor="middle" dominant-baseline="central" font-family="sans-serif" font-size="${n(size)}" fill="#e2e8f0">${esc(label)}</text>`;
|
|
3165
|
-
}
|
|
3166
|
-
}
|
|
3167
|
-
let item = attrs.length ? `<g ${attrs.join(" ")}>${inner}</g>` : inner;
|
|
3168
|
-
if (layer.iris) {
|
|
3169
|
-
defs.push(`<clipPath id="i${i}"><circle cx="${n(frame.width / 2)}" cy="${n(frame.height / 2)}" r="${n(videoIrisRadius(frame, layer.iris.progress))}"/></clipPath>`);
|
|
3170
|
-
item = `<g clip-path="url(#i${i})">${item}</g>`;
|
|
3171
|
-
}
|
|
3172
|
-
return item;
|
|
3173
|
-
}).join("");
|
|
3174
|
-
const body = draw(frame.layers, "");
|
|
3175
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${n(frame.width)} ${n(frame.height)}" width="${n(frame.width)}" height="${n(frame.height)}">${defs.length ? `<defs>${defs.join("")}</defs>` : ""}<rect width="100%" height="100%" fill="${esc(frame.background)}"/>${body}</svg>`;
|
|
3176
|
-
}
|
|
3177
|
-
function videoProjectSvg(project, time, options = {}) {
|
|
3178
|
-
return videoFrameToSvg(videoFrameAt(project, time), { fps: project.fps, ...options }, project.assets);
|
|
3179
|
-
}
|
|
3180
|
-
function videoContactSheetSvg(project, times, options = {}) {
|
|
3181
|
-
const columns = _nullishCoalesce(options.columns, () => ( Math.ceil(Math.sqrt(times.length))));
|
|
3182
|
-
const w = _nullishCoalesce(options.width, () => ( 320));
|
|
3183
|
-
const h = w * project.height / project.width;
|
|
3184
|
-
const label = 18;
|
|
3185
|
-
const gap = 8;
|
|
3186
|
-
const rows = Math.ceil(times.length / columns);
|
|
3187
|
-
const W = columns * w + (columns + 1) * gap;
|
|
3188
|
-
const H = rows * (h + label) + (rows + 1) * gap;
|
|
3189
|
-
const cells = times.map((t, i) => {
|
|
3190
|
-
const x = gap + i % columns * (w + gap);
|
|
3191
|
-
const y = gap + Math.floor(i / columns) * (h + label + gap);
|
|
3192
|
-
const svg = videoProjectSvg(project, t, options).replace(/^<svg xmlns="http:\/\/www.w3.org\/2000\/svg"/, `<svg x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}"`).replace(/ width="[\d.]+" height="[\d.]+">/, ">");
|
|
3193
|
-
return `${svg}<text x="${n(x)}" y="${n(y + h + 14)}" font-family="sans-serif" font-size="12" fill="#0f172a">${(t / 1e3).toFixed(2)} s \xB7 ${formatVideoTimecode(t, project.fps)}</text>`;
|
|
3194
|
-
});
|
|
3195
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${n(W)} ${n(H)}" width="${n(W)}" height="${n(H)}"><rect width="100%" height="100%" fill="#f8fafc"/>${cells.join("")}</svg>`;
|
|
3196
|
-
}
|
|
3197
|
-
function paintVideoLayer(ctx, frame, layer, sourceFor, options) {
|
|
3198
|
-
const { rect } = layer;
|
|
3199
|
-
if (layer.iris) {
|
|
3200
|
-
ctx.beginPath();
|
|
3201
|
-
ctx.arc(frame.width / 2, frame.height / 2, videoIrisRadius(frame, layer.iris.progress), 0, 2 * Math.PI);
|
|
3202
|
-
ctx.clip();
|
|
3203
|
-
}
|
|
3204
|
-
if (layer.grade) {
|
|
3205
|
-
const defs = videoGradeSvgDefs(layer.grade);
|
|
3206
|
-
if (options.defineSvgFilter) for (const d of defs) options.defineSvgFilter(d.id, d.markup);
|
|
3207
|
-
const css = videoGradeCssFilter(layer.grade);
|
|
3208
|
-
ctx.filter = options.defineSvgFilter ? css || "none" : css.replace(/\s*url\([^)]*\)/g, "").trim() || "none";
|
|
3209
|
-
}
|
|
3210
|
-
if (layer.rotation) {
|
|
3211
|
-
ctx.translate(rect.x + rect.width / 2, rect.y + rect.height / 2);
|
|
3212
|
-
ctx.rotate(layer.rotation * Math.PI / 180);
|
|
3213
|
-
ctx.translate(-(rect.x + rect.width / 2), -(rect.y + rect.height / 2));
|
|
3214
|
-
}
|
|
3215
|
-
if (layer.wipe) {
|
|
3216
|
-
const r = videoWipeRect(rect, layer.wipe);
|
|
3217
|
-
ctx.beginPath();
|
|
3218
|
-
ctx.rect(r.x, r.y, r.width, r.height);
|
|
3219
|
-
ctx.clip();
|
|
3220
|
-
}
|
|
3221
|
-
if (layer.type === "color") {
|
|
3222
|
-
ctx.fillStyle = _nullishCoalesce(layer.color, () => ( "#000000"));
|
|
3223
|
-
ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
|
|
3224
|
-
} else if (layer.type === "text" && layer.text) {
|
|
3225
|
-
const t = layer.text;
|
|
3226
|
-
const lines = t.text.split("\n");
|
|
3227
|
-
const lh = t.fontSize * 1.2;
|
|
3228
|
-
const cx = rect.x + rect.width / 2;
|
|
3229
|
-
const top = rect.y + rect.height / 2 - lh * (lines.length - 1) / 2;
|
|
3230
|
-
ctx.font = `${t.fontWeight} ${t.fontSize}px ${t.fontFamily}`;
|
|
3231
|
-
ctx.textAlign = "center";
|
|
3232
|
-
ctx.textBaseline = "middle";
|
|
3233
|
-
if (t.background) {
|
|
3234
|
-
const w = Math.max(...lines.map((l) => ctx.measureText(l).width)) + t.fontSize;
|
|
3235
|
-
const h = lh * lines.length + t.fontSize * 0.4;
|
|
3236
|
-
ctx.fillStyle = t.background;
|
|
3237
|
-
ctx.fillRect(cx - w / 2, rect.y + rect.height / 2 - h / 2, w, h);
|
|
3238
|
-
}
|
|
3239
|
-
ctx.fillStyle = t.color;
|
|
3240
|
-
lines.forEach((l, k) => ctx.fillText(l, cx, top + k * lh));
|
|
3241
|
-
} else {
|
|
3242
|
-
const source = sourceFor(layer);
|
|
3243
|
-
if (source) ctx.drawImage(source, rect.x, rect.y, rect.width, rect.height);
|
|
3244
|
-
else {
|
|
3245
|
-
ctx.fillStyle = "#334155";
|
|
3246
|
-
ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
|
|
3247
|
-
ctx.strokeStyle = "#94a3b8";
|
|
3248
|
-
ctx.lineWidth = 2;
|
|
3249
|
-
ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3252
|
-
}
|
|
3253
|
-
function drawVideoFrame(ctx, frame, sourceFor, scale = 1, options = {}) {
|
|
3254
|
-
ctx.save();
|
|
3255
|
-
ctx.setTransform(scale, 0, 0, scale, 0, 0);
|
|
3256
|
-
ctx.globalAlpha = 1;
|
|
3257
|
-
ctx.fillStyle = frame.background;
|
|
3258
|
-
ctx.fillRect(0, 0, frame.width, frame.height);
|
|
3259
|
-
drawVideoLayers(ctx, frame, frame.layers, sourceFor, scale, options, 0);
|
|
3260
|
-
ctx.restore();
|
|
3261
|
-
}
|
|
3262
|
-
function drawVideoLayers(ctx, frame, layers, sourceFor, scale, options, depth) {
|
|
3263
|
-
const cw = Math.max(1, Math.round(frame.width * scale));
|
|
3264
|
-
const ch = Math.max(1, Math.round(frame.height * scale));
|
|
3265
|
-
for (const layer of layers) {
|
|
3266
|
-
let source = sourceFor;
|
|
3267
|
-
if (layer.layers) {
|
|
3268
|
-
const group = _optionalChain([options, 'access', _58 => _58.scratch, 'optionalCall', _59 => _59(cw, ch, 2 * depth)]);
|
|
3269
|
-
if (!group) {
|
|
3270
|
-
drawVideoLayers(ctx, frame, layer.layers, sourceFor, scale, options, depth + 1);
|
|
3271
|
-
continue;
|
|
3272
|
-
}
|
|
3273
|
-
const g = group.ctx;
|
|
3274
|
-
g.save();
|
|
3275
|
-
g.setTransform(1, 0, 0, 1, 0, 0);
|
|
3276
|
-
g.clearRect(0, 0, cw, ch);
|
|
3277
|
-
g.setTransform(scale, 0, 0, scale, 0, 0);
|
|
3278
|
-
g.globalAlpha = 1;
|
|
3279
|
-
g.globalCompositeOperation = "source-over";
|
|
3280
|
-
drawVideoLayers(g, frame, layer.layers, sourceFor, scale, options, depth + 1);
|
|
3281
|
-
g.restore();
|
|
3282
|
-
source = (l) => l === layer ? group.canvas : sourceFor(l);
|
|
3283
|
-
}
|
|
3284
|
-
const setting = _optionalChain([layer, 'access', _60 => _60.grade, 'optionalAccess', _61 => _61.lut]);
|
|
3285
|
-
const lut = setting ? _optionalChain([options, 'access', _62 => _62.lutFor, 'optionalCall', _63 => _63(setting.src)]) : null;
|
|
3286
|
-
const scratch = lut ? _optionalChain([options, 'access', _64 => _64.scratch, 'optionalCall', _65 => _65(cw, ch, 2 * depth + 1)]) : null;
|
|
3287
|
-
ctx.save();
|
|
3288
|
-
ctx.setTransform(scale, 0, 0, scale, 0, 0);
|
|
3289
|
-
if (lut && scratch) {
|
|
3290
|
-
const s = scratch.ctx;
|
|
3291
|
-
s.save();
|
|
3292
|
-
s.setTransform(1, 0, 0, 1, 0, 0);
|
|
3293
|
-
s.clearRect(0, 0, cw, ch);
|
|
3294
|
-
s.setTransform(scale, 0, 0, scale, 0, 0);
|
|
3295
|
-
s.globalAlpha = 1;
|
|
3296
|
-
s.globalCompositeOperation = "source-over";
|
|
3297
|
-
paintVideoLayer(s, frame, layer, source, options);
|
|
3298
|
-
s.restore();
|
|
3299
|
-
const img = s.getImageData(0, 0, cw, ch);
|
|
3300
|
-
applyVideoLutToPixels(lut, img.data, _nullishCoalesce(setting.strength, () => ( 1)));
|
|
3301
|
-
s.putImageData(img, 0, 0);
|
|
3302
|
-
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
3303
|
-
ctx.globalAlpha = layer.opacity;
|
|
3304
|
-
if (layer.blend && layer.blend !== "normal") ctx.globalCompositeOperation = layer.blend === "add" ? "lighter" : layer.blend;
|
|
3305
|
-
ctx.drawImage(scratch.canvas, 0, 0, cw, ch);
|
|
3306
|
-
} else {
|
|
3307
|
-
ctx.globalAlpha = layer.opacity;
|
|
3308
|
-
if (layer.blend && layer.blend !== "normal") ctx.globalCompositeOperation = layer.blend === "add" ? "lighter" : layer.blend;
|
|
3309
|
-
paintVideoLayer(ctx, frame, layer, source, options);
|
|
3310
|
-
}
|
|
3311
|
-
ctx.restore();
|
|
3312
|
-
}
|
|
3313
|
-
}
|
|
3314
|
-
|
|
3315
|
-
// src/video-editor/export.ts
|
|
3316
|
-
var reelName = (asset) => (_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _66 => _66.name]), () => ( _optionalChain([asset, 'optionalAccess', _67 => _67.id]))), () => ( "AX"))).replace(/\.[a-z0-9]+$/i, "").replace(/[^A-Za-z0-9]/g, "").toUpperCase().slice(0, 8) || "AX";
|
|
3317
|
-
function toVideoEdl(project, options = {}) {
|
|
3318
|
-
const track = options.track !== void 0 ? project.tracks.find((t) => t.id === options.track) : [...project.tracks].reverse().find((t) => t.kind === "video");
|
|
3319
|
-
if (!track) throw new Error(options.track !== void 0 ? `There is no track "${options.track}".` : "The project has no video track.");
|
|
3320
|
-
const fps = project.fps;
|
|
3321
|
-
const dropFrame = (_nullishCoalesce(options.dropFrame, () => ( true))) && isVideoDropFrameRate(fps);
|
|
3322
|
-
const tc = (ms) => formatVideoTimecode(ms, fps, dropFrame);
|
|
3323
|
-
const rec0 = options.recordStart !== void 0 ? videoTimecodeFrames(options.recordStart, fps) : videoHourFrames(fps, dropFrame);
|
|
3324
|
-
const rtc = (ms) => formatVideoTimecodeFrames(rec0 + videoTimecodeFrames(ms, fps), fps, dropFrame);
|
|
3325
|
-
const assets = videoAssetMap(project);
|
|
3326
|
-
const channel = track.kind === "video" ? "V" : "A";
|
|
3327
|
-
const lines = [`TITLE: ${(_nullishCoalesce(_nullishCoalesce(options.title, () => ( project.name)), () => ( "Untitled"))).toUpperCase()}`, `FCM: ${dropFrame ? "DROP FRAME" : "NON-DROP FRAME"}`, ""];
|
|
3328
|
-
let event = 0;
|
|
3329
|
-
const num2 = () => String(++event).padStart(3, "0");
|
|
3330
|
-
const sourceAt = (clip, time) => clip.type === "media" ? (_nullishCoalesce(clip.in, () => ( 0))) + (time - clip.start) * videoClipSpeed(clip) : time - clip.start;
|
|
3331
|
-
const row = (n2, reel, kind, srcIn, srcOut, recIn, recOut) => `${n2} ${reel.padEnd(8)} ${channel.padEnd(5)} ${kind.padEnd(8)} ${tc(srcIn)} ${tc(srcOut)} ${rtc(recIn)} ${rtc(recOut)}`;
|
|
3332
|
-
for (const clip of sortedVideoClips(track)) {
|
|
3333
|
-
const asset = clip.type === "media" ? assets.get(clip.asset) : void 0;
|
|
3334
|
-
const reel = clip.type === "media" ? reelName(asset) : "BL";
|
|
3335
|
-
const end = videoClipEnd(clip);
|
|
3336
|
-
const before = clip.transition ? videoClipBefore(track, clip) : null;
|
|
3337
|
-
const half = before && clip.transition.type !== "dip" ? clip.transition.duration / 2 : 0;
|
|
3338
|
-
const next = sortedVideoClips(track).find((c) => c !== clip && Math.abs(c.start - end) < 0.5 && c.transition && c.transition.type !== "dip");
|
|
3339
|
-
const recOut = next ? end - next.transition.duration / 2 : end;
|
|
3340
|
-
const recIn = clip.start - half;
|
|
3341
|
-
const n2 = num2();
|
|
3342
|
-
if (before) {
|
|
3343
|
-
const t = clip.transition;
|
|
3344
|
-
const frames = String(Math.round(t.duration * fps / 1e3)).padStart(3, "0");
|
|
3345
|
-
const outReel = before.type === "media" ? reelName(assets.get(before.asset)) : "BL";
|
|
3346
|
-
const at = sourceAt(before, recIn);
|
|
3347
|
-
lines.push(row(n2, outReel, "C", at, at, recIn, recIn));
|
|
3348
|
-
lines.push(row(n2, reel, `${t.type === "crossfade" || t.type === "dip" ? "D" : "W001"} ${frames}`, sourceAt(clip, recIn), sourceAt(clip, recOut), recIn, recOut));
|
|
3349
|
-
} else lines.push(row(n2, reel, "C", sourceAt(clip, recIn), sourceAt(clip, recOut), recIn, recOut));
|
|
3350
|
-
if (clip.type === "media" && videoClipSpeed(clip) !== 1) lines.push(`M2 ${reel.padEnd(8)} ${(videoClipSpeed(clip) * fps).toFixed(1).padStart(6)} ${tc(sourceAt(clip, recIn))}`);
|
|
3351
|
-
if (clip.type === "media") lines.push(`* FROM CLIP NAME: ${_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _68 => _68.name]), () => ( _optionalChain([asset, 'optionalAccess', _69 => _69.src]))), () => ( clip.asset))}`);
|
|
3352
|
-
if (clip.type === "text") lines.push(`* TITLE: ${clip.text.replace(/\n/g, " ")}`);
|
|
3353
|
-
if (clip.type === "color") lines.push(`* COLOR: ${clip.color}`);
|
|
3354
|
-
if (clip.type === "sequence") lines.push(`* COMPOUND CLIP: ${_nullishCoalesce(clip.name, () => ( clip.sequence))} (sequence ${clip.sequence} from ${tc(_nullishCoalesce(clip.in, () => ( 0)))}, not flattened)`);
|
|
3355
|
-
lines.push("");
|
|
3356
|
-
}
|
|
3357
|
-
return lines.join("\n");
|
|
3358
|
-
}
|
|
3359
|
-
function loudnormFilter(target = {}, measure = false) {
|
|
3360
|
-
const I = _nullishCoalesce(target.integrated, () => ( -14));
|
|
3361
|
-
const TP = _nullishCoalesce(target.truePeak, () => ( -1));
|
|
3362
|
-
const LRA = _nullishCoalesce(target.range, () => ( 11));
|
|
3363
|
-
if (!(I >= -70 && I <= -5)) throw new Error(`The loudness target must be between -70 and -5 LUFS (got ${I}); -14 suits streaming, -23 broadcast.`);
|
|
3364
|
-
if (!(TP >= -9 && TP <= 0)) throw new Error(`The true peak ceiling must be between -9 and 0 dBTP (got ${TP}); -1 is usual.`);
|
|
3365
|
-
if (!(LRA >= 1 && LRA <= 50)) throw new Error(`The loudness range must be between 1 and 50 LU (got ${LRA}).`);
|
|
3366
|
-
const parts = [`loudnorm=I=${I}:TP=${TP}:LRA=${LRA}`];
|
|
3367
|
-
const m = target.measured;
|
|
3368
|
-
if (m && !measure) {
|
|
3369
|
-
for (const [k, v] of Object.entries(m)) if (!Number.isFinite(v)) throw new Error(`The measured ${k} is not a number (${v}); measure again, or leave "measured" out for a one-pass normalisation.`);
|
|
3370
|
-
parts.push(`measured_I=${m.integrated}:measured_TP=${m.truePeak}:measured_LRA=${m.range}:measured_thresh=${m.threshold}:offset=${m.offset}:linear=true`);
|
|
3371
|
-
}
|
|
3372
|
-
if (measure) parts.push("print_format=json");
|
|
3373
|
-
return `${parts.join(":")},aresample=48000`;
|
|
3374
|
-
}
|
|
3375
|
-
function parseVideoLoudnessMeasurement(output) {
|
|
3376
|
-
const blocks = output.match(/\{[^{}]*"input_i"[^{}]*\}/g);
|
|
3377
|
-
if (!blocks) throw new Error("No loudness measurement found: pass the stderr of the command from toVideoLoudnessMeasure.");
|
|
3378
|
-
const json = JSON.parse(blocks[blocks.length - 1]);
|
|
3379
|
-
const n2 = (k) => Number(json[k]);
|
|
3380
|
-
const m = { integrated: n2("input_i"), truePeak: n2("input_tp"), range: n2("input_lra"), threshold: n2("input_thresh"), offset: n2("target_offset") };
|
|
3381
|
-
if (!Number.isFinite(m.integrated)) throw new Error("The mix is silent, so its loudness cannot be normalised.");
|
|
3382
|
-
return m;
|
|
3383
|
-
}
|
|
3384
|
-
var sec = (ms) => String(Math.round(ms) / 1e3);
|
|
3385
|
-
var fmtMs = (v) => String(Math.round(v * 100) / 100);
|
|
3386
|
-
var FFMPEG_BLEND = {
|
|
3387
|
-
multiply: "multiply",
|
|
3388
|
-
screen: "screen",
|
|
3389
|
-
overlay: "overlay",
|
|
3390
|
-
darken: "darken",
|
|
3391
|
-
lighten: "lighten",
|
|
3392
|
-
"color-dodge": "dodge",
|
|
3393
|
-
"color-burn": "burn",
|
|
3394
|
-
"hard-light": "hardlight",
|
|
3395
|
-
"soft-light": "softlight",
|
|
3396
|
-
difference: "difference",
|
|
3397
|
-
exclusion: "exclusion",
|
|
3398
|
-
add: "addition"
|
|
3399
|
-
};
|
|
3400
|
-
var AFADE_CURVES = { linear: "tri", "equal-power": "qsin", "s-curve": "hsin", exponential: "cub", logarithmic: "ipar" };
|
|
3401
|
-
var afadeCurve = (curve) => curve && curve !== "linear" ? `:curve=${AFADE_CURVES[curve]}` : "";
|
|
3402
|
-
var even = (v) => Math.max(2, 2 * Math.round(v / 2));
|
|
3403
|
-
var ffmpegFilterValue = (s) => s.replace(/[\\':%]/g, (c) => `\\${c}`).replace(/[\\'[\],;]/g, (c) => `\\${c}`);
|
|
3404
|
-
var color = (c) => {
|
|
3405
|
-
const hex = /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(c);
|
|
3406
|
-
if (!hex) return c.replace(/[^A-Za-z0-9@.]/g, "");
|
|
3407
|
-
const h = hex[1].length === 3 ? [...hex[1]].map((x) => x + x).join("") : hex[1];
|
|
3408
|
-
return `0x${h.slice(0, 6)}${h.length === 8 ? `@${(parseInt(h.slice(6), 16) / 255).toFixed(3)}` : ""}`;
|
|
3409
|
-
};
|
|
3410
|
-
var videoShellQuote = (s) => /^[\w@%+=:,./-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`;
|
|
3411
|
-
function atempo(speed) {
|
|
3412
|
-
const out = [];
|
|
3413
|
-
let s = speed;
|
|
3414
|
-
while (s > 2) {
|
|
3415
|
-
out.push("atempo=2");
|
|
3416
|
-
s /= 2;
|
|
3417
|
-
}
|
|
3418
|
-
while (s < 0.5) {
|
|
3419
|
-
out.push("atempo=0.5");
|
|
3420
|
-
s /= 0.5;
|
|
3421
|
-
}
|
|
3422
|
-
if (Math.abs(s - 1) > 1e-6) out.push(`atempo=${Math.round(s * 1e6) / 1e6}`);
|
|
3423
|
-
return out;
|
|
3424
|
-
}
|
|
3425
|
-
function toVideoFfmpeg(project, options = {}) {
|
|
3426
|
-
return buildFfmpeg(project, options, false);
|
|
3427
|
-
}
|
|
3428
|
-
function toVideoLoudnessMeasure(project, options = {}) {
|
|
3429
|
-
return buildFfmpeg(project, { ...options, loudness: { ...options.loudness, measured: void 0 } }, true);
|
|
3430
|
-
}
|
|
3431
|
-
function buildFfmpeg(project, options, measure) {
|
|
3432
|
-
const notes = [];
|
|
3433
|
-
const assets = videoAssetMap(project);
|
|
3434
|
-
const sequences = videoSequenceMap(project);
|
|
3435
|
-
const D = videoProjectDuration(project);
|
|
3436
|
-
if (D <= 0) throw new Error("The project has no clips, so there is nothing to render.");
|
|
3437
|
-
const W = even(project.width);
|
|
3438
|
-
const H = even(project.height);
|
|
3439
|
-
const fps = project.fps;
|
|
3440
|
-
const inputs = [];
|
|
3441
|
-
const graph = measure ? [] : [`color=c=${color(_nullishCoalesce(project.background, () => ( "#000000")))}:s=${W}x${H}:r=${fps}:d=${sec(D)},format=yuva420p[base]`];
|
|
3442
|
-
let usesDrawtext = false;
|
|
3443
|
-
const animated = /* @__PURE__ */ new Set();
|
|
3444
|
-
const ramped = /* @__PURE__ */ new Set();
|
|
3445
|
-
const rampedPicture = (remap, lead, end) => {
|
|
3446
|
-
const pts = videoTimeRemapBreakpoints(remap, 2e3 / fps);
|
|
3447
|
-
const first = pts[0];
|
|
3448
|
-
const last = pts[pts.length - 1];
|
|
3449
|
-
const s = `(T*1000+${fmtMs(first.v)})`;
|
|
3450
|
-
let e = fmtMs(last.t - first.t);
|
|
3451
|
-
for (let i = pts.length - 2; i >= 0; i--) {
|
|
3452
|
-
const a = pts[i];
|
|
3453
|
-
const b = pts[i + 1];
|
|
3454
|
-
if (b.v - a.v < 1e-6) continue;
|
|
3455
|
-
e = `if(lt(${s},${fmtMs(b.v)}),${fmtMs(a.t - first.t)}+(${s}-${fmtMs(a.v)})*${fmtMs((b.t - a.t) / (b.v - a.v))},${e})`;
|
|
3456
|
-
}
|
|
3457
|
-
const before = lead + first.t;
|
|
3458
|
-
const after = Math.max(0, end - last.t);
|
|
3459
|
-
return ["setpts=PTS-STARTPTS", `setpts='(${e})/1000/TB'`, `fps=${fps}`, ...before > 0.5 || after > 0.5 ? [`tpad=start_mode=clone:start_duration=${sec(before)}:stop_mode=clone:stop_duration=${sec(after + 1e3 / fps)}`] : [`tpad=stop_mode=clone:stop_duration=${sec(1e3 / fps)}`], `trim=duration=${sec(lead + end)}`];
|
|
3460
|
-
};
|
|
3461
|
-
const rampedSound = (remap, input2, output, lead, end) => {
|
|
3462
|
-
const pts = videoTimeRemapBreakpoints(remap, Math.max(80, 2e3 / fps));
|
|
3463
|
-
const first = pts[0];
|
|
3464
|
-
const last = pts[pts.length - 1];
|
|
3465
|
-
const n2 = ak;
|
|
3466
|
-
const fmtA = "aformat=sample_fmts=fltp:sample_rates=48000:channel_layouts=stereo";
|
|
3467
|
-
const silence = (ms) => `anullsrc=r=48000:cl=stereo,atrim=duration=${sec(ms)},${fmtA}`;
|
|
3468
|
-
const pieces = [];
|
|
3469
|
-
const out = [];
|
|
3470
|
-
const parts = [];
|
|
3471
|
-
if (lead + first.t > 0.5) parts.push(silence(lead + first.t));
|
|
3472
|
-
const played = [];
|
|
3473
|
-
for (let i = 0; i + 1 < pts.length; i++) {
|
|
3474
|
-
const dt = pts[i + 1].t - pts[i].t;
|
|
3475
|
-
if (dt < 0.5) continue;
|
|
3476
|
-
const speed = (pts[i + 1].v - pts[i].v) / dt;
|
|
3477
|
-
if (speed < 0.1) parts.push(silence(dt));
|
|
3478
|
-
else {
|
|
3479
|
-
played.push({ from: pts[i].v - first.v, to: pts[i + 1].v - first.v, speed });
|
|
3480
|
-
parts.push(`#${played.length - 1}`);
|
|
3481
|
-
}
|
|
3482
|
-
}
|
|
3483
|
-
if (end - last.t > 0.5) parts.push(silence(end - last.t));
|
|
3484
|
-
if (played.length) out.push(`[${input2}]asplit=${played.length}${played.map((_, k2) => `[r${n2}s${k2}]`).join("")}`);
|
|
3485
|
-
parts.forEach((p, k2) => {
|
|
3486
|
-
const label = `[r${n2}p${k2}]`;
|
|
3487
|
-
if (p.startsWith("#")) {
|
|
3488
|
-
const piece = played[Number(p.slice(1))];
|
|
3489
|
-
out.push(`[r${n2}s${p.slice(1)}]atrim=start=${sec(piece.from)}:end=${sec(piece.to)},asetpts=PTS-STARTPTS,${atempo(piece.speed).join(",") || "anull"},${fmtA}${label}`);
|
|
3490
|
-
} else out.push(`${p}${label}`);
|
|
3491
|
-
pieces.push(label);
|
|
3492
|
-
});
|
|
3493
|
-
out.push(`${pieces.join("")}concat=n=${pieces.length}:v=0:a=1${output}`);
|
|
3494
|
-
return out;
|
|
3495
|
-
};
|
|
3496
|
-
const blended = /* @__PURE__ */ new Set();
|
|
3497
|
-
let k = 0;
|
|
3498
|
-
const step = 2e3 / fps;
|
|
3499
|
-
const expr = (prop, clipTime, fallback, what) => {
|
|
3500
|
-
if (isVideoKeyframes(prop)) animated.add(what);
|
|
3501
|
-
return videoKeyframeFfmpegExpr(prop, clipTime, fallback, step);
|
|
3502
|
-
};
|
|
3503
|
-
const input = (clip, asset, lead, tail) => {
|
|
3504
|
-
const speed = videoClipSpeed(clip);
|
|
3505
|
-
const src = options.resolve ? options.resolve(asset) : asset.src;
|
|
3506
|
-
const span = clip.duration + lead + tail;
|
|
3507
|
-
if (asset.kind === "image") inputs.push(["-loop", "1", "-framerate", String(fps), "-t", sec(span), "-i", src]);
|
|
3508
|
-
else if (clip.timeRemap) {
|
|
3509
|
-
const { from, to } = videoTimeRemapSpan(clip.timeRemap);
|
|
3510
|
-
inputs.push(["-ss", sec((_nullishCoalesce(clip.in, () => ( 0))) + from), "-t", sec(to - from + 1e3 / fps), "-i", src]);
|
|
3511
|
-
} else inputs.push(["-ss", sec((_nullishCoalesce(clip.in, () => ( 0))) - lead * speed), "-t", sec(span * speed), "-i", src]);
|
|
3512
|
-
return inputs.length - 1;
|
|
3513
|
-
};
|
|
3514
|
-
let ak = 0;
|
|
3515
|
-
let q = 0;
|
|
3516
|
-
const compose = (tracks, base, length, scope) => {
|
|
3517
|
-
let cur2 = base;
|
|
3518
|
-
const sounds = [];
|
|
3519
|
-
for (const track of [...tracks].reverse()) {
|
|
3520
|
-
for (const raw of sortedVideoClips(track)) {
|
|
3521
|
-
const clip = videoClipAnimated(raw, project);
|
|
3522
|
-
const { lead, tail } = videoClipOverhang(track, clip);
|
|
3523
|
-
const t0 = clip.start - lead;
|
|
3524
|
-
const span = clip.duration + lead + tail;
|
|
3525
|
-
const end = videoClipEnd(clip);
|
|
3526
|
-
const asset = clip.type === "media" ? assets.get(clip.asset) : void 0;
|
|
3527
|
-
if (clip.type === "media" && !asset) {
|
|
3528
|
-
notes.push(`Clip "${clip.id}" was left out: its asset "${clip.asset}" is missing.`);
|
|
3529
|
-
continue;
|
|
3530
|
-
}
|
|
3531
|
-
const shows = scope.picture && track.kind === "video" && !track.hidden;
|
|
3532
|
-
let compound = null;
|
|
3533
|
-
if (clip.type === "sequence") {
|
|
3534
|
-
const seq = sequences.get(clip.sequence);
|
|
3535
|
-
if (!seq || scope.within.includes(seq.id)) {
|
|
3536
|
-
notes.push(`Compound clip "${clip.id}" was left out: its sequence "${clip.sequence}" ${seq ? "contains itself" : "is missing"}.`);
|
|
3537
|
-
continue;
|
|
3538
|
-
}
|
|
3539
|
-
const from = (_nullishCoalesce(clip.in, () => ( 0))) - lead;
|
|
3540
|
-
if (from < -0.5) notes.push(`Compound clip "${clip.id}"'s transition needs ${Math.round(-from)} ms of sequence "${seq.id}" before its start, which is not there; it shows nothing then.`);
|
|
3541
|
-
const length2 = Math.max(videoSequenceDuration(seq), from + span);
|
|
3542
|
-
const hears = scope.sound && !clip.muted && !track.muted;
|
|
3543
|
-
const n2 = q++;
|
|
3544
|
-
const nestedBase = shows ? `nb${n2}` : null;
|
|
3545
|
-
if (nestedBase) graph.push(`color=c=black@0:s=${W}x${H}:r=${fps}:d=${sec(length2)},format=yuva420p[${nestedBase}]`);
|
|
3546
|
-
const sub = compose(seq.tracks, nestedBase, length2, { within: [...scope.within, seq.id], picture: shows, sound: hears });
|
|
3547
|
-
compound = { picture: null, sound: null };
|
|
3548
|
-
if (sub.video) {
|
|
3549
|
-
graph.push(`[${sub.video}]trim=start=${sec(Math.max(0, from))}:duration=${sec(span)},setpts=PTS-STARTPTS[sq${n2}]`);
|
|
3550
|
-
compound.picture = `[sq${n2}]`;
|
|
3551
|
-
}
|
|
3552
|
-
if (sub.audio.length) {
|
|
3553
|
-
graph.push(`${sub.audio.join("")}amix=inputs=${sub.audio.length}:normalize=0:duration=longest,apad,atrim=start=${sec(Math.max(0, from))}:end=${sec(from + span)}[sm${n2}]`);
|
|
3554
|
-
compound.sound = `[sm${n2}]`;
|
|
3555
|
-
}
|
|
3556
|
-
}
|
|
3557
|
-
let index;
|
|
3558
|
-
if (shows && asset && asset.kind !== "audio") index = input(clip, asset, lead, tail);
|
|
3559
|
-
const audible = clip.type === "sequence" ? !!_optionalChain([compound, 'optionalAccess', _70 => _70.sound]) : videoAssetHasSound(asset);
|
|
3560
|
-
if (scope.sound && audible && (clip.type === "media" || clip.type === "sequence") && !clip.muted && !track.muted) {
|
|
3561
|
-
const trackGain = _nullishCoalesce(track.volume, () => ( 1));
|
|
3562
|
-
const volume = isVideoKeyframes(clip.volume) ? `volume='${trackGain}*(${expr(clip.volume, `(t*1000${lead ? `-${Math.round(lead)}` : ""})`, 1, "volume")})':eval=frame` : `volume=${(_nullishCoalesce(clip.volume, () => ( 1))) * trackGain}`;
|
|
3563
|
-
const ramp = clip.type === "media" ? clip.timeRemap : void 0;
|
|
3564
|
-
const ai = compound ? -1 : _nullishCoalesce(index, () => ( input(clip, asset, lead, tail)));
|
|
3565
|
-
let source2 = _nullishCoalesce(_optionalChain([compound, 'optionalAccess', _71 => _71.sound]), () => ( `[${ai}:a]`));
|
|
3566
|
-
if (ramp) {
|
|
3567
|
-
source2 = `[r${ak}]`;
|
|
3568
|
-
graph.push(...rampedSound(ramp, `${ai}:a`, source2, lead, clip.duration + tail));
|
|
3569
|
-
ramped.add("sound");
|
|
3570
|
-
}
|
|
3571
|
-
const chain2 = [...ramp ? [] : ["asetpts=PTS-STARTPTS", ...atempo(videoClipSpeed(clip))], volume];
|
|
3572
|
-
const before2 = clip.transition ? videoClipBefore(track, clip) : null;
|
|
3573
|
-
const next2 = sortedVideoClips(track).find((c) => c !== clip && Math.abs(c.start - end) < 0.5 && c.transition);
|
|
3574
|
-
const inCurve = clip.transition ? afadeCurve(videoTransitionAudioCurve(clip.transition)) : "";
|
|
3575
|
-
const outCurve = next2 ? afadeCurve(videoTransitionAudioCurve(next2.transition)) : "";
|
|
3576
|
-
if (lead) chain2.push(`afade=t=in:st=0:d=${sec(2 * lead)}${inCurve}`);
|
|
3577
|
-
if (tail) chain2.push(`afade=t=out:st=${sec(span - 2 * tail)}:d=${sec(2 * tail)}${outCurve}`);
|
|
3578
|
-
if (before2 && clip.transition.type === "dip") chain2.push(`afade=t=in:st=0:d=${sec(clip.transition.duration / 2)}${inCurve}`);
|
|
3579
|
-
if (_optionalChain([next2, 'optionalAccess', _72 => _72.transition, 'access', _73 => _73.type]) === "dip") chain2.push(`afade=t=out:st=${sec(span - next2.transition.duration / 2)}:d=${sec(next2.transition.duration / 2)}${outCurve}`);
|
|
3580
|
-
if (clip.fadeIn) chain2.push(`afade=t=in:st=${sec(lead)}:d=${sec(clip.fadeIn)}${afadeCurve(clip.fadeInCurve)}`);
|
|
3581
|
-
if (clip.fadeOut) chain2.push(`afade=t=out:st=${sec(lead + clip.duration - clip.fadeOut)}:d=${sec(clip.fadeOut)}${afadeCurve(clip.fadeOutCurve)}`);
|
|
3582
|
-
chain2.push(`adelay=${Math.round(t0)}:all=1`);
|
|
3583
|
-
graph.push(`${source2}${chain2.join(",")}[a${ak}]`);
|
|
3584
|
-
sounds.push(`[a${ak++}]`);
|
|
3585
|
-
}
|
|
3586
|
-
if (!shows || compound && !compound.picture) continue;
|
|
3587
|
-
const enable = `enable='between(t,${sec(t0)},${sec(t0 + span)})'`;
|
|
3588
|
-
const next = `v${k++}`;
|
|
3589
|
-
const onTimeline = `(t*1000-${Math.round(clip.start)})`;
|
|
3590
|
-
const onChain = (v) => `(${v}*1000${lead ? `-${Math.round(lead)}` : ""})`;
|
|
3591
|
-
const tf = clip.transform;
|
|
3592
|
-
const moving = VIDEO_TRANSFORM_PROPERTIES.some((p) => isVideoKeyframes(_optionalChain([tf, 'optionalAccess', _74 => _74[p]])));
|
|
3593
|
-
if (clip.type === "text" && options.titleImage) {
|
|
3594
|
-
inputs.push(["-loop", "1", "-framerate", String(fps), "-t", sec(span), "-i", options.titleImage(moving ? { ...clip, transform: void 0 } : clip, { width: project.width, height: project.height })]);
|
|
3595
|
-
index = inputs.length - 1;
|
|
3596
|
-
} else if (clip.type === "text") {
|
|
3597
|
-
usesDrawtext = true;
|
|
3598
|
-
if (scope.within.length) notes.push(`Title "${clip.id}" is inside a compound clip and drawn with drawtext, which leaves the sequence's transparent areas transparent, so it shows only over pictures in the sequence; pass titleImage to draw it anywhere.`);
|
|
3599
|
-
const op = isVideoKeyframes(clip.opacity) ? `clip(${expr(clip.opacity, onTimeline, 1, "opacity")},0,1)` : String(_nullishCoalesce(clip.opacity, () => ( 1)));
|
|
3600
|
-
const alpha = [op, clip.fadeIn ? `min(1,(t-${sec(clip.start)})/${sec(clip.fadeIn)})` : "", clip.fadeOut ? `min(1,(${sec(end)}-t)/${sec(clip.fadeOut)})` : ""].filter(Boolean).join("*");
|
|
3601
|
-
const coord = (axis) => {
|
|
3602
|
-
const v = _optionalChain([tf, 'optionalAccess', _75 => _75[axis]]);
|
|
3603
|
-
const base2 = `(${axis === "x" ? "w-text_w" : "h-text_h"})/2`;
|
|
3604
|
-
return isVideoKeyframes(v) ? `${axis}='${base2}+(${expr(v, onTimeline, 0, "position")})'` : `${axis}=${base2}+${_nullishCoalesce(v, () => ( 0))}`;
|
|
3605
|
-
};
|
|
3606
|
-
const fontSize = _nullishCoalesce(clip.fontSize, () => ( 64));
|
|
3607
|
-
const opts = [
|
|
3608
|
-
`text=${ffmpegFilterValue(clip.text)}`,
|
|
3609
|
-
options.fontFile ? `fontfile=${ffmpegFilterValue(options.fontFile)}` : `font=${ffmpegFilterValue(_nullishCoalesce(clip.fontFamily, () => ( "sans-serif")))}`,
|
|
3610
|
-
isVideoKeyframes(_optionalChain([tf, 'optionalAccess', _76 => _76.scale])) ? `fontsize='${fontSize}*(${expr(tf.scale, onTimeline, 1, "scale")})'` : `fontsize=${Math.round(fontSize * (_nullishCoalesce(_optionalChain([tf, 'optionalAccess', _77 => _77.scale]), () => ( 1))))}`,
|
|
3611
|
-
`fontcolor=${color(_nullishCoalesce(clip.color, () => ( "#ffffff")))}`,
|
|
3612
|
-
coord("x"),
|
|
3613
|
-
coord("y"),
|
|
3614
|
-
`alpha='${alpha}'`,
|
|
3615
|
-
...clip.background ? ["box=1", `boxcolor=${color(clip.background)}`, `boxborderw=${Math.round((_nullishCoalesce(clip.fontSize, () => ( 64))) / 2)}`] : [],
|
|
3616
|
-
`enable='between(t,${sec(clip.start)},${sec(end)})'`
|
|
3617
|
-
];
|
|
3618
|
-
if (_optionalChain([tf, 'optionalAccess', _78 => _78.rotation])) notes.push(`Title "${clip.id}" is drawn without its rotation (drawtext cannot rotate).`);
|
|
3619
|
-
if (videoGradeFfmpegFilters(clip.grade).length || normalizeVideoGradeLut(_optionalChain([clip, 'access', _79 => _79.grade, 'optionalAccess', _80 => _80.lut]))) notes.push(`Title "${clip.id}" is drawn without its grade (drawtext draws straight onto the picture); pass titleImage to grade titles.`);
|
|
3620
|
-
if (clip.blend && clip.blend !== "normal") notes.push(`Title "${clip.id}" is drawn without its blend mode (drawtext draws straight onto the picture); pass titleImage to blend titles.`);
|
|
3621
|
-
graph.push(`[${cur2}]drawtext=${opts.join(":")}[${next}]`);
|
|
3622
|
-
cur2 = next;
|
|
3623
|
-
continue;
|
|
3624
|
-
}
|
|
3625
|
-
const size = asset ? { width: _nullishCoalesce(asset.width, () => ( project.width)), height: _nullishCoalesce(asset.height, () => ( project.height)) } : { width: project.width, height: project.height };
|
|
3626
|
-
const placed = clip.type === "text" && !moving ? void 0 : tf;
|
|
3627
|
-
const still = Object.fromEntries(Object.entries(_nullishCoalesce(placed, () => ( {}))).filter(([, v]) => !isVideoKeyframes(v)));
|
|
3628
|
-
const rect = placeVideoRect(project, size, clip.type === "text" ? "fill" : _nullishCoalesce(clip.fit, () => ( (clip.type === "media" || clip.type === "sequence" ? "contain" : "fill"))), still);
|
|
3629
|
-
const chain = [];
|
|
3630
|
-
let source;
|
|
3631
|
-
if (clip.type === "color") source = `color=c=${color(clip.color)}:s=${even(rect.width)}x${even(rect.height)}:r=${fps}:d=${sec(span)}`;
|
|
3632
|
-
else if (_optionalChain([compound, 'optionalAccess', _81 => _81.picture])) {
|
|
3633
|
-
source = compound.picture;
|
|
3634
|
-
chain.push(`scale=${even(rect.width)}:${even(rect.height)}`);
|
|
3635
|
-
} else {
|
|
3636
|
-
source = `[${index}:v]`;
|
|
3637
|
-
if (clip.type === "media" && clip.timeRemap) chain.push(...rampedPicture(clip.timeRemap, lead, clip.duration + tail), `scale=${even(rect.width)}:${even(rect.height)}`);
|
|
3638
|
-
else chain.push(`setpts=${videoClipSpeed(clip) !== 1 ? `(PTS-STARTPTS)/${videoClipSpeed(clip)}` : "PTS-STARTPTS"}`, `fps=${fps}`, `scale=${even(rect.width)}:${even(rect.height)}`);
|
|
3639
|
-
}
|
|
3640
|
-
const grade = videoGradeFfmpegFilters(clip.grade);
|
|
3641
|
-
if (grade.length) chain.push("format=rgba", ...grade);
|
|
3642
|
-
const lut = normalizeVideoGradeLut(_optionalChain([clip, 'access', _82 => _82.grade, 'optionalAccess', _83 => _83.lut]));
|
|
3643
|
-
if (lut) {
|
|
3644
|
-
chain.push("format=gbrap");
|
|
3645
|
-
const path = options.resolveLut ? options.resolveLut(lut.src) : lut.src;
|
|
3646
|
-
if (/^(blob|data|https?):/i.test(path)) notes.push(`ffmpeg's lut3d reads only local files, and clip "${clip.id}"'s LUT is "${path.slice(0, 80)}"; save it and pass resolveLut to give its path.`);
|
|
3647
|
-
const file = ffmpegFilterValue(path);
|
|
3648
|
-
const into2 = `q${next}`;
|
|
3649
|
-
graph.push(`${source.startsWith("[") ? source : `${source},`}${chain.join(",")}[${into2}]`);
|
|
3650
|
-
const lut3d = `lut3d=file=${file}:interp=tetrahedral`;
|
|
3651
|
-
if ((_nullishCoalesce(lut.strength, () => ( 1))) >= 1) graph.push(`[${into2}]${lut3d}[r${next}]`);
|
|
3652
|
-
else graph.push(`[${into2}]split[o${next}][p${next}]`, `[p${next}]${lut3d}[s${next}]`, `[s${next}][o${next}]blend=all_mode=normal:all_opacity=${lut.strength}[r${next}]`);
|
|
3653
|
-
source = `[r${next}]`;
|
|
3654
|
-
chain.length = 0;
|
|
3655
|
-
}
|
|
3656
|
-
chain.push("format=yuva420p");
|
|
3657
|
-
if (isVideoKeyframes(clip.opacity)) chain.push(`geq=lum='lum(X,Y)':cb='cb(X,Y)':cr='cr(X,Y)':a='alpha(X,Y)*clip(${expr(clip.opacity, onChain("T"), 1, "opacity")},0,1)'`);
|
|
3658
|
-
else if (clip.opacity !== void 0 && clip.opacity < 1) chain.push(`colorchannelmixer=aa=${clip.opacity}`);
|
|
3659
|
-
if (clip.fadeIn) chain.push(`fade=t=in:st=${sec(lead)}:d=${sec(clip.fadeIn)}:alpha=1`);
|
|
3660
|
-
if (clip.fadeOut) chain.push(`fade=t=out:st=${sec(lead + clip.duration - clip.fadeOut)}:d=${sec(clip.fadeOut)}:alpha=1`);
|
|
3661
|
-
if (lead && clip.transition.type === "crossfade") chain.push(`fade=t=in:st=0:d=${sec(2 * lead)}:alpha=1`);
|
|
3662
|
-
if (lead && clip.transition.type === "wipe") {
|
|
3663
|
-
const d = sec(2 * lead);
|
|
3664
|
-
const p = `min(1,T/${d})`;
|
|
3665
|
-
const dir = _nullishCoalesce(clip.transition.direction, () => ( "right"));
|
|
3666
|
-
const test = dir === "right" ? `lt(X,W*${p})` : dir === "left" ? `gt(X,W*(1-${p}))` : dir === "down" ? `lt(Y,H*${p})` : `gt(Y,H*(1-${p}))`;
|
|
3667
|
-
chain.push(`geq=lum='lum(X,Y)':cb='cb(X,Y)':cr='cr(X,Y)':a='if(${test},alpha(X,Y),0)'`);
|
|
3668
|
-
}
|
|
3669
|
-
if (lead && clip.transition.type === "iris") {
|
|
3670
|
-
const r = videoIrisRadius({ width: W, height: H }, 1);
|
|
3671
|
-
chain.push(`geq=lum='lum(X,Y)':cb='cb(X,Y)':cr='cr(X,Y)':a='if(lte(hypot(X+${Math.round(rect.x)}-${W / 2},Y+${Math.round(rect.y)}-${H / 2}),${Math.round(r)}*min(1,T/${sec(2 * lead)})),alpha(X,Y),0)'`);
|
|
3672
|
-
}
|
|
3673
|
-
const rotation = _optionalChain([placed, 'optionalAccess', _84 => _84.rotation]);
|
|
3674
|
-
if (isVideoKeyframes(rotation)) chain.push(`rotate=a='(${expr(rotation, onChain("t"), 0, "rotation")})*PI/180':c=black@0:ow='hypot(iw,ih)':oh=ow`);
|
|
3675
|
-
else if (rotation) chain.push(`rotate=${rotation}*PI/180:c=black@0:ow=rotw(${rotation}*PI/180):oh=roth(${rotation}*PI/180)`);
|
|
3676
|
-
if (isVideoKeyframes(_optionalChain([placed, 'optionalAccess', _85 => _85.scale]))) {
|
|
3677
|
-
const s = expr(placed.scale, onChain("t"), 1, "scale");
|
|
3678
|
-
chain.push(`scale=w='max(2,trunc(iw*(${s})/2)*2)':h='max(2,trunc(ih*(${s})/2)*2)':eval=frame`);
|
|
3679
|
-
}
|
|
3680
|
-
chain.push(`setpts=PTS+${sec(t0)}/TB`);
|
|
3681
|
-
const cx = rect.x + rect.width / 2;
|
|
3682
|
-
const cy = rect.y + rect.height / 2;
|
|
3683
|
-
const shifts = { x: [], y: [] };
|
|
3684
|
-
const shiftBy = (direction, from, d, entering) => {
|
|
3685
|
-
const dir = _nullishCoalesce(direction, () => ( "right"));
|
|
3686
|
-
const axis = dir === "left" || dir === "right" ? "x" : "y";
|
|
3687
|
-
const size2 = axis === "x" ? W : H;
|
|
3688
|
-
const sign = dir === "left" || dir === "up" ? -1 : 1;
|
|
3689
|
-
const ease = `(1-cos(PI*clip((t-${sec(from)})/${sec(d)},0,1)))/2`;
|
|
3690
|
-
shifts[axis].push(`${sign * size2}*(${ease}${entering ? "-1" : ""})`);
|
|
3691
|
-
};
|
|
3692
|
-
const into = lead ? clip.transition.type : void 0;
|
|
3693
|
-
if (into === "push" || into === "slide") shiftBy(clip.transition.direction, clip.start - lead, 2 * lead, true);
|
|
3694
|
-
const after = tail ? sortedVideoClips(track).find((c) => c !== clip && Math.abs(c.start - end) < 0.5 && c.transition) : void 0;
|
|
3695
|
-
if (_optionalChain([after, 'optionalAccess', _86 => _86.transition, 'access', _87 => _87.type]) === "push") shiftBy(after.transition.direction, end - tail, 2 * tail, false);
|
|
3696
|
-
const at = (axis, c) => {
|
|
3697
|
-
const v = _optionalChain([placed, 'optionalAccess', _88 => _88[axis]]);
|
|
3698
|
-
const extra = shifts[axis].map((s) => `+${s}`).join("");
|
|
3699
|
-
return isVideoKeyframes(v) ? `${axis}='${Math.round(axis === "x" ? project.width / 2 : project.height / 2)}+(${expr(v, onTimeline, 0, "position")})-${axis === "x" ? "w" : "h"}/2${extra}'` : `${axis}='${Math.round(c)}-${axis === "x" ? "w" : "h"}/2${extra}'`;
|
|
3700
|
-
};
|
|
3701
|
-
graph.push(`${source.startsWith("[") ? source : `${source},`}${chain.join(",")}[l${next}]`);
|
|
3702
|
-
if (clip.blend && clip.blend !== "normal") {
|
|
3703
|
-
graph.push(`color=c=black@0:s=${W}x${H}:r=${fps}:d=${sec(length)},format=yuva420p[t${next}]`);
|
|
3704
|
-
const clear = scope.within.length > 0;
|
|
3705
|
-
graph.push(`[t${next}][l${next}]overlay=${at("x", cx)}:${at("y", cy)}:eof_action=pass:${enable},format=gbrap,split${clear ? `=3` : ""}[f${next}][g${next}]${clear ? `[h${next}]` : ""}`);
|
|
3706
|
-
graph.push(`[${cur2}]format=gbrap,split${clear ? `=3` : ""}[c${next}][d${next}]${clear ? `[e${next}]` : ""}`);
|
|
3707
|
-
const layerFirst = clip.blend === "color-dodge" || clip.blend === "color-burn";
|
|
3708
|
-
graph.push(`${layerFirst ? `[f${next}][c${next}]` : `[c${next}][f${next}]`}blend=all_mode=${FFMPEG_BLEND[clip.blend]}[b${next}]`);
|
|
3709
|
-
graph.push(`[g${next}]alphaextract[m${next}]`);
|
|
3710
|
-
if (clear) {
|
|
3711
|
-
graph.push(`[e${next}]alphaextract[ea${next}]`);
|
|
3712
|
-
graph.push(`[b${next}][ea${next}]alphamerge[bb${next}]`);
|
|
3713
|
-
graph.push(`[h${next}]format=gbrp[ho${next}]`);
|
|
3714
|
-
graph.push(`[ho${next}][bb${next}]overlay=format=gbrp[bm${next}]`);
|
|
3715
|
-
graph.push(`[bm${next}][m${next}]alphamerge[x${next}]`);
|
|
3716
|
-
} else graph.push(`[b${next}][m${next}]alphamerge[x${next}]`);
|
|
3717
|
-
graph.push(`[d${next}][x${next}]overlay=format=gbrp,format=yuva420p[${next}]`);
|
|
3718
|
-
blended.add(clip.blend);
|
|
3719
|
-
} else graph.push(`[${cur2}][l${next}]overlay=${at("x", cx)}:${at("y", cy)}:eof_action=pass:${enable}[${next}]`);
|
|
3720
|
-
cur2 = next;
|
|
3721
|
-
const before = clip.transition ? videoClipBefore(track, clip) : null;
|
|
3722
|
-
if (before && clip.transition.type === "dip") {
|
|
3723
|
-
const d = clip.transition.duration;
|
|
3724
|
-
const dip = `d${k}`;
|
|
3725
|
-
graph.push(`color=c=${color(_nullishCoalesce(clip.transition.color, () => ( "#000000")))}:s=${W}x${H}:r=${fps}:d=${sec(d)},format=yuva420p,fade=t=in:st=0:d=${sec(d / 2)}:alpha=1,fade=t=out:st=${sec(d / 2)}:d=${sec(d / 2)}:alpha=1,setpts=PTS+${sec(clip.start - d / 2)}/TB[l${dip}]`);
|
|
3726
|
-
graph.push(`[${cur2}][l${dip}]overlay=eof_action=pass:enable='between(t,${sec(clip.start - d / 2)},${sec(clip.start + d / 2)})'[${dip}]`);
|
|
3727
|
-
cur2 = dip;
|
|
3728
|
-
}
|
|
3729
|
-
}
|
|
3730
|
-
}
|
|
3731
|
-
return { video: cur2, audio: sounds };
|
|
3732
|
-
};
|
|
3733
|
-
const top = compose(project.tracks, measure ? null : "base", D, { within: [], picture: !measure, sound: true });
|
|
3734
|
-
const audio = top.audio;
|
|
3735
|
-
const cur = top.video;
|
|
3736
|
-
if (!measure) graph.push(`[${cur}]format=yuv420p[vout]`);
|
|
3737
|
-
if (measure && !audio.length) throw new Error("Nothing on the timeline makes a sound, so there is no loudness to measure.");
|
|
3738
|
-
const loudness = options.loudness || measure ? `,${loudnormFilter(options.loudness, measure)}` : "";
|
|
3739
|
-
if (audio.length) graph.push(`${audio.join("")}amix=inputs=${audio.length}:normalize=0:duration=longest,apad,atrim=0:${sec(D)}${loudness}[aout]`);
|
|
3740
|
-
if (options.loudness && !audio.length) notes.push("Nothing makes a sound, so there was no loudness to normalise.");
|
|
3741
|
-
else if (options.loudness && !options.loudness.measured)
|
|
3742
|
-
notes.push("Loudness is normalised in one pass, which adjusts the level as it goes; for a fixed gain that keeps the dynamics, run toVideoLoudnessMeasure first and pass its result as loudness.measured.");
|
|
3743
|
-
if (allVideoTracks(project).some(({ track: t }) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _89 => _89.get, 'call', _90 => _90(c.asset), 'optionalAccess', _91 => _91.kind]) === "video" && _optionalChain([assets, 'access', _92 => _92.get, 'call', _93 => _93(c.asset), 'optionalAccess', _94 => _94.hasAudio]) === void 0)))
|
|
3744
|
-
notes.push('Video assets are assumed to have sound; set "hasAudio": false on any that do not, or ffmpeg will stop at a missing audio stream.');
|
|
3745
|
-
if (animated.size)
|
|
3746
|
-
notes.push(`Keyframed ${[...animated].sort().join(", ")} ${animated.size > 1 ? "are" : "is"} rendered as straight lines between keys, with eased segments sampled every two frames${animated.has("scale") ? "; animated scale needs ffmpeg 5 or later (scale with eval=frame)" : ""}.`);
|
|
3747
|
-
if (blended.has("soft-light")) notes.push("ffmpeg's soft-light blend uses a slightly different formula from the browser's, so the render can differ a little from the preview.");
|
|
3748
|
-
if (ramped.has("sound")) notes.push("Sound through a speed ramp plays each stretch at its own speed, so a gliding change is heard in small steps (about every 80 ms), and freezes are silent.");
|
|
3749
|
-
if (usesDrawtext) notes.push("Titles use drawtext, which needs an ffmpeg built with libfreetype (Homebrew's is not: check `ffmpeg -filters | grep drawtext`); pass titleImage to render them as images instead.");
|
|
3750
|
-
const filterComplex = graph.join(";");
|
|
3751
|
-
if (measure) {
|
|
3752
|
-
const args2 = ["-hide_banner", "-nostats", ...inputs.flat(), "-filter_complex", filterComplex, "-map", "[aout]", "-f", "null", "-"];
|
|
3753
|
-
return { args: args2, command: ["ffmpeg", ...args2].map(videoShellQuote).join(" "), filterComplex, duration: D, notes };
|
|
3754
|
-
}
|
|
3755
|
-
const args = [
|
|
3756
|
-
"-y",
|
|
3757
|
-
...inputs.flat(),
|
|
3758
|
-
"-filter_complex",
|
|
3759
|
-
filterComplex,
|
|
3760
|
-
"-map",
|
|
3761
|
-
"[vout]",
|
|
3762
|
-
...audio.length ? ["-map", "[aout]", "-c:a", _nullishCoalesce(options.audioCodec, () => ( "aac"))] : ["-an"],
|
|
3763
|
-
"-c:v",
|
|
3764
|
-
_nullishCoalesce(options.videoCodec, () => ( "libx264")),
|
|
3765
|
-
...(_nullishCoalesce(options.videoCodec, () => ( "libx264"))) === "libx264" ? ["-crf", String(_nullishCoalesce(options.crf, () => ( 18))), "-preset", "medium"] : [],
|
|
3766
|
-
"-pix_fmt",
|
|
3767
|
-
"yuv420p",
|
|
3768
|
-
"-r",
|
|
3769
|
-
String(fps),
|
|
3770
|
-
"-t",
|
|
3771
|
-
sec(D),
|
|
3772
|
-
_nullishCoalesce(options.output, () => ( "output.mp4"))
|
|
3773
|
-
];
|
|
3774
|
-
return { args, command: ["ffmpeg", ...args].map(videoShellQuote).join(" "), filterComplex, duration: D, notes };
|
|
3775
|
-
}
|
|
3776
|
-
|
|
3777
2114
|
// src/video-editor/proxy.ts
|
|
3778
2115
|
var VIDEO_PROXY_SCALES = [0.5, 0.25];
|
|
3779
2116
|
function videoAssetProxy(asset, scale) {
|
|
3780
|
-
if (!_optionalChain([asset, 'optionalAccess',
|
|
2117
|
+
if (!_optionalChain([asset, 'optionalAccess', _30 => _30.proxies, 'optionalAccess', _31 => _31.length]) || !(scale > 0) || scale >= 1) return null;
|
|
3781
2118
|
let best = null;
|
|
3782
2119
|
for (const p of asset.proxies) if (p.scale >= scale - 1e-9 && p.scale < 1 && (!best || p.scale < best.scale)) best = p;
|
|
3783
2120
|
return best;
|
|
3784
2121
|
}
|
|
3785
|
-
var videoPreviewSrc = (asset, scale, fallback = _nullishCoalesce(_optionalChain([asset, 'optionalAccess',
|
|
2122
|
+
var videoPreviewSrc = (asset, scale, fallback = _nullishCoalesce(_optionalChain([asset, 'optionalAccess', _32 => _32.src]), () => ( ""))) => _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _33 => _33(asset, scale), 'optionalAccess', _34 => _34.src]), () => ( fallback));
|
|
3786
2123
|
function resolveVideoPreviewScale(scale, shown) {
|
|
3787
2124
|
if (scale === void 0 || scale === "auto") return Math.min(1, Math.max(0, shown));
|
|
3788
2125
|
if (scale === "full") return 1;
|
|
@@ -3831,7 +2168,7 @@ function videoProxyFfmpeg(asset, options = {}) {
|
|
|
3831
2168
|
output
|
|
3832
2169
|
];
|
|
3833
2170
|
const proxy = { scale, src: output, ...asset.width && asset.height ? { width: Math.trunc(asset.width * scale / 2) * 2, height: Math.trunc(asset.height * scale / 2) * 2 } : {} };
|
|
3834
|
-
return { asset: asset.id, args, command: ["ffmpeg", ...args].map(videoShellQuote).join(" "), proxy };
|
|
2171
|
+
return { asset: asset.id, args, command: ["ffmpeg", ...args].map(_chunkSMJGE7HMcjs.videoShellQuote).join(" "), proxy };
|
|
3835
2172
|
}
|
|
3836
2173
|
function videoProxyPlan(project, options = {}) {
|
|
3837
2174
|
const scale = _nullishCoalesce(options.scale, () => ( 0.5));
|
|
@@ -3841,7 +2178,7 @@ function videoProxyPlan(project, options = {}) {
|
|
|
3841
2178
|
if (!a) throw new Error(`There is no asset "${id}"; the assets are ${project.assets.map((x) => `"${x.id}"`).join(", ") || "none"}.`);
|
|
3842
2179
|
if (a.kind !== "video") throw new Error(`Asset "${id}" is ${a.kind === "image" ? "an image" : "audio"}; only video assets have proxies.`);
|
|
3843
2180
|
}
|
|
3844
|
-
return project.assets.filter((a) => a.kind === "video" && (!wanted || wanted.has(a.id)) && !_optionalChain([a, 'access',
|
|
2181
|
+
return project.assets.filter((a) => a.kind === "video" && (!wanted || wanted.has(a.id)) && !_optionalChain([a, 'access', _35 => _35.proxies, 'optionalAccess', _36 => _36.some, 'call', _37 => _37((p) => Math.abs(p.scale - scale) < 1e-9)])).map((a) => videoProxyFfmpeg(a, { ...options, scale }));
|
|
3845
2182
|
}
|
|
3846
2183
|
var VIDEO_PREVIEW_SCALE_OPTIONS = [
|
|
3847
2184
|
{ value: "auto", label: "Auto", scale: "auto" },
|
|
@@ -3849,7 +2186,7 @@ var VIDEO_PREVIEW_SCALE_OPTIONS = [
|
|
|
3849
2186
|
...VIDEO_PROXY_SCALES.map((s) => ({ value: String(s), label: s === 0.5 ? "\xBD" : s === 0.25 ? "\xBC" : `${s * 100}%`, scale: s }))
|
|
3850
2187
|
];
|
|
3851
2188
|
var parseVideoPreviewScale = (value) => value === "full" ? "full" : Number(value) > 0 && Number(value) <= 1 ? Number(value) : "auto";
|
|
3852
|
-
var videoProjectHasProxies = (project) => project.assets.some((a) => !!_optionalChain([a, 'access',
|
|
2189
|
+
var videoProjectHasProxies = (project) => project.assets.some((a) => !!_optionalChain([a, 'access', _38 => _38.proxies, 'optionalAccess', _39 => _39.length]));
|
|
3853
2190
|
|
|
3854
2191
|
// src/video-editor/frame-cache.ts
|
|
3855
2192
|
var videoSourceFrame = (sourceTime, fps) => Math.max(0, Math.floor(sourceTime * fps / 1e3 + 1e-6));
|
|
@@ -3857,7 +2194,7 @@ var videoSourceFrameTime = (frame, fps) => (frame + 0.5) * 1e3 / fps;
|
|
|
3857
2194
|
var videoFrameCacheKey = (src, frame) => `${frame}@${src}`;
|
|
3858
2195
|
function videoFrameRequestsAt(project, time, srcFor = (l) => l.src) {
|
|
3859
2196
|
const out = [];
|
|
3860
|
-
for (const layer of videoFrameLeafLayers(videoFrameAt(project, time).layers)) {
|
|
2197
|
+
for (const layer of _chunkSMJGE7HMcjs.videoFrameLeafLayers.call(void 0, _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, project, time).layers)) {
|
|
3861
2198
|
if (layer.type !== "media" || layer.assetKind !== "video") continue;
|
|
3862
2199
|
const src = srcFor(layer);
|
|
3863
2200
|
if (!src) continue;
|
|
@@ -3884,7 +2221,7 @@ function planVideoPrefetch(project, time, options = {}) {
|
|
|
3884
2221
|
return out;
|
|
3885
2222
|
}
|
|
3886
2223
|
function videoCacheEvictions(entries, options) {
|
|
3887
|
-
let total = entries.reduce((
|
|
2224
|
+
let total = entries.reduce((n, e) => n + e.bytes, 0);
|
|
3888
2225
|
if (total <= options.maxBytes) return [];
|
|
3889
2226
|
const dir = _nullishCoalesce(options.direction, () => ( 1));
|
|
3890
2227
|
const behind = _nullishCoalesce(options.behind, () => ( 2));
|
|
@@ -3893,7 +2230,7 @@ function videoCacheEvictions(entries, options) {
|
|
|
3893
2230
|
return d >= 0 ? d : -d * behind;
|
|
3894
2231
|
};
|
|
3895
2232
|
const out = [];
|
|
3896
|
-
for (const e of entries.filter((x) => !_optionalChain([options, 'access',
|
|
2233
|
+
for (const e of entries.filter((x) => !_optionalChain([options, 'access', _40 => _40.protect, 'optionalAccess', _41 => _41.has, 'call', _42 => _42(x.key)])).sort((a, b) => cost(b) - cost(a))) {
|
|
3897
2234
|
if (total <= options.maxBytes) break;
|
|
3898
2235
|
out.push(e.key);
|
|
3899
2236
|
total -= e.bytes;
|
|
@@ -3905,26 +2242,26 @@ var defaultCapture = async (source) => {
|
|
|
3905
2242
|
const image = await createImageBitmap(source);
|
|
3906
2243
|
return { image, width: image.width, height: image.height };
|
|
3907
2244
|
};
|
|
3908
|
-
var VideoFrameCache = (
|
|
3909
|
-
constructor(options = {}) {;
|
|
2245
|
+
var VideoFrameCache = (_class4 = class {
|
|
2246
|
+
constructor(options = {}) {;_class4.prototype.__init9.call(this);_class4.prototype.__init10.call(this);_class4.prototype.__init11.call(this);_class4.prototype.__init12.call(this);_class4.prototype.__init13.call(this);_class4.prototype.__init14.call(this);_class4.prototype.__init15.call(this);_class4.prototype.__init16.call(this);_class4.prototype.__init17.call(this);_class4.prototype.__init18.call(this);_class4.prototype.__init19.call(this);_class4.prototype.__init20.call(this);
|
|
3910
2247
|
this.options = options;
|
|
3911
2248
|
this.maxBytes = _nullishCoalesce(options.maxBytes, () => ( 512 * 1024 * 1024));
|
|
3912
2249
|
this.prefetch = _nullishCoalesce(options.prefetch, () => ( 2e3));
|
|
3913
2250
|
this.decode = options.decode !== void 0 ? options.decode : typeof document !== "undefined" ? createVideoElementDecoder() : null;
|
|
3914
2251
|
}
|
|
3915
2252
|
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
2253
|
+
__init9() {this.entries = /* @__PURE__ */ new Map()}
|
|
2254
|
+
__init10() {this.inFlight = /* @__PURE__ */ new Set()}
|
|
2255
|
+
__init11() {this.queue = []}
|
|
2256
|
+
__init12() {this.protect = /* @__PURE__ */ new Set()}
|
|
2257
|
+
__init13() {this.listeners = /* @__PURE__ */ new Set()}
|
|
2258
|
+
__init14() {this.playhead = 0}
|
|
2259
|
+
__init15() {this.direction = 1}
|
|
2260
|
+
__init16() {this.hits = 0}
|
|
2261
|
+
__init17() {this.misses = 0}
|
|
2262
|
+
__init18() {this.bytes = 0}
|
|
2263
|
+
__init19() {this.generation = 0}
|
|
2264
|
+
__init20() {this.destroyed = false}
|
|
3928
2265
|
|
|
3929
2266
|
|
|
3930
2267
|
|
|
@@ -3934,7 +2271,7 @@ var VideoFrameCache = (_class5 = class {
|
|
|
3934
2271
|
const entry = this.entries.get(videoFrameCacheKey(src, videoSourceFrame(sourceTime, fps)));
|
|
3935
2272
|
if (entry) this.hits++;
|
|
3936
2273
|
else this.misses++;
|
|
3937
|
-
return _optionalChain([entry, 'optionalAccess',
|
|
2274
|
+
return _optionalChain([entry, 'optionalAccess', _43 => _43.frame, 'access', _44 => _44.image]);
|
|
3938
2275
|
}
|
|
3939
2276
|
/** Whether a frame is cached, without counting it. */
|
|
3940
2277
|
has(src, sourceTime, fps) {
|
|
@@ -3942,7 +2279,7 @@ var VideoFrameCache = (_class5 = class {
|
|
|
3942
2279
|
}
|
|
3943
2280
|
/** Keeps a decoded frame (replacing any with the same key), then evicts to the budget. */
|
|
3944
2281
|
put(request, frame) {
|
|
3945
|
-
if (this.destroyed) return void _optionalChain([frame, 'access',
|
|
2282
|
+
if (this.destroyed) return void _optionalChain([frame, 'access', _45 => _45.image, 'access', _46 => _46.close, 'optionalCall', _47 => _47()]);
|
|
3946
2283
|
const old = this.entries.get(request.key);
|
|
3947
2284
|
if (old) this.drop(old);
|
|
3948
2285
|
const bytes = Math.max(1, frame.width * frame.height * 4);
|
|
@@ -4041,7 +2378,7 @@ var VideoFrameCache = (_class5 = class {
|
|
|
4041
2378
|
(frame) => {
|
|
4042
2379
|
this.inFlight.delete(r.key);
|
|
4043
2380
|
if (generation === this.generation || this.bytes + frame.width * frame.height * 4 <= this.maxBytes) this.put(r, frame);
|
|
4044
|
-
else _optionalChain([frame, 'access',
|
|
2381
|
+
else _optionalChain([frame, 'access', _48 => _48.image, 'access', _49 => _49.close, 'optionalCall', _50 => _50()]);
|
|
4045
2382
|
},
|
|
4046
2383
|
() => this.inFlight.delete(r.key)
|
|
4047
2384
|
).finally(() => this.pump());
|
|
@@ -4054,12 +2391,12 @@ var VideoFrameCache = (_class5 = class {
|
|
|
4054
2391
|
drop(e) {
|
|
4055
2392
|
this.entries.delete(e.key);
|
|
4056
2393
|
this.bytes -= e.bytes;
|
|
4057
|
-
_optionalChain([e, 'access',
|
|
2394
|
+
_optionalChain([e, 'access', _51 => _51.frame, 'access', _52 => _52.image, 'access', _53 => _53.close, 'optionalCall', _54 => _54()]);
|
|
4058
2395
|
}
|
|
4059
2396
|
emit() {
|
|
4060
2397
|
for (const l of [...this.listeners]) l();
|
|
4061
2398
|
}
|
|
4062
|
-
},
|
|
2399
|
+
}, _class4);
|
|
4063
2400
|
function createVideoElementDecoder(options = {}) {
|
|
4064
2401
|
const videos = /* @__PURE__ */ new Map();
|
|
4065
2402
|
const make = _nullishCoalesce(options.createVideo, () => ( (() => {
|
|
@@ -4101,12 +2438,12 @@ function createVideoElementDecoder(options = {}) {
|
|
|
4101
2438
|
}
|
|
4102
2439
|
|
|
4103
2440
|
// src/video-editor/preview.ts
|
|
4104
|
-
var VideoPreviewEngine = (
|
|
4105
|
-
constructor(source, canvas2, options = {}) {;
|
|
2441
|
+
var VideoPreviewEngine = (_class5 = class {
|
|
2442
|
+
constructor(source, canvas2, options = {}) {;_class5.prototype.__init21.call(this);_class5.prototype.__init22.call(this);_class5.prototype.__init23.call(this);_class5.prototype.__init24.call(this);_class5.prototype.__init25.call(this);_class5.prototype.__init26.call(this);_class5.prototype.__init27.call(this);_class5.prototype.__init28.call(this);_class5.prototype.__init29.call(this);_class5.prototype.__init30.call(this);_class5.prototype.__init31.call(this);_class5.prototype.__init32.call(this);_class5.prototype.__init33.call(this);_class5.prototype.__init34.call(this);_class5.prototype.__init35.call(this);_class5.prototype.__init36.call(this);
|
|
4106
2443
|
this.source = source;
|
|
4107
2444
|
this.options = options;
|
|
4108
2445
|
this.canvas = canvas2;
|
|
4109
|
-
this.ctx = options.context !== void 0 ? options.context : _nullishCoalesce(_optionalChain([canvas2, 'access',
|
|
2446
|
+
this.ctx = options.context !== void 0 ? options.context : _nullishCoalesce(_optionalChain([canvas2, 'access', _59 => _59.getContext, 'optionalCall', _60 => _60("2d")]), () => ( null));
|
|
4110
2447
|
this.unsubscribe = source.subscribe(() => this.update());
|
|
4111
2448
|
this.lutCache = options.luts !== void 0 ? options.luts : _nullishCoalesce(source.luts, () => ( null));
|
|
4112
2449
|
this.unsubscribeLuts = this.lutCache ? this.lutCache.subscribe(() => this.redraw()) : () => {
|
|
@@ -4124,29 +2461,29 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4124
2461
|
|
|
4125
2462
|
|
|
4126
2463
|
|
|
4127
|
-
|
|
4128
|
-
|
|
2464
|
+
__init21() {this.media = /* @__PURE__ */ new Map()}
|
|
2465
|
+
__init22() {this.images = /* @__PURE__ */ new Map()}
|
|
4129
2466
|
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
2467
|
+
__init23() {this.scheduled = false}
|
|
2468
|
+
__init24() {this.destroyed = false}
|
|
2469
|
+
__init25() {this.filterHost = null}
|
|
2470
|
+
__init26() {this.filters = /* @__PURE__ */ new Set()}
|
|
4134
2471
|
|
|
4135
2472
|
|
|
4136
|
-
|
|
4137
|
-
|
|
2473
|
+
__init27() {this.drawn = null}
|
|
2474
|
+
__init28() {this.complete = true}
|
|
4138
2475
|
|
|
4139
2476
|
|
|
4140
2477
|
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
2478
|
+
__init29() {this.srcFor = (layer) => layer.src}
|
|
2479
|
+
__init30() {this.playing = false}
|
|
2480
|
+
__init31() {this.fps = 30}
|
|
4144
2481
|
|
|
4145
|
-
|
|
2482
|
+
__init32() {this.scratchCanvases = /* @__PURE__ */ new Map()}
|
|
4146
2483
|
/** The canvas's pixels and the frame they show, or `null` when its context cannot be read. */
|
|
4147
2484
|
readPixels() {
|
|
4148
2485
|
const ctx = this.ctx;
|
|
4149
|
-
if (!_optionalChain([ctx, 'optionalAccess',
|
|
2486
|
+
if (!_optionalChain([ctx, 'optionalAccess', _61 => _61.getImageData]) || !this.drawn) return null;
|
|
4150
2487
|
return { ...this.drawn, pixels: ctx.getImageData(0, 0, this.canvas.width, this.canvas.height) };
|
|
4151
2488
|
}
|
|
4152
2489
|
createMedia(kind) {
|
|
@@ -4184,8 +2521,8 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4184
2521
|
entry.media.pause();
|
|
4185
2522
|
entry.media.removeEventListener("seeked", entry.onReady);
|
|
4186
2523
|
entry.media.removeEventListener("loadeddata", entry.onReady);
|
|
4187
|
-
_optionalChain([entry, 'access',
|
|
4188
|
-
_optionalChain([entry, 'access',
|
|
2524
|
+
_optionalChain([entry, 'access', _62 => _62.media, 'access', _63 => _63.removeAttribute, 'optionalCall', _64 => _64("src")]);
|
|
2525
|
+
_optionalChain([entry, 'access', _65 => _65.media, 'access', _66 => _66.load, 'optionalCall', _67 => _67()]);
|
|
4189
2526
|
this.media.delete(entry.clip);
|
|
4190
2527
|
}
|
|
4191
2528
|
/** Brings the media elements in step with the editor and draws the frame. */
|
|
@@ -4193,13 +2530,13 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4193
2530
|
if (this.destroyed) return;
|
|
4194
2531
|
const state = this.source.getState();
|
|
4195
2532
|
const { project, time, playing } = state;
|
|
4196
|
-
const frame = videoFrameAt(project, time);
|
|
2533
|
+
const frame = _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, project, time);
|
|
4197
2534
|
const scale = resolveVideoPreviewScale(_nullishCoalesce(this.options.previewScale, () => ( state.previewScale)), this.resolutionFor(project.width));
|
|
4198
2535
|
const assets = new Map(project.assets.map((a) => [a.id, a]));
|
|
4199
2536
|
this.srcFor = (layer) => videoPreviewSrc(assets.get(_nullishCoalesce(layer.asset, () => ( ""))), scale, layer.src);
|
|
4200
2537
|
this.playing = playing;
|
|
4201
2538
|
this.fps = project.fps;
|
|
4202
|
-
_optionalChain([this, 'access',
|
|
2539
|
+
_optionalChain([this, 'access', _68 => _68.frameCache, 'optionalAccess', _69 => _69.update, 'call', _70 => _70(project, time, { playing, srcFor: this.srcFor })]);
|
|
4203
2540
|
const tolerance = (_nullishCoalesce(this.options.tolerance, () => ( 200))) / 1e3;
|
|
4204
2541
|
const active = /* @__PURE__ */ new Set();
|
|
4205
2542
|
const sync = (clip, src, kind, sourceTime, speed, gain) => {
|
|
@@ -4223,10 +2560,10 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4223
2560
|
}
|
|
4224
2561
|
};
|
|
4225
2562
|
const sounding = new Map(frame.audio.map((a) => [a.clip, a]));
|
|
4226
|
-
for (const layer of videoFrameLeafLayers(frame.layers)) {
|
|
2563
|
+
for (const layer of _chunkSMJGE7HMcjs.videoFrameLeafLayers.call(void 0, frame.layers)) {
|
|
4227
2564
|
if (layer.type !== "media" || layer.assetKind !== "video" || !layer.src) continue;
|
|
4228
2565
|
const sound = sounding.get(layer.clip);
|
|
4229
|
-
sync(layer.clip, this.srcFor(layer), "video", _nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(_optionalChain([sound, 'optionalAccess',
|
|
2566
|
+
sync(layer.clip, this.srcFor(layer), "video", _nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(_optionalChain([sound, 'optionalAccess', _71 => _71.speed]), () => ( 1)), sound ? sound.gain : null);
|
|
4230
2567
|
sounding.delete(layer.clip);
|
|
4231
2568
|
}
|
|
4232
2569
|
for (const a of sounding.values()) sync(a.clip, a.src, "audio", a.sourceTime, a.speed, a.gain);
|
|
@@ -4238,10 +2575,10 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4238
2575
|
this.scheduled = true;
|
|
4239
2576
|
queueMicrotask(() => {
|
|
4240
2577
|
this.scheduled = false;
|
|
4241
|
-
if (!this.destroyed) this.draw(videoFrameAt(this.source.getState().project, this.source.getState().time));
|
|
2578
|
+
if (!this.destroyed) this.draw(_chunkSMJGE7HMcjs.videoFrameAt.call(void 0, this.source.getState().project, this.source.getState().time));
|
|
4242
2579
|
});
|
|
4243
2580
|
}
|
|
4244
|
-
|
|
2581
|
+
__init33() {this.sourceFor = (layer) => {
|
|
4245
2582
|
if (layer.assetKind === "image" && layer.src) {
|
|
4246
2583
|
const img = this.image(layer.src);
|
|
4247
2584
|
return img.complete ? img : null;
|
|
@@ -4249,7 +2586,7 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4249
2586
|
const entry = this.media.get(layer.clip);
|
|
4250
2587
|
const ready = !!entry && entry.media.readyState >= 2;
|
|
4251
2588
|
const cache = this.frameCache;
|
|
4252
|
-
const src = _nullishCoalesce(_optionalChain([entry, 'optionalAccess',
|
|
2589
|
+
const src = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _72 => _72.src]), () => ( this.srcFor(layer)));
|
|
4253
2590
|
const sourceTime = _nullishCoalesce(layer.sourceTime, () => ( 0));
|
|
4254
2591
|
if (cache && src && (!this.playing || !ready || entry.media.seeking)) {
|
|
4255
2592
|
const hit = cache.get(src, sourceTime, this.fps);
|
|
@@ -4280,18 +2617,18 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4280
2617
|
if (!source) this.complete = false;
|
|
4281
2618
|
return source;
|
|
4282
2619
|
};
|
|
4283
|
-
drawVideoFrame(this.ctx, frame, sourceFor, resolution, { defineSvgFilter: this.defineSvgFilter, lutFor: this.lutFor, scratch: this.scratch });
|
|
2620
|
+
_chunkSMJGE7HMcjs.drawVideoFrame.call(void 0, this.ctx, frame, sourceFor, resolution, { defineSvgFilter: this.defineSvgFilter, lutFor: this.lutFor, scratch: this.scratch });
|
|
4284
2621
|
this.drawn = { time: frame.time, complete: this.complete };
|
|
4285
|
-
_optionalChain([this, 'access',
|
|
4286
|
-
_optionalChain([this, 'access',
|
|
2622
|
+
_optionalChain([this, 'access', _73 => _73.options, 'access', _74 => _74.onFrame, 'optionalCall', _75 => _75(frame)]);
|
|
2623
|
+
_optionalChain([this, 'access', _76 => _76.pixelsTarget, 'optionalAccess', _77 => _77.drawn, 'call', _78 => _78(frame.time, this.complete)]);
|
|
4287
2624
|
}
|
|
4288
2625
|
/** A grade's LUT once loaded; while it loads (or if it fails) the frame is drawn without it and counts as incomplete. */
|
|
4289
|
-
|
|
4290
|
-
const lut = _optionalChain([this, 'access',
|
|
2626
|
+
__init34() {this.lutFor = (src) => {
|
|
2627
|
+
const lut = _optionalChain([this, 'access', _79 => _79.lutCache, 'optionalAccess', _80 => _80.get, 'call', _81 => _81(src)]);
|
|
4291
2628
|
if (!lut) this.complete = false;
|
|
4292
2629
|
return lut;
|
|
4293
2630
|
}}
|
|
4294
|
-
|
|
2631
|
+
__init35() {this.scratch = (width, height, slot) => {
|
|
4295
2632
|
if (!this.scratchCanvases.has(slot)) {
|
|
4296
2633
|
let made = null;
|
|
4297
2634
|
if (this.options.createScratch) made = this.options.createScratch(width, height, slot);
|
|
@@ -4309,7 +2646,7 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4309
2646
|
if (c.height !== height) c.height = height;
|
|
4310
2647
|
return s;
|
|
4311
2648
|
}}
|
|
4312
|
-
|
|
2649
|
+
__init36() {this.defineSvgFilter = (id, markup) => {
|
|
4313
2650
|
if (this.options.defineSvgFilter === null) return;
|
|
4314
2651
|
if (this.options.defineSvgFilter) return this.options.defineSvgFilter(id, markup);
|
|
4315
2652
|
if (this.filters.has(id) || typeof document === "undefined") return;
|
|
@@ -4331,50 +2668,50 @@ var VideoPreviewEngine = (_class6 = class {
|
|
|
4331
2668
|
this.detachPixels();
|
|
4332
2669
|
this.unsubscribeLuts();
|
|
4333
2670
|
this.unsubscribeFrames();
|
|
4334
|
-
_optionalChain([this, 'access',
|
|
2671
|
+
_optionalChain([this, 'access', _82 => _82.filterHost, 'optionalAccess', _83 => _83.remove, 'call', _84 => _84()]);
|
|
4335
2672
|
this.filterHost = null;
|
|
4336
2673
|
this.filters.clear();
|
|
4337
2674
|
this.unsubscribe();
|
|
4338
2675
|
for (const entry of [...this.media.values()]) this.release(entry);
|
|
4339
2676
|
this.images.clear();
|
|
4340
2677
|
}
|
|
4341
|
-
},
|
|
2678
|
+
}, _class5);
|
|
4342
2679
|
|
|
4343
2680
|
// src/video-editor/controller.ts
|
|
4344
|
-
var VideoEditorController = (
|
|
2681
|
+
var VideoEditorController = (_class6 = class {
|
|
4345
2682
|
|
|
4346
2683
|
|
|
4347
2684
|
/** Sound levels per asset, loaded on demand for waveforms and agents. */
|
|
4348
2685
|
|
|
4349
2686
|
/** The pixels the preview last drew, for scopes and `get_video_scopes` (a `VideoPreviewEngine` fills it). */
|
|
4350
|
-
|
|
2687
|
+
__init37() {this.previewPixels = new VideoPreviewPixels()}
|
|
4351
2688
|
/** Grades' LUTs, loaded on demand for the preview, SVG frames and agents. */
|
|
4352
2689
|
|
|
4353
2690
|
/** The host's frame cache, if it gave one (the preview fills and reads it). */
|
|
4354
2691
|
|
|
4355
2692
|
|
|
4356
2693
|
|
|
4357
|
-
|
|
2694
|
+
__init38() {this.selection = []}
|
|
4358
2695
|
|
|
4359
2696
|
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
2697
|
+
__init39() {this.error = null}
|
|
2698
|
+
__init40() {this.revision = 0}
|
|
2699
|
+
__init41() {this.applying = false}
|
|
4363
2700
|
|
|
4364
|
-
|
|
4365
|
-
|
|
2701
|
+
__init42() {this.listeners = /* @__PURE__ */ new Set()}
|
|
2702
|
+
__init43() {this.unsubscribers = []}
|
|
4366
2703
|
|
|
4367
|
-
constructor(options = {}) {;
|
|
2704
|
+
constructor(options = {}) {;_class6.prototype.__init37.call(this);_class6.prototype.__init38.call(this);_class6.prototype.__init39.call(this);_class6.prototype.__init40.call(this);_class6.prototype.__init41.call(this);_class6.prototype.__init42.call(this);_class6.prototype.__init43.call(this);_class6.prototype.__init44.call(this);_class6.prototype.__init45.call(this);
|
|
4368
2705
|
this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkQKLRAA4Tcjs.HistoryManager)()));
|
|
4369
2706
|
this.audioPeaks = options.audioPeaks instanceof VideoAudioPeaksCache ? options.audioPeaks : new VideoAudioPeaksCache(options.audioPeaks);
|
|
4370
|
-
this.luts = options.luts instanceof VideoLutCache ? options.luts : new VideoLutCache(options.luts);
|
|
2707
|
+
this.luts = options.luts instanceof _chunkSMJGE7HMcjs.VideoLutCache ? options.luts : new (0, _chunkSMJGE7HMcjs.VideoLutCache)(options.luts);
|
|
4371
2708
|
this.frameCache = _nullishCoalesce(options.frameCache, () => ( null));
|
|
4372
2709
|
this.project = options.project ? parseVideoProject(options.project) : createVideoProject();
|
|
4373
2710
|
this.issues = checkVideoProject(this.project);
|
|
4374
2711
|
this.readOnly = _nullishCoalesce(options.readOnly, () => ( false));
|
|
4375
2712
|
this.previewScale = checkPreviewScale(_nullishCoalesce(options.previewScale, () => ( "auto")));
|
|
4376
2713
|
this.onChange = options.onChange;
|
|
4377
|
-
this.player = new (0, _chunk477UVMNRcjs.AnimationPlayer)({ clock: options.clock, duration: () => videoProjectDuration(this.project), loop: "none" });
|
|
2714
|
+
this.player = new (0, _chunk477UVMNRcjs.AnimationPlayer)({ clock: options.clock, duration: () => _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, this.project), loop: "none" });
|
|
4378
2715
|
this.state = this.computeState();
|
|
4379
2716
|
this.connect();
|
|
4380
2717
|
}
|
|
@@ -4392,8 +2729,8 @@ var VideoEditorController = (_class7 = class {
|
|
|
4392
2729
|
this.player.pause();
|
|
4393
2730
|
this.unsubscribers.splice(0).forEach((u) => u());
|
|
4394
2731
|
}
|
|
4395
|
-
|
|
4396
|
-
|
|
2732
|
+
__init44() {this.getState = () => this.state}
|
|
2733
|
+
__init45() {this.subscribe = (listener) => {
|
|
4397
2734
|
this.connect();
|
|
4398
2735
|
this.listeners.add(listener);
|
|
4399
2736
|
return () => {
|
|
@@ -4409,12 +2746,12 @@ var VideoEditorController = (_class7 = class {
|
|
|
4409
2746
|
const h = this.history.getState();
|
|
4410
2747
|
return {
|
|
4411
2748
|
project: this.project,
|
|
4412
|
-
duration: videoProjectDuration(this.project),
|
|
2749
|
+
duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, this.project),
|
|
4413
2750
|
time: p.time,
|
|
4414
2751
|
playing: p.playing,
|
|
4415
2752
|
loop: p.loop,
|
|
4416
2753
|
selection: this.selection,
|
|
4417
|
-
current: videoClipsAt(this.project, p.time).map((c) => c.clip.id),
|
|
2754
|
+
current: _chunkSMJGE7HMcjs.videoClipsAt.call(void 0, this.project, p.time).map((c) => c.clip.id),
|
|
4418
2755
|
issues: this.issues,
|
|
4419
2756
|
readOnly: this.readOnly,
|
|
4420
2757
|
error: this.error,
|
|
@@ -4445,12 +2782,12 @@ var VideoEditorController = (_class7 = class {
|
|
|
4445
2782
|
this.issues = checkVideoProject(project);
|
|
4446
2783
|
const ids = new Set(project.tracks.flatMap((t) => t.clips.map((c) => c.id)));
|
|
4447
2784
|
if (this.selection.some((id) => !ids.has(id))) this.selection = this.selection.filter((id) => ids.has(id));
|
|
4448
|
-
this.player.setDuration(() => videoProjectDuration(this.project));
|
|
2785
|
+
this.player.setDuration(() => _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, this.project));
|
|
4449
2786
|
} finally {
|
|
4450
2787
|
this.applying = false;
|
|
4451
2788
|
}
|
|
4452
2789
|
this.notify();
|
|
4453
|
-
_optionalChain([this, 'access',
|
|
2790
|
+
_optionalChain([this, 'access', _85 => _85.onChange, 'optionalCall', _86 => _86(project)]);
|
|
4454
2791
|
}
|
|
4455
2792
|
commit(label, next) {
|
|
4456
2793
|
const before = this.project;
|
|
@@ -4525,7 +2862,7 @@ var VideoEditorController = (_class7 = class {
|
|
|
4525
2862
|
}
|
|
4526
2863
|
/** Selects clips (unknown ids are dropped). `add` toggles them into the current selection. */
|
|
4527
2864
|
select(clips, options = {}) {
|
|
4528
|
-
const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess',
|
|
2865
|
+
const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess', _87 => _87.filter, 'call', _88 => _88((id) => _chunkSMJGE7HMcjs.findVideoClip.call(void 0, this.project, id))]), () => ( []));
|
|
4529
2866
|
let next;
|
|
4530
2867
|
if (options.add) {
|
|
4531
2868
|
next = [...this.selection];
|
|
@@ -4552,7 +2889,7 @@ var VideoEditorController = (_class7 = class {
|
|
|
4552
2889
|
step(frames) {
|
|
4553
2890
|
this.player.pause();
|
|
4554
2891
|
const fps = this.project.fps;
|
|
4555
|
-
this.player.seek(Math.max(0, snapToVideoFrame(this.player.currentTime, fps) + frames * 1e3 / fps));
|
|
2892
|
+
this.player.seek(Math.max(0, _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, this.player.currentTime, fps) + frames * 1e3 / fps));
|
|
4556
2893
|
}
|
|
4557
2894
|
setLoop(loop) {
|
|
4558
2895
|
this.player.setLoop(loop);
|
|
@@ -4569,14 +2906,14 @@ var VideoEditorController = (_class7 = class {
|
|
|
4569
2906
|
*/
|
|
4570
2907
|
snap(time, options = {}) {
|
|
4571
2908
|
const threshold = _nullishCoalesce(options.threshold, () => ( 8 * 1e3 / this.project.fps));
|
|
4572
|
-
const points = videoSnapPoints(this.project, { exclude: options.exclude, playhead: options.playhead === false ? void 0 : this.player.currentTime });
|
|
4573
|
-
const hit = snapVideoTime(time, points, threshold);
|
|
4574
|
-
return hit.snapped !== null ? hit : { time: Math.max(0, snapToVideoFrame(time, this.project.fps)), snapped: null };
|
|
2909
|
+
const points = _chunkSMJGE7HMcjs.videoSnapPoints.call(void 0, this.project, { exclude: options.exclude, playhead: options.playhead === false ? void 0 : this.player.currentTime });
|
|
2910
|
+
const hit = _chunkSMJGE7HMcjs.snapVideoTime.call(void 0, time, points, threshold);
|
|
2911
|
+
return hit.snapped !== null ? hit : { time: Math.max(0, _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, time, this.project.fps)), snapped: null };
|
|
4575
2912
|
}
|
|
4576
2913
|
/** Splits the selected clips (or every clip) under the playhead there, as one undo step. */
|
|
4577
2914
|
splitAtPlayhead() {
|
|
4578
|
-
const t = snapToVideoFrame(this.player.currentTime, this.project.fps);
|
|
4579
|
-
const under = videoClipsAt(this.project, t).filter(({ clip }) => t > clip.start && t < videoClipEnd(clip));
|
|
2915
|
+
const t = _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, this.player.currentTime, this.project.fps);
|
|
2916
|
+
const under = _chunkSMJGE7HMcjs.videoClipsAt.call(void 0, this.project, t).filter(({ clip }) => t > clip.start && t < _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip));
|
|
4580
2917
|
const chosen = this.selection.length ? under.filter(({ clip }) => this.selection.includes(clip.id)) : under;
|
|
4581
2918
|
if (!chosen.length) return this.refuse("No clip is under the playhead to split.");
|
|
4582
2919
|
return this.apply(chosen.map(({ clip }) => ({ op: "split_clip", clip: clip.id, at: t })), "Split");
|
|
@@ -4588,25 +2925,25 @@ var VideoEditorController = (_class7 = class {
|
|
|
4588
2925
|
}
|
|
4589
2926
|
/** What plays at `time` (default: the playhead). */
|
|
4590
2927
|
frame(time = this.player.currentTime) {
|
|
4591
|
-
return videoFrameAt(this.project, time);
|
|
2928
|
+
return _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, this.project, time);
|
|
4592
2929
|
}
|
|
4593
2930
|
/** The frame at `time` (default: the playhead) as SVG. */
|
|
4594
2931
|
toSvg(time = this.player.currentTime, options = {}) {
|
|
4595
|
-
return videoProjectSvg(this.project, time, { lutFor: (src) => this.luts.peek(src), ...options });
|
|
2932
|
+
return _chunkSMJGE7HMcjs.videoProjectSvg.call(void 0, this.project, time, { lutFor: (src) => this.luts.peek(src), ...options });
|
|
4596
2933
|
}
|
|
4597
2934
|
/** The project as an ffmpeg command. */
|
|
4598
2935
|
toFfmpeg(options = {}) {
|
|
4599
|
-
return toVideoFfmpeg(this.project, options);
|
|
2936
|
+
return _chunkSMJGE7HMcjs.toVideoFfmpeg.call(void 0, this.project, options);
|
|
4600
2937
|
}
|
|
4601
2938
|
/** The ffmpeg command that measures the mix's loudness (see `toVideoLoudnessMeasure`). */
|
|
4602
2939
|
toLoudnessMeasure(options = {}) {
|
|
4603
|
-
return toVideoLoudnessMeasure(this.project, options);
|
|
2940
|
+
return _chunkSMJGE7HMcjs.toVideoLoudnessMeasure.call(void 0, this.project, options);
|
|
4604
2941
|
}
|
|
4605
2942
|
/** One track as a CMX 3600 EDL. */
|
|
4606
2943
|
toEdl(options = {}) {
|
|
4607
|
-
return toVideoEdl(this.project, options);
|
|
2944
|
+
return _chunkSMJGE7HMcjs.toVideoEdl.call(void 0, this.project, options);
|
|
4608
2945
|
}
|
|
4609
|
-
},
|
|
2946
|
+
}, _class6);
|
|
4610
2947
|
function checkPreviewScale(scale) {
|
|
4611
2948
|
if (scale === "auto" || scale === "full") return scale;
|
|
4612
2949
|
if (typeof scale !== "number" || !(scale > 0 && scale <= 1)) throw new Error(`A preview scale is "auto", "full" or a fraction above 0 up to 1 (0.5 is half size), not ${JSON.stringify(scale)}.`);
|
|
@@ -4623,12 +2960,12 @@ function videoRulerTicks(duration, pxPerSecond, fps) {
|
|
|
4623
2960
|
const ticks = [];
|
|
4624
2961
|
for (let t = 0; t <= duration + 1e-6; t += step) {
|
|
4625
2962
|
const isMajor = Math.abs(t / major - Math.round(t / major)) < 1e-9;
|
|
4626
|
-
ticks.push({ time: t, x: t * pxPerMs, major: isMajor, ...isMajor ? { label: formatVideoTimecode(t, fps).replace(/^00:/, "") } : {} });
|
|
2963
|
+
ticks.push({ time: t, x: t * pxPerMs, major: isMajor, ...isMajor ? { label: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, t, fps).replace(/^00:/, "") } : {} });
|
|
4627
2964
|
}
|
|
4628
2965
|
return ticks;
|
|
4629
2966
|
}
|
|
4630
2967
|
function videoClipShowsWaveform(clip, asset, mode = "audio") {
|
|
4631
|
-
if (clip.type !== "media" || mode === "none" || !videoAssetHasSound(asset)) return false;
|
|
2968
|
+
if (clip.type !== "media" || mode === "none" || !_chunkSMJGE7HMcjs.videoAssetHasSound.call(void 0, asset)) return false;
|
|
4632
2969
|
return mode === "all" || asset.kind === "audio";
|
|
4633
2970
|
}
|
|
4634
2971
|
var VIDEO_CLIP_ANIMATION_LABELS = {
|
|
@@ -4682,13 +3019,13 @@ function videoClipLabel(clip, asset, sequence) {
|
|
|
4682
3019
|
if (clip.name) return clip.name;
|
|
4683
3020
|
if (clip.type === "text") return clip.text.split("\n")[0];
|
|
4684
3021
|
if (clip.type === "color") return clip.color;
|
|
4685
|
-
if (clip.type === "sequence") return `Compound: ${_nullishCoalesce(_optionalChain([sequence, 'optionalAccess',
|
|
4686
|
-
const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess',
|
|
4687
|
-
const speed = videoClipSpeed(clip);
|
|
3022
|
+
if (clip.type === "sequence") return `Compound: ${_nullishCoalesce(_optionalChain([sequence, 'optionalAccess', _89 => _89.name]), () => ( clip.sequence))}`;
|
|
3023
|
+
const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _90 => _90.name]), () => ( _optionalChain([asset, 'optionalAccess', _91 => _91.src, 'access', _92 => _92.replace, 'call', _93 => _93(/^.*[\\/]/, "")]))), () => ( clip.asset));
|
|
3024
|
+
const speed = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip);
|
|
4688
3025
|
return speed !== 1 ? `${base} (${Math.round(speed * 100)}%)` : base;
|
|
4689
3026
|
}
|
|
4690
3027
|
function planVideoClipDrag(project, input) {
|
|
4691
|
-
const at = findVideoClip(project, input.clip);
|
|
3028
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, input.clip);
|
|
4692
3029
|
if (!at) return null;
|
|
4693
3030
|
const { clip, track } = at;
|
|
4694
3031
|
const snap = _nullishCoalesce(input.snap, () => ( ((t) => t)));
|
|
@@ -4705,17 +3042,17 @@ function planVideoClipDrag(project, input) {
|
|
|
4705
3042
|
}
|
|
4706
3043
|
const minimum = 1e3 / project.fps;
|
|
4707
3044
|
if (input.mode === "trim-start") {
|
|
4708
|
-
const to2 = Math.min(snap(Math.max(0, clip.start + input.delta)), videoClipEnd(clip) - minimum);
|
|
3045
|
+
const to2 = Math.min(snap(Math.max(0, clip.start + input.delta)), _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) - minimum);
|
|
4709
3046
|
const changed2 = Math.abs(to2 - clip.start) > 1e-6;
|
|
4710
|
-
const plan = input.ripple ? { start: clip.start, duration: clip.duration - (to2 - clip.start) } : { start: to2, duration: videoClipEnd(clip) - to2 };
|
|
3047
|
+
const plan = input.ripple ? { start: clip.start, duration: clip.duration - (to2 - clip.start) } : { start: to2, duration: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) - to2 };
|
|
4711
3048
|
return { ...plan, track: track.id, edit: changed2 ? { op: "trim_clip", clip: clip.id, edge: "start", to: to2, ...input.ripple ? { ripple: true } : {} } : null };
|
|
4712
3049
|
}
|
|
4713
|
-
const to = Math.max(snap(videoClipEnd(clip) + input.delta), clip.start + minimum);
|
|
4714
|
-
const changed = Math.abs(to - videoClipEnd(clip)) > 1e-6;
|
|
3050
|
+
const to = Math.max(snap(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) + input.delta), clip.start + minimum);
|
|
3051
|
+
const changed = Math.abs(to - _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip)) > 1e-6;
|
|
4715
3052
|
return { start: clip.start, duration: to - clip.start, track: track.id, edit: changed ? { op: "trim_clip", clip: clip.id, edge: "end", to, ...input.ripple ? { ripple: true } : {} } : null };
|
|
4716
3053
|
}
|
|
4717
3054
|
function videoDropTracks(project, clipId) {
|
|
4718
|
-
const at = findVideoClip(project, clipId);
|
|
3055
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
|
|
4719
3056
|
if (!at) return [];
|
|
4720
3057
|
return project.tracks.filter((t) => t.kind === at.track.kind && !t.locked).map((t) => t.id);
|
|
4721
3058
|
}
|
|
@@ -4724,10 +3061,10 @@ function videoDragLabel(edit) {
|
|
|
4724
3061
|
return edit.op === "trim_clip" && edit.ripple ? "Ripple trim" : "Trim clip";
|
|
4725
3062
|
}
|
|
4726
3063
|
function videoAssetDropEdit(project, assetId, options = {}) {
|
|
4727
|
-
const asset = videoAssetMap(project).get(assetId);
|
|
3064
|
+
const asset = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project).get(assetId);
|
|
4728
3065
|
if (!asset) return null;
|
|
4729
3066
|
const kind = asset.kind === "audio" ? "audio" : "video";
|
|
4730
|
-
const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access',
|
|
3067
|
+
const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access', _94 => _94.tracks, 'access', _95 => _95.find, 'call', _96 => _96((t) => t.kind === kind && !t.locked), 'optionalAccess', _97 => _97.id])));
|
|
4731
3068
|
if (!track) return null;
|
|
4732
3069
|
return { op: "add_clip", track, clip: { type: "media", asset: asset.id, ...options.start !== void 0 ? { start: options.start } : {} }, ...options.ripple ? { ripple: true } : {}, ...options.mode && options.mode !== "refuse" ? { mode: options.mode } : {} };
|
|
4733
3070
|
}
|
|
@@ -4776,25 +3113,25 @@ var KEY_LABELS = {
|
|
|
4776
3113
|
scale: { label: "Scale", step: 0.05 },
|
|
4777
3114
|
rotation: { label: "Rotation", step: 1 }
|
|
4778
3115
|
};
|
|
4779
|
-
var animatableOf = (clip, property) => VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([clip, 'access',
|
|
3116
|
+
var animatableOf = (clip, property) => _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([clip, 'access', _98 => _98.transform, 'optionalAccess', _99 => _99[property]]) : property === "volume" ? clip.type === "media" || clip.type === "sequence" ? clip.volume : void 0 : clip.opacity;
|
|
4780
3117
|
var playheadInClip = (clip, time) => Math.round(Math.min(clip.duration, Math.max(0, time - clip.start)));
|
|
4781
3118
|
function videoKeyframeRows(project, clipId, time) {
|
|
4782
|
-
const at = findVideoClip(project, clipId);
|
|
3119
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
|
|
4783
3120
|
if (!at) return [];
|
|
4784
3121
|
const { clip } = at;
|
|
4785
|
-
const asset = clip.type === "media" ? videoAssetMap(project).get(clip.asset) : void 0;
|
|
4786
|
-
const visual = !(_optionalChain([asset, 'optionalAccess',
|
|
4787
|
-
const audible = clip.type === "media" && videoAssetHasSound(asset) || clip.type === "sequence";
|
|
4788
|
-
const properties = [...visual ? ["opacity"] : [], ...audible ? ["volume"] : [], ...visual ? VIDEO_TRANSFORM_PROPERTIES : []];
|
|
3122
|
+
const asset = clip.type === "media" ? _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project).get(clip.asset) : void 0;
|
|
3123
|
+
const visual = !(_optionalChain([asset, 'optionalAccess', _100 => _100.kind]) === "audio" || at.track.kind === "audio");
|
|
3124
|
+
const audible = clip.type === "media" && _chunkSMJGE7HMcjs.videoAssetHasSound.call(void 0, asset) || clip.type === "sequence";
|
|
3125
|
+
const properties = [...visual ? ["opacity"] : [], ...audible ? ["volume"] : [], ...visual ? _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES : []];
|
|
4789
3126
|
const clipTime = playheadInClip(clip, time);
|
|
4790
3127
|
return properties.map((property) => {
|
|
4791
3128
|
const prop = animatableOf(clip, property);
|
|
4792
|
-
const keys = isVideoKeyframes(prop) ? prop.keys : [];
|
|
4793
|
-
const limits = VIDEO_KEYFRAME_LIMITS[property];
|
|
3129
|
+
const keys = _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop) ? prop.keys : [];
|
|
3130
|
+
const limits = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[property];
|
|
4794
3131
|
return {
|
|
4795
3132
|
property,
|
|
4796
3133
|
...KEY_LABELS[property],
|
|
4797
|
-
value: Math.round(videoValueAt(prop, clipTime, limits.default) * 1e3) / 1e3,
|
|
3134
|
+
value: Math.round(_chunkSMJGE7HMcjs.videoValueAt.call(void 0, prop, clipTime, limits.default) * 1e3) / 1e3,
|
|
4798
3135
|
keyed: keys.length > 0,
|
|
4799
3136
|
keys: keys.length,
|
|
4800
3137
|
onKey: keys.some((k) => Math.abs(k.t - clipTime) < 0.5),
|
|
@@ -4805,44 +3142,44 @@ function videoKeyframeRows(project, clipId, time) {
|
|
|
4805
3142
|
});
|
|
4806
3143
|
}
|
|
4807
3144
|
function plainValueEdit(clip, property, value) {
|
|
4808
|
-
if (!VIDEO_TRANSFORM_PROPERTIES.includes(property))
|
|
3145
|
+
if (!_chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property))
|
|
4809
3146
|
return value === void 0 ? { op: "update_clip", clip: clip.id, remove: [property] } : { op: "update_clip", clip: clip.id, set: { [property]: value } };
|
|
4810
3147
|
const transform = { ...clip.transform, [property]: value };
|
|
4811
3148
|
if (value === void 0) delete transform[property];
|
|
4812
3149
|
return Object.keys(transform).length ? { op: "update_clip", clip: clip.id, set: { transform } } : { op: "update_clip", clip: clip.id, remove: ["transform"] };
|
|
4813
3150
|
}
|
|
4814
3151
|
function videoKeyframeValueEdit(project, clipId, property, time, value) {
|
|
4815
|
-
const at = findVideoClip(project, clipId);
|
|
3152
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
|
|
4816
3153
|
if (!at) return null;
|
|
4817
3154
|
const prop = animatableOf(at.clip, property);
|
|
4818
|
-
if (!isVideoKeyframes(prop)) return plainValueEdit(at.clip, property, value);
|
|
3155
|
+
if (!_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop)) return plainValueEdit(at.clip, property, value);
|
|
4819
3156
|
if (value === void 0) return null;
|
|
4820
|
-
return { op: "set_keyframes", clip: clipId, property, keys: setVideoKey(prop, { t: playheadInClip(at.clip, time), v: value }, VIDEO_KEYFRAME_LIMITS[property].default).keys };
|
|
3157
|
+
return { op: "set_keyframes", clip: clipId, property, keys: _chunkSMJGE7HMcjs.setVideoKey.call(void 0, prop, { t: playheadInClip(at.clip, time), v: value }, _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[property].default).keys };
|
|
4821
3158
|
}
|
|
4822
3159
|
function videoKeyframeToggleEdit(project, clipId, property, time) {
|
|
4823
|
-
const at = findVideoClip(project, clipId);
|
|
3160
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
|
|
4824
3161
|
if (!at) return null;
|
|
4825
3162
|
const prop = animatableOf(at.clip, property);
|
|
4826
3163
|
const t = playheadInClip(at.clip, time);
|
|
4827
|
-
const fallback = VIDEO_KEYFRAME_LIMITS[property].default;
|
|
4828
|
-
if (isVideoKeyframes(prop)) {
|
|
3164
|
+
const fallback = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[property].default;
|
|
3165
|
+
if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop)) {
|
|
4829
3166
|
const key = prop.keys.find((k) => Math.abs(k.t - t) < 0.5);
|
|
4830
3167
|
if (key) {
|
|
4831
|
-
const rest = removeVideoKey(prop, key.t);
|
|
4832
|
-
return isVideoKeyframes(rest) ? { op: "set_keyframes", clip: clipId, property, keys: rest.keys } : plainValueEdit(at.clip, property, rest === fallback ? void 0 : rest);
|
|
3168
|
+
const rest = _chunkSMJGE7HMcjs.removeVideoKey.call(void 0, prop, key.t);
|
|
3169
|
+
return _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, rest) ? { op: "set_keyframes", clip: clipId, property, keys: rest.keys } : plainValueEdit(at.clip, property, rest === fallback ? void 0 : rest);
|
|
4833
3170
|
}
|
|
4834
3171
|
}
|
|
4835
|
-
const v = videoValueAt(prop, t, fallback);
|
|
4836
|
-
return { op: "set_keyframes", clip: clipId, property, keys: isVideoKeyframes(prop) ? setVideoKey(prop, { t, v }, fallback).keys : [{ t, v }] };
|
|
3172
|
+
const v = _chunkSMJGE7HMcjs.videoValueAt.call(void 0, prop, t, fallback);
|
|
3173
|
+
return { op: "set_keyframes", clip: clipId, property, keys: _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop) ? _chunkSMJGE7HMcjs.setVideoKey.call(void 0, prop, { t, v }, fallback).keys : [{ t, v }] };
|
|
4837
3174
|
}
|
|
4838
3175
|
function videoLutEdits(project, clips, lut) {
|
|
4839
3176
|
const edits = [];
|
|
4840
3177
|
for (const id of clips) {
|
|
4841
|
-
const at = findVideoClip(project, id);
|
|
3178
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, id);
|
|
4842
3179
|
if (!at) continue;
|
|
4843
3180
|
const { lut: current, ...rest } = _nullishCoalesce(at.clip.grade, () => ( {}));
|
|
4844
3181
|
if (!lut && !current) continue;
|
|
4845
|
-
const grade = normalizeVideoGrade(lut ? { ...rest, lut } : rest);
|
|
3182
|
+
const grade = _chunkSMJGE7HMcjs.normalizeVideoGrade.call(void 0, lut ? { ...rest, lut } : rest);
|
|
4846
3183
|
edits.push(grade ? { op: "update_clip", clip: id, set: { grade } } : { op: "update_clip", clip: id, remove: ["grade"] });
|
|
4847
3184
|
}
|
|
4848
3185
|
return edits;
|
|
@@ -4872,7 +3209,7 @@ var RIPPLE = {
|
|
|
4872
3209
|
};
|
|
4873
3210
|
var MODE = {
|
|
4874
3211
|
type: "string",
|
|
4875
|
-
enum: [...VIDEO_PLACEMENT_MODES],
|
|
3212
|
+
enum: [..._chunkSMJGE7HMcjs.VIDEO_PLACEMENT_MODES],
|
|
4876
3213
|
description: 'What to do with clips already where it lands: "refuse" (default) fails with the next free place; "overwrite" cuts, trims or removes what is underneath on that track; "insert" cuts everything across the start and pushes later material along by its length on this track and every sync-locked track.'
|
|
4877
3214
|
};
|
|
4878
3215
|
var DELTA = (what) => ({ type: "number", description: `${what}, in milliseconds of timeline time: positive is later, negative earlier. It is clamped to what the media and neighbours allow; the result says how far it went.` });
|
|
@@ -4889,11 +3226,11 @@ var TRANSFORM = object(
|
|
|
4889
3226
|
);
|
|
4890
3227
|
var TRANSITION = object(
|
|
4891
3228
|
{
|
|
4892
|
-
type: { type: "string", enum: [...VIDEO_TRANSITION_TYPES], description: "crossfade (this clip fades up over the one before), dip (down into a colour and up out of it), wipe (an edge travels across revealing this clip), push (this clip slides in and pushes the one before out), slide (this clip slides in over the one before) or iris (a circle opens from the centre)." },
|
|
3229
|
+
type: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_TRANSITION_TYPES], description: "crossfade (this clip fades up over the one before), dip (down into a colour and up out of it), wipe (an edge travels across revealing this clip), push (this clip slides in and pushes the one before out), slide (this clip slides in over the one before) or iris (a circle opens from the centre)." },
|
|
4893
3230
|
duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms, centred on the cut. Every type but dip needs half of it in media past the cut on both sides (handles); a dip needs none." },
|
|
4894
3231
|
color: COLOR("For dip: the colour passed through (default black)"),
|
|
4895
|
-
direction: { type: "string", enum: [...VIDEO_WIPE_DIRECTIONS], description: "For wipe, push and slide: the way the edge or picture travels (default right, coming in from the left)." },
|
|
4896
|
-
audioCurve: { type: "string", enum: [...VIDEO_FADE_CURVES], description: "Shape of the sound's fades through it: default equal-power for every type but dip (steady loudness while the two sounds overlap), linear for dip; or s-curve, exponential, logarithmic." }
|
|
3232
|
+
direction: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_WIPE_DIRECTIONS], description: "For wipe, push and slide: the way the edge or picture travels (default right, coming in from the left)." },
|
|
3233
|
+
audioCurve: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fades through it: default equal-power for every type but dip (steady loudness while the two sounds overlap), linear for dip; or s-curve, exponential, logarithmic." }
|
|
4897
3234
|
},
|
|
4898
3235
|
["type", "duration"],
|
|
4899
3236
|
"A transition from the clip that ends where this one starts on the same track."
|
|
@@ -4902,7 +3239,7 @@ var LUT_SRC = { type: "string", minLength: 1, description: 'A .cube 3D LUT file
|
|
|
4902
3239
|
var LUT_STRENGTH = { type: "number", minimum: 0, maximum: 1, description: "How much of the LUT's change to apply, 0 (none) to 1 (full, the default); 0.3-0.7 for a subtler look." };
|
|
4903
3240
|
var GRADE = object(
|
|
4904
3241
|
{
|
|
4905
|
-
...Object.fromEntries(VIDEO_GRADE_CONTROLS.map((c) => [c.key, { type: "number", minimum: c.min, maximum: c.max, description: c.description }])),
|
|
3242
|
+
...Object.fromEntries(_chunkSMJGE7HMcjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, { type: "number", minimum: c.min, maximum: c.max, description: c.description }])),
|
|
4906
3243
|
lut: object({ src: LUT_SRC, strength: LUT_STRENGTH, name: { type: "string", minLength: 1, description: "A label for the look." } }, ["src"], "A 3D LUT applied after the other settings (set_video_lut checks the file first).")
|
|
4907
3244
|
},
|
|
4908
3245
|
[],
|
|
@@ -4910,7 +3247,7 @@ var GRADE = object(
|
|
|
4910
3247
|
);
|
|
4911
3248
|
var ANIMATION = (when) => object(
|
|
4912
3249
|
{
|
|
4913
|
-
effect: { type: "string", enum: [...VIDEO_CLIP_ANIMATION_EFFECTS], description: "fade; rise (up into place) or drop (down into place); slide-left / slide-right (moving that way); zoom (grows into place); pop (grows past its size and settles). Each also fades; an exit plays the movement backwards." },
|
|
3250
|
+
effect: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_EFFECTS], description: "fade; rise (up into place) or drop (down into place); slide-left / slide-right (moving that way); zoom (grows into place); pop (grows past its size and settles). Each also fades; an exit plays the movement backwards." },
|
|
4914
3251
|
duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms (default 500)." }
|
|
4915
3252
|
},
|
|
4916
3253
|
["effect"],
|
|
@@ -4920,11 +3257,11 @@ var CLIP_COMMON = {
|
|
|
4920
3257
|
name: { type: "string", description: "A label for the clip." },
|
|
4921
3258
|
opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0\u20131 (default 1). A number replaces any keyframes; set_video_keyframes animates it." },
|
|
4922
3259
|
transform: TRANSFORM,
|
|
4923
|
-
fit: { type: "string", enum: [...VIDEO_FITS], description: "How the picture fits the frame before the transform, as CSS object-fit (default contain for media, fill for colours)." },
|
|
3260
|
+
fit: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_FITS], description: "How the picture fits the frame before the transform, as CSS object-fit (default contain for media, fill for colours)." },
|
|
4924
3261
|
grade: GRADE,
|
|
4925
3262
|
animateIn: ANIMATION("How the picture enters, from the clip's start (on top of any fade in). Titles usually rise, pop or fade in."),
|
|
4926
3263
|
animateOut: ANIMATION("How the picture leaves, ending at the clip's end."),
|
|
4927
|
-
blend: { type: "string", enum: [...VIDEO_BLEND_MODES], description: "How the picture mixes with what is beneath it, as CSS mix-blend-mode (default normal): multiply darkens (shadows, textures), screen and add lighten (light leaks, flares, glows), overlay and soft-light add contrast, difference and exclusion invert." },
|
|
3264
|
+
blend: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_BLEND_MODES], description: "How the picture mixes with what is beneath it, as CSS mix-blend-mode (default normal): multiply darkens (shadows, textures), screen and add lighten (light leaks, flares, glows), overlay and soft-light add contrast, difference and exclusion invert." },
|
|
4928
3265
|
fadeIn: MS("Fade up from nothing (picture and sound) over this long"),
|
|
4929
3266
|
fadeOut: MS("Fade down to nothing over this long")
|
|
4930
3267
|
};
|
|
@@ -4933,8 +3270,8 @@ var MEDIA_FIELDS = {
|
|
|
4933
3270
|
speed: { type: "number", minimum: 0.05, maximum: 20, description: "Playback speed (default 1). Changing it keeps the stretch of source, so the clip gets shorter or longer." },
|
|
4934
3271
|
volume: { type: "number", minimum: 0, maximum: 4, description: "Gain (1 = unchanged, default 1). A number replaces any keyframes; set_video_keyframes animates it." },
|
|
4935
3272
|
muted: { type: "boolean", description: "Silence this clip (default false)." },
|
|
4936
|
-
fadeInCurve: { type: "string", enum: [...VIDEO_FADE_CURVES], description: "Shape of the sound's fade in (default linear; the picture always fades linearly): linear, equal-power (steady loudness, best for crossfades), s-curve (gentle at both ends), exponential (slow start, natural from silence) or logarithmic (fast start)." },
|
|
4937
|
-
fadeOutCurve: { type: "string", enum: [...VIDEO_FADE_CURVES], description: "Shape of the sound's fade out (default linear), the same choices as fadeInCurve; exponential sounds natural fading to silence." }
|
|
3273
|
+
fadeInCurve: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade in (default linear; the picture always fades linearly): linear, equal-power (steady loudness, best for crossfades), s-curve (gentle at both ends), exponential (slow start, natural from silence) or logarithmic (fast start)." },
|
|
3274
|
+
fadeOutCurve: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade out (default linear), the same choices as fadeInCurve; exponential sounds natural fading to silence." }
|
|
4938
3275
|
};
|
|
4939
3276
|
var TEXT_FIELDS = {
|
|
4940
3277
|
text: { type: "string", minLength: 1, description: `The title's text ("\\n" breaks lines).` },
|
|
@@ -4983,7 +3320,7 @@ var ASSET_FIELDS = {
|
|
|
4983
3320
|
};
|
|
4984
3321
|
var KEY_PROPERTY = {
|
|
4985
3322
|
type: "string",
|
|
4986
|
-
enum: [...VIDEO_KEYFRAME_PROPERTIES],
|
|
3323
|
+
enum: [..._chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES],
|
|
4987
3324
|
description: "Which property: opacity (0\u20131), volume (media only, 0\u20134 gain), x / y (pixels from the frame's centre, right / down), scale (1 = fitted size) or rotation (degrees clockwise)."
|
|
4988
3325
|
};
|
|
4989
3326
|
var KEYS = {
|
|
@@ -4998,7 +3335,7 @@ var KEYS = {
|
|
|
4998
3335
|
ease: {
|
|
4999
3336
|
description: "How the value moves from this key to the next (default linear): linear, hold (stays, then jumps at the next key), ease-in, ease-out, ease-in-out, or CSS cubic-bezier points [x1, y1, x2, y2] with x1 and x2 in 0\u20131.",
|
|
5000
3337
|
anyOf: [
|
|
5001
|
-
{ type: "string", enum: [...VIDEO_EASE_NAMES] },
|
|
3338
|
+
{ type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_EASE_NAMES] },
|
|
5002
3339
|
{ type: "array", items: { type: "number" }, minItems: 4, maxItems: 4 }
|
|
5003
3340
|
]
|
|
5004
3341
|
}
|
|
@@ -5027,19 +3364,19 @@ var describeVideoTracks = (tracks) => tracks.map((t, index) => ({
|
|
|
5027
3364
|
...t.locked ? { locked: true } : {},
|
|
5028
3365
|
...t.syncLocked === false ? { syncLocked: false } : {},
|
|
5029
3366
|
...t.volume !== void 0 ? { volume: t.volume } : {},
|
|
5030
|
-
clips: sortedVideoClips(t).map((c) => ({ ...c, end: videoClipEnd(c), ...c.type === "media" || c.type === "sequence" ? { source: videoClipSourceRange(c) } : {} }))
|
|
3367
|
+
clips: _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, t).map((c) => ({ ...c, end: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, c) } : {} }))
|
|
5031
3368
|
}));
|
|
5032
|
-
var videoSequenceUsers = (project, id) => allVideoTracks(project).flatMap(
|
|
5033
|
-
({ sequence, track }) => track.clips.flatMap((c) => c.type === "sequence" && c.sequence === id ? [{ clip: c.id, ...sequence ? { inSequence: sequence } : {}, track: track.id, start: c.start, end: videoClipEnd(c), source: videoClipSourceRange(c) }] : [])
|
|
3369
|
+
var videoSequenceUsers = (project, id) => _chunkSMJGE7HMcjs.allVideoTracks.call(void 0, project).flatMap(
|
|
3370
|
+
({ sequence, track }) => track.clips.flatMap((c) => c.type === "sequence" && c.sequence === id ? [{ clip: c.id, ...sequence ? { inSequence: sequence } : {}, track: track.id, start: c.start, end: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), source: _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, c) }] : [])
|
|
5034
3371
|
);
|
|
5035
3372
|
function describeVideoSequence(project, sequence, tracks = true) {
|
|
5036
|
-
const cycle = findVideoSequenceCycle(project, sequence.id);
|
|
3373
|
+
const cycle = _chunkSMJGE7HMcjs.findVideoSequenceCycle.call(void 0, project, sequence.id);
|
|
5037
3374
|
return {
|
|
5038
3375
|
id: sequence.id,
|
|
5039
3376
|
...sequence.name ? { name: sequence.name } : {},
|
|
5040
|
-
duration: videoSequenceDuration(sequence),
|
|
5041
|
-
clipCount: sequence.tracks.reduce((
|
|
5042
|
-
nests: videoSequenceChildren(sequence),
|
|
3377
|
+
duration: _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, sequence),
|
|
3378
|
+
clipCount: sequence.tracks.reduce((n, t) => n + t.clips.length, 0),
|
|
3379
|
+
nests: _chunkSMJGE7HMcjs.videoSequenceChildren.call(void 0, sequence),
|
|
5043
3380
|
usedBy: videoSequenceUsers(project, sequence.id),
|
|
5044
3381
|
...cycle ? { cycle } : {},
|
|
5045
3382
|
...tracks ? { tracks: describeVideoTracks(sequence.tracks) } : { trackCount: sequence.tracks.length }
|
|
@@ -5051,11 +3388,11 @@ function describeVideoProject(project) {
|
|
|
5051
3388
|
width: project.width,
|
|
5052
3389
|
height: project.height,
|
|
5053
3390
|
fps: project.fps,
|
|
5054
|
-
duration: videoProjectDuration(project),
|
|
3391
|
+
duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, project),
|
|
5055
3392
|
...project.background ? { background: project.background } : {},
|
|
5056
3393
|
assets: project.assets.map(videoAssetOut),
|
|
5057
3394
|
tracks: describeVideoTracks(project.tracks),
|
|
5058
|
-
..._optionalChain([project, 'access',
|
|
3395
|
+
..._optionalChain([project, 'access', _101 => _101.sequences, 'optionalAccess', _102 => _102.length]) ? { sequences: project.sequences.map((q) => describeVideoSequence(project, q, false)) } : {},
|
|
5059
3396
|
markers: _nullishCoalesce(project.markers, () => ( []))
|
|
5060
3397
|
};
|
|
5061
3398
|
}
|
|
@@ -5068,7 +3405,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5068
3405
|
const project = () => controller.getProject();
|
|
5069
3406
|
const outcome = (result, extra = {}) => {
|
|
5070
3407
|
if (!result.ok) throw new Error(result.error);
|
|
5071
|
-
return { ...extra, duration: videoProjectDuration(result.project), issues: issueSummary(result.issues) };
|
|
3408
|
+
return { ...extra, duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, result.project), issues: issueSummary(result.issues) };
|
|
5072
3409
|
};
|
|
5073
3410
|
const apply = (edits, label, extra) => {
|
|
5074
3411
|
const result = controller.apply(edits, label);
|
|
@@ -5077,19 +3414,19 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5077
3414
|
const clipOut = (p, id) => {
|
|
5078
3415
|
for (const t of p.tracks) {
|
|
5079
3416
|
const c = t.clips.find((x) => x.id === id);
|
|
5080
|
-
if (c) return { track: t.id, ...c, end: videoClipEnd(c), ...c.type === "media" || c.type === "sequence" ? { source: videoClipSourceRange(c) } : {} };
|
|
3417
|
+
if (c) return { track: t.id, ...c, end: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, c) } : {} };
|
|
5081
3418
|
}
|
|
5082
3419
|
return null;
|
|
5083
3420
|
};
|
|
5084
3421
|
const placed = (o) => ({
|
|
5085
|
-
..._optionalChain([o, 'access',
|
|
5086
|
-
..._optionalChain([o, 'access',
|
|
5087
|
-
..._optionalChain([o, 'access',
|
|
3422
|
+
..._optionalChain([o, 'access', _103 => _103.created, 'optionalAccess', _104 => _104.length]) ? { created: o.created } : {},
|
|
3423
|
+
..._optionalChain([o, 'access', _105 => _105.trimmed, 'optionalAccess', _106 => _106.length]) ? { trimmed: o.trimmed } : {},
|
|
3424
|
+
..._optionalChain([o, 'access', _107 => _107.removed, 'optionalAccess', _108 => _108.length]) ? { removed: o.removed } : {},
|
|
5088
3425
|
...o.rippled ? { rippled: o.rippled } : {}
|
|
5089
3426
|
});
|
|
5090
3427
|
const keysOut = (p, clip, property) => {
|
|
5091
3428
|
const c = clipOut(p, clip);
|
|
5092
|
-
const value = VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([c, 'optionalAccess',
|
|
3429
|
+
const value = _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([c, 'optionalAccess', _109 => _109.transform, 'optionalAccess', _110 => _110[property]]) : _optionalChain([c, 'optionalAccess', _111 => _111[property]]);
|
|
5093
3430
|
return typeof value === "object" ? { keys: value.keys } : { keys: [], value: _nullishCoalesce(value, () => ( null)) };
|
|
5094
3431
|
};
|
|
5095
3432
|
const getProject = {
|
|
@@ -5111,8 +3448,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5111
3448
|
inputSchema: object({ time: MS("Time from the start (default: the playhead)") }),
|
|
5112
3449
|
annotations: { title: "What plays at a moment", ...READ },
|
|
5113
3450
|
handler: ({ time }) => {
|
|
5114
|
-
const frame = videoFrameAt(project(), _nullishCoalesce(time, () => ( controller.getState().time)));
|
|
5115
|
-
return { ...frame, timecode: formatVideoTimecode(frame.time, project().fps) };
|
|
3451
|
+
const frame = _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, project(), _nullishCoalesce(time, () => ( controller.getState().time)));
|
|
3452
|
+
return { ...frame, timecode: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, frame.time, project().fps) };
|
|
5116
3453
|
}
|
|
5117
3454
|
};
|
|
5118
3455
|
const listSequences = {
|
|
@@ -5140,7 +3477,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5140
3477
|
annotations: { title: "Find gaps", ...READ },
|
|
5141
3478
|
handler: ({ track }) => {
|
|
5142
3479
|
if (track !== void 0 && !project().tracks.some((t) => t.id === track)) throw new Error(`There is no track "${track}"; the tracks are ${project().tracks.map((t) => `"${t.id}"`).join(", ")}.`);
|
|
5143
|
-
return { gaps: findVideoGaps(project(), track) };
|
|
3480
|
+
return { gaps: _chunkSMJGE7HMcjs.findVideoGaps.call(void 0, project(), track) };
|
|
5144
3481
|
}
|
|
5145
3482
|
};
|
|
5146
3483
|
const checkProject = {
|
|
@@ -5167,10 +3504,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5167
3504
|
annotations: { title: "Render a frame", ...READ },
|
|
5168
3505
|
handler: async ({ time, times, columns, format = "svg" }) => {
|
|
5169
3506
|
const p = project();
|
|
5170
|
-
const lutSrcs = [...new Set(p.tracks.flatMap((t) => t.clips.map((c) => _optionalChain([c, 'access',
|
|
3507
|
+
const lutSrcs = [...new Set(p.tracks.flatMap((t) => t.clips.map((c) => _optionalChain([c, 'access', _112 => _112.grade, 'optionalAccess', _113 => _113.lut, 'optionalAccess', _114 => _114.src])).filter((x) => !!x)))];
|
|
5171
3508
|
const missing = (await Promise.all(lutSrcs.map((src) => controller.luts.load(src).then(() => null, (e) => e.message)))).filter((m) => !!m);
|
|
5172
3509
|
const svgOptions = { lutFor: (src) => controller.luts.peek(src), ...columns ? { columns } : {} };
|
|
5173
|
-
const svg = times ? videoContactSheetSvg(p, times, svgOptions) : videoProjectSvg(p, _nullishCoalesce(time, () => ( controller.getState().time)), svgOptions);
|
|
3510
|
+
const svg = times ? _chunkSMJGE7HMcjs.videoContactSheetSvg.call(void 0, p, times, svgOptions) : _chunkSMJGE7HMcjs.videoProjectSvg.call(void 0, p, _nullishCoalesce(time, () => ( controller.getState().time)), svgOptions);
|
|
5174
3511
|
const notes = [...missing.map((m) => `${m}; that LUT is left out of the picture.`), ...lutSrcs.length > missing.length ? ["LUTs are drawn approximately in SVG (curves and a colour matrix); the preview and export apply them exactly."] : []];
|
|
5175
3512
|
if (format === "png") {
|
|
5176
3513
|
if (!options.rasterize) throw new Error('This host cannot make PNG images; call render_video_frame with format "svg".');
|
|
@@ -5260,7 +3597,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5260
3597
|
if (play === true) controller.play();
|
|
5261
3598
|
if (play === false) controller.pause();
|
|
5262
3599
|
const state = controller.getState();
|
|
5263
|
-
return { time: state.time, timecode: formatVideoTimecode(state.time, p.fps), playing: state.playing, clips: state.current };
|
|
3600
|
+
return { time: state.time, timecode: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, state.time, p.fps), playing: state.playing, clips: state.current };
|
|
5264
3601
|
}
|
|
5265
3602
|
};
|
|
5266
3603
|
const setSettings = {
|
|
@@ -5405,10 +3742,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5405
3742
|
const gradeTargets = (ids) => {
|
|
5406
3743
|
const p = project();
|
|
5407
3744
|
for (const id of ids) {
|
|
5408
|
-
const at = findVideoClip(p, id);
|
|
3745
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, p, id);
|
|
5409
3746
|
if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
|
|
5410
3747
|
const { clip } = at;
|
|
5411
|
-
if (at.track.kind !== "video" || clip.type === "media" && _optionalChain([p, 'access',
|
|
3748
|
+
if (at.track.kind !== "video" || clip.type === "media" && _optionalChain([p, 'access', _115 => _115.assets, 'access', _116 => _116.find, 'call', _117 => _117((a) => a.id === clip.asset), 'optionalAccess', _118 => _118.kind]) === "audio")
|
|
5412
3749
|
throw new Error(`Clip "${id}" is sound only; grades change pictures. Pass clips on video tracks.`);
|
|
5413
3750
|
}
|
|
5414
3751
|
};
|
|
@@ -5419,7 +3756,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5419
3756
|
inputSchema: object(
|
|
5420
3757
|
{
|
|
5421
3758
|
clips: { type: "array", items: CLIP_ID, minItems: 1, description: "Clips on video tracks to grade." },
|
|
5422
|
-
preset: { type: "string", enum: [...VIDEO_GRADE_PRESET_NAMES], description: "The look." },
|
|
3759
|
+
preset: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_GRADE_PRESET_NAMES], description: "The look." },
|
|
5423
3760
|
amount: { type: "number", minimum: 0, maximum: 1, description: "Strength, 0 (none) to 1 (full, the default); 0.5 is a subtler version." }
|
|
5424
3761
|
},
|
|
5425
3762
|
["clips", "preset"]
|
|
@@ -5428,10 +3765,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5428
3765
|
handler: ({ clips, preset, amount }) => {
|
|
5429
3766
|
gradeTargets(clips);
|
|
5430
3767
|
const edits = clips.map((clip) => {
|
|
5431
|
-
const grade = videoGradeLook(findVideoClip(project(), clip).clip.grade, preset, _nullishCoalesce(amount, () => ( 1)));
|
|
3768
|
+
const grade = _chunkSMJGE7HMcjs.videoGradeLook.call(void 0, _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project(), clip).clip.grade, preset, _nullishCoalesce(amount, () => ( 1)));
|
|
5432
3769
|
return grade ? { op: "update_clip", clip, set: { grade } } : { op: "update_clip", clip, remove: ["grade"] };
|
|
5433
3770
|
});
|
|
5434
|
-
return apply(edits, `Apply ${preset} look`, (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([findVideoClip
|
|
3771
|
+
return apply(edits, `Apply ${preset} look`, (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _119 => _119.clip, 'access', _120 => _120.grade]), () => ( null)) })) }));
|
|
5435
3772
|
}
|
|
5436
3773
|
};
|
|
5437
3774
|
const copyGrade = {
|
|
@@ -5442,7 +3779,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5442
3779
|
annotations: { title: "Copy a colour grade", ...WRITE_IDEMPOTENT },
|
|
5443
3780
|
handler: ({ from, to }) => {
|
|
5444
3781
|
gradeTargets([from, ...to]);
|
|
5445
|
-
const grade = findVideoClip(project(), from).clip.grade;
|
|
3782
|
+
const grade = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project(), from).clip.grade;
|
|
5446
3783
|
const edits = to.map((clip) => grade ? { op: "update_clip", clip, set: { grade: { ...grade } } } : { op: "update_clip", clip, remove: ["grade"] });
|
|
5447
3784
|
return apply(edits, "Copy grade", () => ({ grade: _nullishCoalesce(grade, () => ( null)), clips: to }));
|
|
5448
3785
|
}
|
|
@@ -5467,7 +3804,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5467
3804
|
const lut = await controller.luts.load(src);
|
|
5468
3805
|
const label = _nullishCoalesce(name, () => ( lut.title));
|
|
5469
3806
|
const setting = { src, ...strength !== void 0 && strength !== 1 ? { strength } : {}, ...label ? { name: label } : {} };
|
|
5470
|
-
return apply(videoLutEdits(project(), clips, setting), "Apply LUT", (r) => ({ lut: { src, ...lut.title ? { title: lut.title } : {}, size: lut.size }, clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([findVideoClip
|
|
3807
|
+
return apply(videoLutEdits(project(), clips, setting), "Apply LUT", (r) => ({ lut: { src, ...lut.title ? { title: lut.title } : {}, size: lut.size }, clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _121 => _121.clip, 'access', _122 => _122.grade]), () => ( null)) })) }));
|
|
5471
3808
|
}
|
|
5472
3809
|
};
|
|
5473
3810
|
const removeLut = {
|
|
@@ -5479,9 +3816,9 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5479
3816
|
handler: ({ clips }) => {
|
|
5480
3817
|
gradeTargets(clips);
|
|
5481
3818
|
const p = project();
|
|
5482
|
-
const withLut = clips.filter((id) => _optionalChain([findVideoClip
|
|
3819
|
+
const withLut = clips.filter((id) => _optionalChain([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, p, id), 'access', _123 => _123.clip, 'access', _124 => _124.grade, 'optionalAccess', _125 => _125.lut]));
|
|
5483
3820
|
if (!withLut.length) throw new Error(`None of ${clips.map((c) => `"${c}"`).join(", ")} has a LUT; get_video_project shows each clip's grade.`);
|
|
5484
|
-
return apply(videoLutEdits(p, withLut, null), "Remove LUT", (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([findVideoClip
|
|
3821
|
+
return apply(videoLutEdits(p, withLut, null), "Remove LUT", (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _126 => _126.clip, 'access', _127 => _127.grade]), () => ( null)) })) }));
|
|
5485
3822
|
}
|
|
5486
3823
|
};
|
|
5487
3824
|
const PROXY_SCALE = { type: "number", exclusiveMinimum: 0, exclusiveMaximum: 1, description: "Proxy size as a fraction of the original: 0.5 (half width and height, the default) or 0.25 for very large footage." };
|
|
@@ -5539,7 +3876,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5539
3876
|
controller.setPreviewScale(scale);
|
|
5540
3877
|
const s = controller.getState().previewScale;
|
|
5541
3878
|
const fixed = s === "full" ? 1 : typeof s === "number" ? s : null;
|
|
5542
|
-
const plays = fixed === null ? void 0 : project().assets.filter((a) => a.kind === "video").map((a) => ({ asset: a.id, src: _nullishCoalesce(_optionalChain([videoAssetProxy, 'call',
|
|
3879
|
+
const plays = fixed === null ? void 0 : project().assets.filter((a) => a.kind === "video").map((a) => ({ asset: a.id, src: _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _128 => _128(a, fixed), 'optionalAccess', _129 => _129.src]), () => ( a.src)), proxy: !!videoAssetProxy(a, fixed) }));
|
|
5543
3880
|
return { previewScale: s, ...plays ? { plays } : { note: "auto picks the smallest proxy at least as large as the preview canvas shows, so it depends on the preview's size." } };
|
|
5544
3881
|
}
|
|
5545
3882
|
};
|
|
@@ -5590,7 +3927,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5590
3927
|
approximate: parsed.approximate,
|
|
5591
3928
|
first: list[0],
|
|
5592
3929
|
last: list[list.length - 1],
|
|
5593
|
-
...a.duration !== void 0 && list[list.length - 1].end > a.duration + VIDEO_TIME_EPSILON ? { warning: `The transcript runs to ${list[list.length - 1].end} ms, past the asset's ${a.duration} ms: is it for this asset?` } : {}
|
|
3930
|
+
...a.duration !== void 0 && list[list.length - 1].end > a.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON ? { warning: `The transcript runs to ${list[list.length - 1].end} ms, past the asset's ${a.duration} ms: is it for this asset?` } : {}
|
|
5594
3931
|
}));
|
|
5595
3932
|
}
|
|
5596
3933
|
};
|
|
@@ -5608,7 +3945,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5608
3945
|
handler: ({ track, from, to, limit }) => {
|
|
5609
3946
|
const all = timelineWords(track).filter((w) => w.end > (_nullishCoalesce(from, () => ( 0))) && w.start < (_nullishCoalesce(to, () => ( Infinity))));
|
|
5610
3947
|
const words = all.slice(0, _nullishCoalesce(limit, () => ( 1e3)));
|
|
5611
|
-
return { track: _nullishCoalesce(_optionalChain([words, 'access',
|
|
3948
|
+
return { track: _nullishCoalesce(_optionalChain([words, 'access', _130 => _130[0], 'optionalAccess', _131 => _131.track]), () => ( videoTranscriptTrack(project(), track))), text: words.map((w) => w.word).join(" "), words: words.map((w) => ({ word: w.word, start: round(w.start), end: round(w.end), clip: w.clip })), more: all.length > words.length };
|
|
5612
3949
|
}
|
|
5613
3950
|
};
|
|
5614
3951
|
const findText = {
|
|
@@ -5627,7 +3964,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5627
3964
|
annotations: { title: "Find filler words", ...READ },
|
|
5628
3965
|
handler: ({ track, fillers }) => {
|
|
5629
3966
|
const found = findVideoFillers(timelineWords(track), fillers);
|
|
5630
|
-
return { fillers: found.map(RANGE_OUT), total: round(found.reduce((
|
|
3967
|
+
return { fillers: found.map(RANGE_OUT), total: round(found.reduce((n, r) => n + r.to - r.from, 0)) };
|
|
5631
3968
|
}
|
|
5632
3969
|
};
|
|
5633
3970
|
const findPauses = {
|
|
@@ -5642,7 +3979,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5642
3979
|
annotations: { title: "Find pauses between words", ...READ },
|
|
5643
3980
|
handler: ({ track, min, keep }) => {
|
|
5644
3981
|
const found = findVideoTranscriptPauses(timelineWords(track), { min, keep, fps: project().fps });
|
|
5645
|
-
return { pauses: found.map(RANGE_OUT), total: round(found.reduce((
|
|
3982
|
+
return { pauses: found.map(RANGE_OUT), total: round(found.reduce((n, r) => n + r.to - r.from, 0)) };
|
|
5646
3983
|
}
|
|
5647
3984
|
};
|
|
5648
3985
|
const removeRanges = {
|
|
@@ -5661,22 +3998,22 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5661
3998
|
const bad = ranges.findIndex((r) => !(r.to > r.from));
|
|
5662
3999
|
if (bad >= 0) throw new Error(`Range ${bad + 1} is empty or backwards (${ranges[bad].from}\u2013${ranges[bad].to} ms); "to" must be after "from".`);
|
|
5663
4000
|
const merged = mergeVideoRanges(ranges);
|
|
5664
|
-
const before = videoProjectDuration(project());
|
|
5665
|
-
return apply(videoRemoveRangesEdits(merged, tracks), merged.length > 1 ? `Cut ${merged.length} stretches` : "Cut stretch", (r) => ({ removed: merged.length, time: round(before - videoProjectDuration(r.project)), duration: videoProjectDuration(r.project) }));
|
|
4001
|
+
const before = _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, project());
|
|
4002
|
+
return apply(videoRemoveRangesEdits(merged, tracks), merged.length > 1 ? `Cut ${merged.length} stretches` : "Cut stretch", (r) => ({ removed: merged.length, time: round(before - _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, r.project)), duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, r.project) }));
|
|
5666
4003
|
}
|
|
5667
4004
|
};
|
|
5668
4005
|
const rampTarget = (id) => {
|
|
5669
|
-
const at = findVideoClip(project(), id);
|
|
4006
|
+
const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project(), id);
|
|
5670
4007
|
if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
|
|
5671
4008
|
const { clip } = at;
|
|
5672
4009
|
if (clip.type === "sequence") throw new Error(`Clip "${id}" is a compound clip, which plays its sequence at normal speed; change the speed of the clips inside the sequence instead.`);
|
|
5673
4010
|
if (clip.type !== "media") throw new Error(`Clip "${id}" is a ${clip.type === "text" ? "title" : "colour"}, so it has no source to change the speed of; use a video or audio clip.`);
|
|
5674
|
-
if (_optionalChain([project, 'call',
|
|
4011
|
+
if (_optionalChain([project, 'call', _132 => _132(), 'access', _133 => _133.assets, 'access', _134 => _134.find, 'call', _135 => _135((a) => a.id === clip.asset), 'optionalAccess', _136 => _136.kind]) === "image") throw new Error(`Clip "${id}" is a still, so it has no motion to change the speed of.`);
|
|
5675
4012
|
return clip;
|
|
5676
4013
|
};
|
|
5677
4014
|
const rampOut = (r, id) => {
|
|
5678
4015
|
const outcome2 = r.outcomes[r.outcomes.length - 1];
|
|
5679
|
-
return { clip: clipOut(r.project, id), ...outcome2.rippled ? { rippled: outcome2.rippled } : {}, duration: videoProjectDuration(r.project) };
|
|
4016
|
+
return { clip: clipOut(r.project, id), ...outcome2.rippled ? { rippled: outcome2.rippled } : {}, duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, r.project) };
|
|
5680
4017
|
};
|
|
5681
4018
|
const RIPPLE_RAMP = { type: "boolean", description: "Move later material on every sync-locked track by the change in length (default true); false refuses if the clip would overlap the next one." };
|
|
5682
4019
|
const setSpeedRamp = {
|
|
@@ -5707,8 +4044,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5707
4044
|
),
|
|
5708
4045
|
annotations: { title: "Ramp the speed", ...WRITE_IDEMPOTENT },
|
|
5709
4046
|
handler: ({ clip, segments, ripple }) => {
|
|
5710
|
-
const edit = videoSpeedRampEdit(rampTarget(clip), segments, _nullishCoalesce(ripple, () => ( true)));
|
|
5711
|
-
return apply(edit, "Speed ramp", (r) => ({ ...rampOut(r, clip), source: Math.round(videoSpeedRampKeys(segments).source) }));
|
|
4047
|
+
const edit = _chunkSMJGE7HMcjs.videoSpeedRampEdit.call(void 0, rampTarget(clip), segments, _nullishCoalesce(ripple, () => ( true)));
|
|
4048
|
+
return apply(edit, "Speed ramp", (r) => ({ ...rampOut(r, clip), source: Math.round(_chunkSMJGE7HMcjs.videoSpeedRampKeys.call(void 0, segments).source) }));
|
|
5712
4049
|
}
|
|
5713
4050
|
};
|
|
5714
4051
|
const addFreeze = {
|
|
@@ -5728,8 +4065,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5728
4065
|
handler: ({ clip, at, duration, ripple }) => {
|
|
5729
4066
|
const c = rampTarget(clip);
|
|
5730
4067
|
const t = at - c.start;
|
|
5731
|
-
if (t < 0 || t > c.duration) throw new Error(`${formatVideoSeconds(at)} is outside clip "${clip}" (${formatVideoSeconds(c.start)}\u2013${formatVideoSeconds(videoClipEnd(c))}); pick a time inside it.`);
|
|
5732
|
-
return apply(videoFreezeFrameEdit(c, t, duration, _nullishCoalesce(ripple, () => ( true))), "Freeze frame", (r) => rampOut(r, clip));
|
|
4068
|
+
if (t < 0 || t > c.duration) throw new Error(`${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, at)} is outside clip "${clip}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, c.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c))}); pick a time inside it.`);
|
|
4069
|
+
return apply(_chunkSMJGE7HMcjs.videoFreezeFrameEdit.call(void 0, c, t, duration, _nullishCoalesce(ripple, () => ( true))), "Freeze frame", (r) => rampOut(r, clip));
|
|
5733
4070
|
}
|
|
5734
4071
|
};
|
|
5735
4072
|
const removeRamp = {
|
|
@@ -5902,7 +4239,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5902
4239
|
let from;
|
|
5903
4240
|
let to;
|
|
5904
4241
|
if (args.clip !== void 0) {
|
|
5905
|
-
const found = findVideoClip(p, args.clip);
|
|
4242
|
+
const found = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, p, args.clip);
|
|
5906
4243
|
if (!found) throw new Error(`There is no clip "${args.clip}"; get_video_project lists the clips.`);
|
|
5907
4244
|
const c = found.clip;
|
|
5908
4245
|
if (c.type === "sequence") throw new Error(`Clip "${c.id}" is a compound clip; its sound is the mix of its sequence "${c.sequence}", so read the levels of the media in it (list_video_sequences lists its clips and assets).`);
|
|
@@ -5912,7 +4249,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5912
4249
|
toSource = (t) => (_nullishCoalesce(c.in, () => ( 0))) + (t - c.start) * speed;
|
|
5913
4250
|
toOut = (s) => c.start + (s - (_nullishCoalesce(c.in, () => ( 0)))) / speed;
|
|
5914
4251
|
from = Math.max(c.start, _nullishCoalesce(args.from, () => ( c.start)));
|
|
5915
|
-
to = Math.min(videoClipEnd(c), _nullishCoalesce(args.to, () => ( videoClipEnd(c))));
|
|
4252
|
+
to = Math.min(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), _nullishCoalesce(args.to, () => ( _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c))));
|
|
5916
4253
|
} else {
|
|
5917
4254
|
asset = p.assets.find((a) => a.id === args.asset);
|
|
5918
4255
|
if (!asset) throw new Error(`There is no asset "${args.asset}"; the assets are ${p.assets.map((a) => `"${a.id}"`).join(", ") || "none"}.`);
|
|
@@ -5958,7 +4295,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5958
4295
|
const r = soundRange(args);
|
|
5959
4296
|
const peaks = await controller.audioPeaks.load(r.asset);
|
|
5960
4297
|
const silences = findVideoAudioSilences(peaks, r.toSource(r.from), r.toSource(r.to), { thresholdDb: args.thresholdDb, minDuration: args.minDuration }).map((x) => ({ start: round(r.toOut(x.start)), end: round(r.toOut(x.end)) }));
|
|
5961
|
-
return { asset: r.asset.id, from: r.from, to: r.to, silences, total: round(silences.reduce((
|
|
4298
|
+
return { asset: r.asset.id, from: r.from, to: r.to, silences, total: round(silences.reduce((n, x) => n + x.end - x.start, 0)) };
|
|
5962
4299
|
}
|
|
5963
4300
|
};
|
|
5964
4301
|
const pixelsAt = async (time) => {
|
|
@@ -5993,11 +4330,11 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
5993
4330
|
annotations: { title: "Measure a frame with scopes", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
5994
4331
|
handler: async ({ time, bins, columns }) => {
|
|
5995
4332
|
const p = project();
|
|
5996
|
-
const end = videoProjectDuration(p);
|
|
4333
|
+
const end = _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, p);
|
|
5997
4334
|
const t = _nullishCoalesce(time, () => ( controller.getState().time));
|
|
5998
4335
|
if (time !== void 0 && time > end) throw new Error(`Time ${time} ms is past the end of the project (${end} ms).`);
|
|
5999
4336
|
const pixels = await pixelsAt(t);
|
|
6000
|
-
return { time: t, timecode: formatVideoTimecode(t, p.fps), width: pixels.width, height: pixels.height, ...summarizeVideoScopes(pixels, { bins, columns }) };
|
|
4337
|
+
return { time: t, timecode: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, t, p.fps), width: pixels.width, height: pixels.height, ...summarizeVideoScopes(pixels, { bins, columns }) };
|
|
6001
4338
|
}
|
|
6002
4339
|
};
|
|
6003
4340
|
const reads = [getProject, listSequences, getFrame, getTranscript, findText, findFillers, findPauses, findGaps, checkProject, renderFrame, getScopes, previewCache, planProxies, exportFfmpeg, exportLoudnessMeasure, exportEdl, audioLevels, findSilences, seek, setPreviewScale];
|
|
@@ -6250,5 +4587,5 @@ function createVideoEditorToolProvider(controller, options = {}) {
|
|
|
6250
4587
|
|
|
6251
4588
|
|
|
6252
4589
|
|
|
6253
|
-
exports.VIDEO_BLEND_MODES = VIDEO_BLEND_MODES; exports.VIDEO_BLEND_MODE_LABELS = VIDEO_BLEND_MODE_LABELS; exports.VIDEO_CLIP_ANIMATION_DURATION = VIDEO_CLIP_ANIMATION_DURATION; exports.VIDEO_CLIP_ANIMATION_EFFECTS = VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_CLIP_ANIMATION_LABELS = VIDEO_CLIP_ANIMATION_LABELS; exports.VIDEO_CLIP_TYPES = VIDEO_CLIP_TYPES; exports.VIDEO_DEFAULT_FILLERS = VIDEO_DEFAULT_FILLERS; exports.VIDEO_DEFAULT_STILL_DURATION = VIDEO_DEFAULT_STILL_DURATION; exports.VIDEO_DEFAULT_TITLE_DURATION = VIDEO_DEFAULT_TITLE_DURATION; exports.VIDEO_EASE_NAMES = VIDEO_EASE_NAMES; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_FADE_CURVES = VIDEO_FADE_CURVES; exports.VIDEO_FADE_CURVE_LABELS = VIDEO_FADE_CURVE_LABELS; exports.VIDEO_FITS = VIDEO_FITS; exports.VIDEO_GRADE_CONTROLS = VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = VIDEO_GRADE_PRESET_NAMES; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_KEYFRAME_LIMITS = VIDEO_KEYFRAME_LIMITS; exports.VIDEO_KEYFRAME_PROPERTIES = VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_LUT_MAX_SIZE = VIDEO_LUT_MAX_SIZE; exports.VIDEO_PEAK_BLOCK = VIDEO_PEAK_BLOCK; exports.VIDEO_PLACEMENT_MODES = VIDEO_PLACEMENT_MODES; exports.VIDEO_PREVIEW_SCALE_OPTIONS = VIDEO_PREVIEW_SCALE_OPTIONS; exports.VIDEO_PROXY_SCALES = VIDEO_PROXY_SCALES; exports.VIDEO_SCOPE_KINDS = VIDEO_SCOPE_KINDS; exports.VIDEO_TIME_EPSILON = VIDEO_TIME_EPSILON; exports.VIDEO_TRANSFORM_PROPERTIES = VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_TRANSITION_LABELS = VIDEO_TRANSITION_LABELS; exports.VIDEO_TRANSITION_TYPES = VIDEO_TRANSITION_TYPES; exports.VIDEO_VECTORSCOPE_TARGETS = VIDEO_VECTORSCOPE_TARGETS; exports.VIDEO_WIPE_DIRECTIONS = VIDEO_WIPE_DIRECTIONS; exports.VideoAudioPeaksCache = VideoAudioPeaksCache; exports.VideoEditorController = VideoEditorController; exports.VideoFrameCache = VideoFrameCache; exports.VideoLutCache = VideoLutCache; exports.VideoPreviewEngine = VideoPreviewEngine; exports.VideoPreviewPixels = VideoPreviewPixels; exports.allVideoClipIds = allVideoClipIds; exports.allVideoTracks = allVideoTracks; exports.applyVideoEdits = applyVideoEdits; exports.applyVideoGrade = applyVideoGrade; exports.applyVideoLut = applyVideoLut; exports.applyVideoLutToPixels = applyVideoLutToPixels; exports.buildVideoAudioPeaks = buildVideoAudioPeaks; exports.checkVideoProject = checkVideoProject; exports.checkVideoTimeRemap = checkVideoTimeRemap; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoElementDecoder = createVideoElementDecoder; exports.createVideoProject = createVideoProject; exports.decodeVideoAudioPeaks = decodeVideoAudioPeaks; exports.describeVideoProject = describeVideoProject; exports.describeVideoSequence = describeVideoSequence; exports.drawVideoFrame = drawVideoFrame; exports.ffmpegFilterValue = ffmpegFilterValue; exports.findVideoAudioSilences = findVideoAudioSilences; exports.findVideoClip = findVideoClip; exports.findVideoFillers = findVideoFillers; exports.findVideoGaps = findVideoGaps; exports.findVideoSequenceClip = findVideoSequenceClip; exports.findVideoSequenceCycle = findVideoSequenceCycle; exports.findVideoTranscriptPauses = findVideoTranscriptPauses; exports.findVideoTranscriptText = findVideoTranscriptText; exports.formatVideoSeconds = formatVideoSeconds; exports.formatVideoTimecode = formatVideoTimecode; exports.formatVideoTimecodeFrames = formatVideoTimecodeFrames; exports.isVideoDropFrameRate = isVideoDropFrameRate; exports.isVideoKeyframes = isVideoKeyframes; exports.mergeVideoRanges = mergeVideoRanges; exports.nextFreeVideoSlot = nextFreeVideoSlot; exports.normalizeVideoGrade = normalizeVideoGrade; exports.normalizeVideoGradeLut = normalizeVideoGradeLut; exports.normalizeVideoWord = normalizeVideoWord; exports.parseVideoAnimatable = parseVideoAnimatable; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoAssetProxies = parseVideoAssetProxies; exports.parseVideoClip = parseVideoClip; exports.parseVideoClipAnimation = parseVideoClipAnimation; exports.parseVideoCubeLut = parseVideoCubeLut; exports.parseVideoGrade = parseVideoGrade; exports.parseVideoGradeLut = parseVideoGradeLut; exports.parseVideoKeyframes = parseVideoKeyframes; exports.parseVideoLoudnessMeasurement = parseVideoLoudnessMeasurement; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoPreviewScale = parseVideoPreviewScale; exports.parseVideoProject = parseVideoProject; exports.parseVideoSequence = parseVideoSequence; exports.parseVideoTimeRemap = parseVideoTimeRemap; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTranscript = parseVideoTranscript; exports.parseVideoTranscriptWords = parseVideoTranscriptWords; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.planVideoPrefetch = planVideoPrefetch; exports.probeVideoMedia = probeVideoMedia; exports.readVideoScopesPanel = readVideoScopesPanel; exports.removeVideoKey = removeVideoKey; exports.resolveVideoPreviewScale = resolveVideoPreviewScale; exports.retimeVideoAnimatable = retimeVideoAnimatable; exports.setVideoKey = setVideoKey; exports.snapToVideoFrame = snapToVideoFrame; exports.snapVideoTime = snapVideoTime; exports.sortVideoKeys = sortVideoKeys; exports.sortedVideoClips = sortedVideoClips; exports.splitVideoAnimatable = splitVideoAnimatable; exports.summarizeVideoScopes = summarizeVideoScopes; exports.toVideoEdl = toVideoEdl; exports.toVideoFfmpeg = toVideoFfmpeg; exports.toVideoLoudnessMeasure = toVideoLoudnessMeasure; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetHasSound = videoAssetHasSound; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = videoAssetMap; exports.videoAssetProxy = videoAssetProxy; exports.videoAudioLevels = videoAudioLevels; exports.videoAudioPeakRange = videoAudioPeakRange; exports.videoAudioPeakSpans = videoAudioPeakSpans; exports.videoAudioPeaksDuration = videoAudioPeaksDuration; exports.videoCacheEvictions = videoCacheEvictions; exports.videoChroma = videoChroma; exports.videoClipAfter = videoClipAfter; exports.videoClipAnimated = videoClipAnimated; exports.videoClipAnimationProperties = videoClipAnimationProperties; exports.videoClipAnimationSpans = videoClipAnimationSpans; exports.videoClipBefore = videoClipBefore; exports.videoClipEnd = videoClipEnd; exports.videoClipHandles = videoClipHandles; exports.videoClipKeyframes = videoClipKeyframes; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = videoClipOverhang; exports.videoClipShowsWaveform = videoClipShowsWaveform; exports.videoClipSoundGain = videoClipSoundGain; exports.videoClipSourceRange = videoClipSourceRange; exports.videoClipSourceTime = videoClipSourceTime; exports.videoClipSpeed = videoClipSpeed; exports.videoClipSpeedAt = videoClipSpeedAt; exports.videoClipTint = videoClipTint; exports.videoClipWaveform = videoClipWaveform; exports.videoClipWaveformPath = videoClipWaveformPath; exports.videoClipsAt = videoClipsAt; exports.videoContactSheetSvg = videoContactSheetSvg; exports.videoDragLabel = videoDragLabel; exports.videoDropTracks = videoDropTracks; exports.videoEaseBezier = videoEaseBezier; exports.videoEaseProgress = videoEaseProgress; exports.videoExposureNotes = videoExposureNotes; exports.videoExposureStats = videoExposureStats; exports.videoFadeCurveGain = videoFadeCurveGain; exports.videoFrameAt = videoFrameAt; exports.videoFrameCacheKey = videoFrameCacheKey; exports.videoFrameDuration = videoFrameDuration; exports.videoFrameLeafLayers = videoFrameLeafLayers; exports.videoFrameRequestsAt = videoFrameRequestsAt; exports.videoFrameToSvg = videoFrameToSvg; exports.videoFrames = videoFrames; exports.videoFreezeFrameEdit = videoFreezeFrameEdit; exports.videoGradeCssFilter = videoGradeCssFilter; exports.videoGradeFfmpegFilters = videoGradeFfmpegFilters; exports.videoGradeGainsFilterId = videoGradeGainsFilterId; exports.videoGradeLook = videoGradeLook; exports.videoGradePreset = videoGradePreset; exports.videoGradeStepMatrix = videoGradeStepMatrix; exports.videoGradeStepSvgValues = videoGradeStepSvgValues; exports.videoGradeSteps = videoGradeSteps; exports.videoGradeSvgDefs = videoGradeSvgDefs; exports.videoGradeSvgFilter = videoGradeSvgFilter; exports.videoHistogram = videoHistogram; exports.videoHistogramImage = videoHistogramImage; exports.videoHourFrames = videoHourFrames; exports.videoIrisRadius = videoIrisRadius; exports.videoIssueKey = videoIssueKey; exports.videoKeyframeBreakpoints = videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = videoKeyframeFfmpegExpr; exports.videoKeyframeRows = videoKeyframeRows; exports.videoKeyframeToggleEdit = videoKeyframeToggleEdit; exports.videoKeyframeValueEdit = videoKeyframeValueEdit; exports.videoKeysOf = videoKeysOf; exports.videoLuma = videoLuma; exports.videoLumaWaveform = videoLumaWaveform; exports.videoLutEdits = videoLutEdits; exports.videoLutFromFunction = videoLutFromFunction; exports.videoLutSvgApproximation = videoLutSvgApproximation; exports.videoLutSvgPrimitives = videoLutSvgPrimitives; exports.videoLutToCube = videoLutToCube; exports.videoOverlap = videoOverlap; exports.videoPeakDb = videoPeakDb; exports.videoPreviewSrc = videoPreviewSrc; exports.videoProjectDuration = videoProjectDuration; exports.videoProjectHasProxies = videoProjectHasProxies; exports.videoProjectSvg = videoProjectSvg; exports.videoProxyFfmpeg = videoProxyFfmpeg; exports.videoProxyName = videoProxyName; exports.videoProxyPlan = videoProxyPlan; exports.videoRemoveRangesEdits = videoRemoveRangesEdits; exports.videoRulerTicks = videoRulerTicks; exports.videoScopeImage = videoScopeImage; exports.videoSequenceChildren = videoSequenceChildren; exports.videoSequenceDuration = videoSequenceDuration; exports.videoSequenceMap = videoSequenceMap; exports.videoShellQuote = videoShellQuote; exports.videoSlowMotionRamp = videoSlowMotionRamp; exports.videoSnapPoints = videoSnapPoints; exports.videoSourceFrame = videoSourceFrame; exports.videoSourceFrameTime = videoSourceFrameTime; exports.videoSpeedRampEdit = videoSpeedRampEdit; exports.videoSpeedRampKeys = videoSpeedRampKeys; exports.videoTextStyle = videoTextStyle; exports.videoTimeRemapBreakpoints = videoTimeRemapBreakpoints; exports.videoTimeRemapSpan = videoTimeRemapSpan; exports.videoTimecodeFrames = videoTimecodeFrames; exports.videoTimelineTranscript = videoTimelineTranscript; exports.videoTitleFrame = videoTitleFrame; exports.videoTrackSyncLocked = videoTrackSyncLocked; exports.videoTranscriptEdit = videoTranscriptEdit; exports.videoTranscriptTrack = videoTranscriptTrack; exports.videoTransformAt = videoTransformAt; exports.videoTransitionAudioCurve = videoTransitionAudioCurve; exports.videoTransitionEase = videoTransitionEase; exports.videoTransitionHasDirection = videoTransitionHasDirection; exports.videoValueAt = videoValueAt; exports.videoVectorscope = videoVectorscope; exports.videoVectorscopeAngle = videoVectorscopeAngle; exports.videoVectorscopeImage = videoVectorscopeImage; exports.videoVectorscopePoint = videoVectorscopePoint; exports.videoWaveformImage = videoWaveformImage; exports.videoWaveformPath = videoWaveformPath; exports.videoWipeRect = videoWipeRect; exports.videoWordAt = videoWordAt; exports.videoWordsRange = videoWordsRange;
|
|
4590
|
+
exports.VIDEO_BLEND_MODES = _chunkSMJGE7HMcjs.VIDEO_BLEND_MODES; exports.VIDEO_BLEND_MODE_LABELS = VIDEO_BLEND_MODE_LABELS; exports.VIDEO_CLIP_ANIMATION_DURATION = _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_DURATION; exports.VIDEO_CLIP_ANIMATION_EFFECTS = _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_CLIP_ANIMATION_LABELS = VIDEO_CLIP_ANIMATION_LABELS; exports.VIDEO_CLIP_TYPES = _chunkSMJGE7HMcjs.VIDEO_CLIP_TYPES; exports.VIDEO_DEFAULT_FILLERS = VIDEO_DEFAULT_FILLERS; exports.VIDEO_DEFAULT_STILL_DURATION = VIDEO_DEFAULT_STILL_DURATION; exports.VIDEO_DEFAULT_TITLE_DURATION = VIDEO_DEFAULT_TITLE_DURATION; exports.VIDEO_EASE_NAMES = _chunkSMJGE7HMcjs.VIDEO_EASE_NAMES; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_FADE_CURVES = _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES; exports.VIDEO_FADE_CURVE_LABELS = VIDEO_FADE_CURVE_LABELS; exports.VIDEO_FITS = _chunkSMJGE7HMcjs.VIDEO_FITS; exports.VIDEO_GRADE_CONTROLS = _chunkSMJGE7HMcjs.VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = _chunkSMJGE7HMcjs.VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = _chunkSMJGE7HMcjs.VIDEO_GRADE_PRESET_NAMES; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_KEYFRAME_LIMITS = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS; exports.VIDEO_KEYFRAME_PROPERTIES = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_LUT_MAX_SIZE = _chunkSMJGE7HMcjs.VIDEO_LUT_MAX_SIZE; exports.VIDEO_PEAK_BLOCK = VIDEO_PEAK_BLOCK; exports.VIDEO_PLACEMENT_MODES = _chunkSMJGE7HMcjs.VIDEO_PLACEMENT_MODES; exports.VIDEO_PREVIEW_SCALE_OPTIONS = VIDEO_PREVIEW_SCALE_OPTIONS; exports.VIDEO_PROXY_SCALES = VIDEO_PROXY_SCALES; exports.VIDEO_SCOPE_KINDS = VIDEO_SCOPE_KINDS; exports.VIDEO_TIME_EPSILON = _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON; exports.VIDEO_TRANSFORM_PROPERTIES = _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_TRANSITION_LABELS = VIDEO_TRANSITION_LABELS; exports.VIDEO_TRANSITION_TYPES = _chunkSMJGE7HMcjs.VIDEO_TRANSITION_TYPES; exports.VIDEO_VECTORSCOPE_TARGETS = VIDEO_VECTORSCOPE_TARGETS; exports.VIDEO_WIPE_DIRECTIONS = _chunkSMJGE7HMcjs.VIDEO_WIPE_DIRECTIONS; exports.VideoAudioPeaksCache = VideoAudioPeaksCache; exports.VideoEditorController = VideoEditorController; exports.VideoFrameCache = VideoFrameCache; exports.VideoLutCache = _chunkSMJGE7HMcjs.VideoLutCache; exports.VideoPreviewEngine = VideoPreviewEngine; exports.VideoPreviewPixels = VideoPreviewPixels; exports.allVideoClipIds = _chunkSMJGE7HMcjs.allVideoClipIds; exports.allVideoTracks = _chunkSMJGE7HMcjs.allVideoTracks; exports.applyVideoEdits = applyVideoEdits; exports.applyVideoGrade = _chunkSMJGE7HMcjs.applyVideoGrade; exports.applyVideoLut = _chunkSMJGE7HMcjs.applyVideoLut; exports.applyVideoLutToPixels = _chunkSMJGE7HMcjs.applyVideoLutToPixels; exports.buildVideoAudioPeaks = buildVideoAudioPeaks; exports.checkVideoProject = checkVideoProject; exports.checkVideoTimeRemap = _chunkSMJGE7HMcjs.checkVideoTimeRemap; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoElementDecoder = createVideoElementDecoder; exports.createVideoProject = createVideoProject; exports.decodeVideoAudioPeaks = decodeVideoAudioPeaks; exports.describeVideoProject = describeVideoProject; exports.describeVideoSequence = describeVideoSequence; exports.drawVideoFrame = _chunkSMJGE7HMcjs.drawVideoFrame; exports.ffmpegFilterValue = _chunkSMJGE7HMcjs.ffmpegFilterValue; exports.findVideoAudioSilences = findVideoAudioSilences; exports.findVideoClip = _chunkSMJGE7HMcjs.findVideoClip; exports.findVideoFillers = findVideoFillers; exports.findVideoGaps = _chunkSMJGE7HMcjs.findVideoGaps; exports.findVideoSequenceClip = _chunkSMJGE7HMcjs.findVideoSequenceClip; exports.findVideoSequenceCycle = _chunkSMJGE7HMcjs.findVideoSequenceCycle; exports.findVideoTranscriptPauses = findVideoTranscriptPauses; exports.findVideoTranscriptText = findVideoTranscriptText; exports.formatVideoSeconds = _chunkSMJGE7HMcjs.formatVideoSeconds; exports.formatVideoTimecode = _chunkSMJGE7HMcjs.formatVideoTimecode; exports.formatVideoTimecodeFrames = _chunkSMJGE7HMcjs.formatVideoTimecodeFrames; exports.isVideoDropFrameRate = _chunkSMJGE7HMcjs.isVideoDropFrameRate; exports.isVideoKeyframes = _chunkSMJGE7HMcjs.isVideoKeyframes; exports.mergeVideoRanges = mergeVideoRanges; exports.nextFreeVideoSlot = _chunkSMJGE7HMcjs.nextFreeVideoSlot; exports.normalizeVideoGrade = _chunkSMJGE7HMcjs.normalizeVideoGrade; exports.normalizeVideoGradeLut = _chunkSMJGE7HMcjs.normalizeVideoGradeLut; exports.normalizeVideoWord = normalizeVideoWord; exports.parseVideoAnimatable = parseVideoAnimatable; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoAssetProxies = parseVideoAssetProxies; exports.parseVideoClip = parseVideoClip; exports.parseVideoClipAnimation = parseVideoClipAnimation; exports.parseVideoCubeLut = _chunkSMJGE7HMcjs.parseVideoCubeLut; exports.parseVideoGrade = parseVideoGrade; exports.parseVideoGradeLut = parseVideoGradeLut; exports.parseVideoKeyframes = parseVideoKeyframes; exports.parseVideoLoudnessMeasurement = _chunkSMJGE7HMcjs.parseVideoLoudnessMeasurement; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoPreviewScale = parseVideoPreviewScale; exports.parseVideoProject = parseVideoProject; exports.parseVideoSequence = parseVideoSequence; exports.parseVideoTimeRemap = parseVideoTimeRemap; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTranscript = parseVideoTranscript; exports.parseVideoTranscriptWords = parseVideoTranscriptWords; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = _chunkSMJGE7HMcjs.placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.planVideoPrefetch = planVideoPrefetch; exports.probeVideoMedia = probeVideoMedia; exports.readVideoScopesPanel = readVideoScopesPanel; exports.removeVideoKey = _chunkSMJGE7HMcjs.removeVideoKey; exports.resolveVideoPreviewScale = resolveVideoPreviewScale; exports.retimeVideoAnimatable = _chunkSMJGE7HMcjs.retimeVideoAnimatable; exports.setVideoKey = _chunkSMJGE7HMcjs.setVideoKey; exports.snapToVideoFrame = _chunkSMJGE7HMcjs.snapToVideoFrame; exports.snapVideoTime = _chunkSMJGE7HMcjs.snapVideoTime; exports.sortVideoKeys = _chunkSMJGE7HMcjs.sortVideoKeys; exports.sortedVideoClips = _chunkSMJGE7HMcjs.sortedVideoClips; exports.splitVideoAnimatable = _chunkSMJGE7HMcjs.splitVideoAnimatable; exports.summarizeVideoScopes = summarizeVideoScopes; exports.toVideoEdl = _chunkSMJGE7HMcjs.toVideoEdl; exports.toVideoFfmpeg = _chunkSMJGE7HMcjs.toVideoFfmpeg; exports.toVideoLoudnessMeasure = _chunkSMJGE7HMcjs.toVideoLoudnessMeasure; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetHasSound = _chunkSMJGE7HMcjs.videoAssetHasSound; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = _chunkSMJGE7HMcjs.videoAssetMap; exports.videoAssetProxy = videoAssetProxy; exports.videoAudioLevels = videoAudioLevels; exports.videoAudioPeakRange = videoAudioPeakRange; exports.videoAudioPeakSpans = videoAudioPeakSpans; exports.videoAudioPeaksDuration = videoAudioPeaksDuration; exports.videoCacheEvictions = videoCacheEvictions; exports.videoChroma = videoChroma; exports.videoClipAfter = _chunkSMJGE7HMcjs.videoClipAfter; exports.videoClipAnimated = _chunkSMJGE7HMcjs.videoClipAnimated; exports.videoClipAnimationProperties = _chunkSMJGE7HMcjs.videoClipAnimationProperties; exports.videoClipAnimationSpans = _chunkSMJGE7HMcjs.videoClipAnimationSpans; exports.videoClipBefore = _chunkSMJGE7HMcjs.videoClipBefore; exports.videoClipEnd = _chunkSMJGE7HMcjs.videoClipEnd; exports.videoClipHandles = _chunkSMJGE7HMcjs.videoClipHandles; exports.videoClipKeyframes = videoClipKeyframes; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = _chunkSMJGE7HMcjs.videoClipOverhang; exports.videoClipShowsWaveform = videoClipShowsWaveform; exports.videoClipSoundGain = _chunkSMJGE7HMcjs.videoClipSoundGain; exports.videoClipSourceRange = _chunkSMJGE7HMcjs.videoClipSourceRange; exports.videoClipSourceTime = _chunkSMJGE7HMcjs.videoClipSourceTime; exports.videoClipSpeed = _chunkSMJGE7HMcjs.videoClipSpeed; exports.videoClipSpeedAt = _chunkSMJGE7HMcjs.videoClipSpeedAt; exports.videoClipTint = videoClipTint; exports.videoClipWaveform = videoClipWaveform; exports.videoClipWaveformPath = videoClipWaveformPath; exports.videoClipsAt = _chunkSMJGE7HMcjs.videoClipsAt; exports.videoContactSheetSvg = _chunkSMJGE7HMcjs.videoContactSheetSvg; exports.videoDragLabel = videoDragLabel; exports.videoDropTracks = videoDropTracks; exports.videoEaseBezier = _chunkSMJGE7HMcjs.videoEaseBezier; exports.videoEaseProgress = _chunkSMJGE7HMcjs.videoEaseProgress; exports.videoExposureNotes = videoExposureNotes; exports.videoExposureStats = videoExposureStats; exports.videoFadeCurveGain = _chunkSMJGE7HMcjs.videoFadeCurveGain; exports.videoFrameAt = _chunkSMJGE7HMcjs.videoFrameAt; exports.videoFrameCacheKey = videoFrameCacheKey; exports.videoFrameDuration = _chunkSMJGE7HMcjs.videoFrameDuration; exports.videoFrameLeafLayers = _chunkSMJGE7HMcjs.videoFrameLeafLayers; exports.videoFrameRequestsAt = videoFrameRequestsAt; exports.videoFrameToSvg = _chunkSMJGE7HMcjs.videoFrameToSvg; exports.videoFrames = _chunkSMJGE7HMcjs.videoFrames; exports.videoFreezeFrameEdit = _chunkSMJGE7HMcjs.videoFreezeFrameEdit; exports.videoGradeCssFilter = _chunkSMJGE7HMcjs.videoGradeCssFilter; exports.videoGradeFfmpegFilters = _chunkSMJGE7HMcjs.videoGradeFfmpegFilters; exports.videoGradeGainsFilterId = _chunkSMJGE7HMcjs.videoGradeGainsFilterId; exports.videoGradeLook = _chunkSMJGE7HMcjs.videoGradeLook; exports.videoGradePreset = _chunkSMJGE7HMcjs.videoGradePreset; exports.videoGradeStepMatrix = _chunkSMJGE7HMcjs.videoGradeStepMatrix; exports.videoGradeStepSvgValues = _chunkSMJGE7HMcjs.videoGradeStepSvgValues; exports.videoGradeSteps = _chunkSMJGE7HMcjs.videoGradeSteps; exports.videoGradeSvgDefs = _chunkSMJGE7HMcjs.videoGradeSvgDefs; exports.videoGradeSvgFilter = _chunkSMJGE7HMcjs.videoGradeSvgFilter; exports.videoHistogram = videoHistogram; exports.videoHistogramImage = videoHistogramImage; exports.videoHourFrames = _chunkSMJGE7HMcjs.videoHourFrames; exports.videoIrisRadius = _chunkSMJGE7HMcjs.videoIrisRadius; exports.videoIssueKey = videoIssueKey; exports.videoKeyframeBreakpoints = _chunkSMJGE7HMcjs.videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = _chunkSMJGE7HMcjs.videoKeyframeFfmpegExpr; exports.videoKeyframeRows = videoKeyframeRows; exports.videoKeyframeToggleEdit = videoKeyframeToggleEdit; exports.videoKeyframeValueEdit = videoKeyframeValueEdit; exports.videoKeysOf = _chunkSMJGE7HMcjs.videoKeysOf; exports.videoLuma = videoLuma; exports.videoLumaWaveform = videoLumaWaveform; exports.videoLutEdits = videoLutEdits; exports.videoLutFromFunction = _chunkSMJGE7HMcjs.videoLutFromFunction; exports.videoLutSvgApproximation = _chunkSMJGE7HMcjs.videoLutSvgApproximation; exports.videoLutSvgPrimitives = _chunkSMJGE7HMcjs.videoLutSvgPrimitives; exports.videoLutToCube = _chunkSMJGE7HMcjs.videoLutToCube; exports.videoOverlap = _chunkSMJGE7HMcjs.videoOverlap; exports.videoPeakDb = videoPeakDb; exports.videoPreviewSrc = videoPreviewSrc; exports.videoProjectDuration = _chunkSMJGE7HMcjs.videoProjectDuration; exports.videoProjectHasProxies = videoProjectHasProxies; exports.videoProjectSvg = _chunkSMJGE7HMcjs.videoProjectSvg; exports.videoProxyFfmpeg = videoProxyFfmpeg; exports.videoProxyName = videoProxyName; exports.videoProxyPlan = videoProxyPlan; exports.videoRemoveRangesEdits = videoRemoveRangesEdits; exports.videoRulerTicks = videoRulerTicks; exports.videoScopeImage = videoScopeImage; exports.videoSequenceChildren = _chunkSMJGE7HMcjs.videoSequenceChildren; exports.videoSequenceDuration = _chunkSMJGE7HMcjs.videoSequenceDuration; exports.videoSequenceMap = _chunkSMJGE7HMcjs.videoSequenceMap; exports.videoShellQuote = _chunkSMJGE7HMcjs.videoShellQuote; exports.videoSlowMotionRamp = _chunkSMJGE7HMcjs.videoSlowMotionRamp; exports.videoSnapPoints = _chunkSMJGE7HMcjs.videoSnapPoints; exports.videoSourceFrame = videoSourceFrame; exports.videoSourceFrameTime = videoSourceFrameTime; exports.videoSpeedRampEdit = _chunkSMJGE7HMcjs.videoSpeedRampEdit; exports.videoSpeedRampKeys = _chunkSMJGE7HMcjs.videoSpeedRampKeys; exports.videoTextStyle = _chunkSMJGE7HMcjs.videoTextStyle; exports.videoTimeRemapBreakpoints = _chunkSMJGE7HMcjs.videoTimeRemapBreakpoints; exports.videoTimeRemapSpan = _chunkSMJGE7HMcjs.videoTimeRemapSpan; exports.videoTimecodeFrames = _chunkSMJGE7HMcjs.videoTimecodeFrames; exports.videoTimelineTranscript = videoTimelineTranscript; exports.videoTitleFrame = _chunkSMJGE7HMcjs.videoTitleFrame; exports.videoTrackSyncLocked = _chunkSMJGE7HMcjs.videoTrackSyncLocked; exports.videoTranscriptEdit = videoTranscriptEdit; exports.videoTranscriptTrack = videoTranscriptTrack; exports.videoTransformAt = _chunkSMJGE7HMcjs.videoTransformAt; exports.videoTransitionAudioCurve = _chunkSMJGE7HMcjs.videoTransitionAudioCurve; exports.videoTransitionEase = _chunkSMJGE7HMcjs.videoTransitionEase; exports.videoTransitionHasDirection = videoTransitionHasDirection; exports.videoValueAt = _chunkSMJGE7HMcjs.videoValueAt; exports.videoVectorscope = videoVectorscope; exports.videoVectorscopeAngle = videoVectorscopeAngle; exports.videoVectorscopeImage = videoVectorscopeImage; exports.videoVectorscopePoint = videoVectorscopePoint; exports.videoWaveformImage = videoWaveformImage; exports.videoWaveformPath = videoWaveformPath; exports.videoWipeRect = _chunkSMJGE7HMcjs.videoWipeRect; exports.videoWordAt = videoWordAt; exports.videoWordsRange = videoWordsRange;
|
|
6254
4591
|
//# sourceMappingURL=index.cjs.map
|