@remotion/web-renderer 4.0.431 → 4.0.433
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/can-render-types.d.ts +2 -2
- package/dist/esm/index.mjs +401 -98
- package/dist/index.d.ts +1 -1
- package/dist/mediabunny-mappings.d.ts +6 -4
- package/dist/register-aac-encoder.d.ts +1 -0
- package/dist/register-flac-encoder.d.ts +1 -0
- package/dist/render-media-on-web.d.ts +1 -1
- package/package.json +11 -8
- package/dist/add-sample.js +0 -20
- package/dist/artifact.js +0 -56
- package/dist/audio.js +0 -42
- package/dist/calculate-transforms.d.ts +0 -9
- package/dist/calculate-transforms.js +0 -74
- package/dist/can-use-webfs-target.js +0 -19
- package/dist/composable.d.ts +0 -10
- package/dist/composable.js +0 -1
- package/dist/compose-canvas.d.ts +0 -1
- package/dist/compose-canvas.js +0 -12
- package/dist/compose-svg.d.ts +0 -1
- package/dist/compose-svg.js +0 -34
- package/dist/compose.js +0 -85
- package/dist/create-scaffold.js +0 -104
- package/dist/drawing/border-radius.js +0 -151
- package/dist/drawing/calculate-object-fit.js +0 -208
- package/dist/drawing/calculate-transforms.js +0 -127
- package/dist/drawing/clamp-rect-to-parent-bounds.js +0 -18
- package/dist/drawing/do-rects-intersect.js +0 -6
- package/dist/drawing/draw-background.js +0 -62
- package/dist/drawing/draw-border.js +0 -353
- package/dist/drawing/draw-box-shadow.js +0 -103
- package/dist/drawing/draw-dom-element.js +0 -85
- package/dist/drawing/draw-element-to-canvas.d.ts +0 -11
- package/dist/drawing/draw-element-to-canvas.js +0 -64
- package/dist/drawing/draw-element.js +0 -84
- package/dist/drawing/draw-outline.js +0 -93
- package/dist/drawing/draw-rounded.js +0 -34
- package/dist/drawing/drawn-fn.js +0 -1
- package/dist/drawing/fit-svg-into-its-dimensions.js +0 -35
- package/dist/drawing/get-clipped-background.d.ts +0 -23
- package/dist/drawing/get-clipped-background.js +0 -14
- package/dist/drawing/get-padding-box.js +0 -30
- package/dist/drawing/get-pretransform-rect.js +0 -49
- package/dist/drawing/go-rects-intersect.d.ts +0 -1
- package/dist/drawing/go-rects-intersect.js +0 -6
- package/dist/drawing/handle-3d-transform.js +0 -26
- package/dist/drawing/handle-mask.js +0 -21
- package/dist/drawing/has-transform.js +0 -14
- package/dist/drawing/mask-image.js +0 -14
- package/dist/drawing/opacity.js +0 -7
- package/dist/drawing/overflow.js +0 -14
- package/dist/drawing/parse-linear-gradient.js +0 -260
- package/dist/drawing/parse-transform-origin.js +0 -7
- package/dist/drawing/precompose.d.ts +0 -27
- package/dist/drawing/precompose.js +0 -14
- package/dist/drawing/process-node.js +0 -122
- package/dist/drawing/round-to-expand-rect.js +0 -7
- package/dist/drawing/text/apply-text-transform.js +0 -12
- package/dist/drawing/text/draw-text.js +0 -53
- package/dist/drawing/text/find-line-breaks.text.js +0 -118
- package/dist/drawing/text/get-base-height.d.ts +0 -1
- package/dist/drawing/text/get-base-height.js +0 -13
- package/dist/drawing/text/get-collapsed-text.d.ts +0 -1
- package/dist/drawing/text/get-collapsed-text.js +0 -46
- package/dist/drawing/text/handle-text-node.js +0 -24
- package/dist/drawing/transform-in-3d.js +0 -177
- package/dist/drawing/transform-rect-with-matrix.js +0 -19
- package/dist/drawing/transform.js +0 -10
- package/dist/drawing/turn-svg-into-drawable.js +0 -41
- package/dist/find-capturable-elements.d.ts +0 -2
- package/dist/find-capturable-elements.js +0 -28
- package/dist/frame-range.js +0 -15
- package/dist/get-audio-encoding-config.js +0 -18
- package/dist/get-biggest-bounding-client-rect.js +0 -43
- package/dist/index.js +0 -2
- package/dist/internal-state.js +0 -21
- package/dist/mediabunny-mappings.js +0 -63
- package/dist/output-target.js +0 -1
- package/dist/parse-transform-origin.d.ts +0 -4
- package/dist/parse-transform-origin.js +0 -7
- package/dist/props-if-has-props.js +0 -1
- package/dist/render-media-on-web.js +0 -297
- package/dist/render-operations-queue.js +0 -3
- package/dist/render-still-on-web.js +0 -109
- package/dist/send-telemetry-event.js +0 -22
- package/dist/take-screenshot.js +0 -30
- package/dist/throttle-progress.js +0 -43
- package/dist/tree-walker-cleanup-after-children.js +0 -33
- package/dist/update-time.js +0 -17
- package/dist/validate-video-frame.js +0 -34
- package/dist/wait-for-ready.js +0 -35
- package/dist/walk-tree.js +0 -14
- package/dist/web-fs-target.js +0 -41
- package/dist/with-resolvers.js +0 -9
package/dist/esm/index.mjs
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
7
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
8
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
9
|
+
for (let key of __getOwnPropNames(mod))
|
|
10
|
+
if (!__hasOwnProp.call(to, key))
|
|
11
|
+
__defProp(to, key, {
|
|
12
|
+
get: () => mod[key],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
18
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
19
|
+
}) : x)(function(x) {
|
|
20
|
+
if (typeof require !== "undefined")
|
|
21
|
+
return require.apply(this, arguments);
|
|
22
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
23
|
+
});
|
|
1
24
|
var __dispose = Symbol.dispose || /* @__PURE__ */ Symbol.for("Symbol.dispose");
|
|
2
25
|
var __asyncDispose = Symbol.asyncDispose || /* @__PURE__ */ Symbol.for("Symbol.asyncDispose");
|
|
3
26
|
var __using = (stack, value, async) => {
|
|
@@ -91,14 +114,24 @@ var checkWebGLSupport = () => {
|
|
|
91
114
|
|
|
92
115
|
// src/mediabunny-mappings.ts
|
|
93
116
|
import {
|
|
117
|
+
AdtsOutputFormat,
|
|
118
|
+
FlacOutputFormat,
|
|
119
|
+
MkvOutputFormat,
|
|
120
|
+
MovOutputFormat,
|
|
121
|
+
Mp3OutputFormat,
|
|
94
122
|
Mp4OutputFormat,
|
|
123
|
+
OggOutputFormat,
|
|
95
124
|
QUALITY_HIGH,
|
|
96
125
|
QUALITY_LOW,
|
|
97
126
|
QUALITY_MEDIUM,
|
|
98
127
|
QUALITY_VERY_HIGH,
|
|
99
128
|
QUALITY_VERY_LOW,
|
|
129
|
+
WavOutputFormat,
|
|
100
130
|
WebMOutputFormat
|
|
101
131
|
} from "mediabunny";
|
|
132
|
+
var isAudioOnlyContainer = (container) => {
|
|
133
|
+
return container === "wav" || container === "mp3" || container === "aac" || container === "ogg" || container === "flac";
|
|
134
|
+
};
|
|
102
135
|
var codecToMediabunnyCodec = (codec) => {
|
|
103
136
|
switch (codec) {
|
|
104
137
|
case "h264":
|
|
@@ -118,9 +151,23 @@ var codecToMediabunnyCodec = (codec) => {
|
|
|
118
151
|
var containerToMediabunnyContainer = (container) => {
|
|
119
152
|
switch (container) {
|
|
120
153
|
case "mp4":
|
|
121
|
-
return new Mp4OutputFormat;
|
|
154
|
+
return new Mp4OutputFormat({ fastStart: "reserve" });
|
|
122
155
|
case "webm":
|
|
123
156
|
return new WebMOutputFormat;
|
|
157
|
+
case "mkv":
|
|
158
|
+
return new MkvOutputFormat;
|
|
159
|
+
case "wav":
|
|
160
|
+
return new WavOutputFormat;
|
|
161
|
+
case "mp3":
|
|
162
|
+
return new Mp3OutputFormat;
|
|
163
|
+
case "aac":
|
|
164
|
+
return new AdtsOutputFormat;
|
|
165
|
+
case "ogg":
|
|
166
|
+
return new OggOutputFormat;
|
|
167
|
+
case "flac":
|
|
168
|
+
return new FlacOutputFormat;
|
|
169
|
+
case "mov":
|
|
170
|
+
return new MovOutputFormat({ fastStart: "reserve" });
|
|
124
171
|
default:
|
|
125
172
|
throw new Error(`Unsupported container: ${container}`);
|
|
126
173
|
}
|
|
@@ -131,10 +178,32 @@ var getDefaultVideoCodecForContainer = (container) => {
|
|
|
131
178
|
return "h264";
|
|
132
179
|
case "webm":
|
|
133
180
|
return "vp8";
|
|
181
|
+
case "mkv":
|
|
182
|
+
case "mov":
|
|
183
|
+
return "h264";
|
|
184
|
+
case "wav":
|
|
185
|
+
case "mp3":
|
|
186
|
+
case "aac":
|
|
187
|
+
case "ogg":
|
|
188
|
+
case "flac":
|
|
189
|
+
return null;
|
|
134
190
|
default:
|
|
135
191
|
throw new Error(`Unsupported container: ${container}`);
|
|
136
192
|
}
|
|
137
193
|
};
|
|
194
|
+
var getDefaultContainerForCodec = (codec) => {
|
|
195
|
+
switch (codec) {
|
|
196
|
+
case "h264":
|
|
197
|
+
case "h265":
|
|
198
|
+
case "av1":
|
|
199
|
+
return "mp4";
|
|
200
|
+
case "vp8":
|
|
201
|
+
case "vp9":
|
|
202
|
+
return "webm";
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(`Unsupported codec: ${codec}`);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
138
207
|
var getQualityForWebRendererQuality = (quality) => {
|
|
139
208
|
switch (quality) {
|
|
140
209
|
case "very-low":
|
|
@@ -157,6 +226,20 @@ var getMimeType = (container) => {
|
|
|
157
226
|
return "video/mp4";
|
|
158
227
|
case "webm":
|
|
159
228
|
return "video/webm";
|
|
229
|
+
case "mkv":
|
|
230
|
+
return "video/x-matroska";
|
|
231
|
+
case "wav":
|
|
232
|
+
return "audio/wav";
|
|
233
|
+
case "mp3":
|
|
234
|
+
return "audio/mpeg";
|
|
235
|
+
case "aac":
|
|
236
|
+
return "audio/aac";
|
|
237
|
+
case "ogg":
|
|
238
|
+
return "audio/ogg";
|
|
239
|
+
case "flac":
|
|
240
|
+
return "audio/flac";
|
|
241
|
+
case "mov":
|
|
242
|
+
return "video/quicktime";
|
|
160
243
|
default:
|
|
161
244
|
throw new Error(`Unsupported container: ${container}`);
|
|
162
245
|
}
|
|
@@ -167,6 +250,20 @@ var getDefaultAudioCodecForContainer = (container) => {
|
|
|
167
250
|
return "aac";
|
|
168
251
|
case "webm":
|
|
169
252
|
return "opus";
|
|
253
|
+
case "mkv":
|
|
254
|
+
return "aac";
|
|
255
|
+
case "wav":
|
|
256
|
+
return "pcm-s16";
|
|
257
|
+
case "mp3":
|
|
258
|
+
return "mp3";
|
|
259
|
+
case "aac":
|
|
260
|
+
return "aac";
|
|
261
|
+
case "ogg":
|
|
262
|
+
return "opus";
|
|
263
|
+
case "flac":
|
|
264
|
+
return "flac";
|
|
265
|
+
case "mov":
|
|
266
|
+
return "aac";
|
|
170
267
|
default:
|
|
171
268
|
throw new Error(`Unsupported container: ${container}`);
|
|
172
269
|
}
|
|
@@ -179,22 +276,100 @@ var WEB_RENDERER_VIDEO_CODECS = [
|
|
|
179
276
|
"av1"
|
|
180
277
|
];
|
|
181
278
|
var getSupportedVideoCodecsForContainer = (container) => {
|
|
279
|
+
if (isAudioOnlyContainer(container)) {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
182
282
|
const format = containerToMediabunnyContainer(container);
|
|
183
283
|
const allSupported = format.getSupportedVideoCodecs();
|
|
184
284
|
return WEB_RENDERER_VIDEO_CODECS.filter((codec) => allSupported.includes(codecToMediabunnyCodec(codec)));
|
|
185
285
|
};
|
|
186
|
-
var WEB_RENDERER_AUDIO_CODECS = [
|
|
286
|
+
var WEB_RENDERER_AUDIO_CODECS = [
|
|
287
|
+
"aac",
|
|
288
|
+
"opus",
|
|
289
|
+
"mp3",
|
|
290
|
+
"vorbis",
|
|
291
|
+
"pcm-s16",
|
|
292
|
+
"flac"
|
|
293
|
+
];
|
|
294
|
+
var audioCodecToMediabunnyAudioCodec = (audioCodec) => {
|
|
295
|
+
switch (audioCodec) {
|
|
296
|
+
case "aac":
|
|
297
|
+
return "aac";
|
|
298
|
+
case "opus":
|
|
299
|
+
return "opus";
|
|
300
|
+
case "mp3":
|
|
301
|
+
return "mp3";
|
|
302
|
+
case "vorbis":
|
|
303
|
+
return "vorbis";
|
|
304
|
+
case "pcm-s16":
|
|
305
|
+
return "pcm-s16";
|
|
306
|
+
case "flac":
|
|
307
|
+
return "flac";
|
|
308
|
+
default:
|
|
309
|
+
throw new Error(`Unsupported audio codec: ${audioCodec}`);
|
|
310
|
+
}
|
|
311
|
+
};
|
|
187
312
|
var getSupportedAudioCodecsForContainer = (container) => {
|
|
188
313
|
const format = containerToMediabunnyContainer(container);
|
|
189
314
|
const allSupported = format.getSupportedAudioCodecs();
|
|
190
|
-
return WEB_RENDERER_AUDIO_CODECS.filter((codec) => allSupported.includes(codec));
|
|
191
|
-
};
|
|
192
|
-
var audioCodecToMediabunnyAudioCodec = (audioCodec) => {
|
|
193
|
-
return audioCodec;
|
|
315
|
+
return WEB_RENDERER_AUDIO_CODECS.filter((codec) => allSupported.includes(audioCodecToMediabunnyAudioCodec(codec)));
|
|
194
316
|
};
|
|
195
317
|
|
|
196
318
|
// src/resolve-audio-codec.ts
|
|
319
|
+
import { canEncodeAudio as canEncodeAudio4 } from "mediabunny";
|
|
320
|
+
|
|
321
|
+
// src/register-aac-encoder.ts
|
|
197
322
|
import { canEncodeAudio } from "mediabunny";
|
|
323
|
+
var registrationPromise = null;
|
|
324
|
+
var doRegister = async () => {
|
|
325
|
+
const nativeSupport = await canEncodeAudio("aac");
|
|
326
|
+
if (!nativeSupport) {
|
|
327
|
+
const { registerAacEncoder } = await import("@mediabunny/aac-encoder");
|
|
328
|
+
registerAacEncoder();
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
var ensureAacEncoderRegistered = () => {
|
|
332
|
+
if (!registrationPromise) {
|
|
333
|
+
registrationPromise = doRegister();
|
|
334
|
+
}
|
|
335
|
+
return registrationPromise;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// src/register-flac-encoder.ts
|
|
339
|
+
import { canEncodeAudio as canEncodeAudio2 } from "mediabunny";
|
|
340
|
+
var registrationPromise2 = null;
|
|
341
|
+
var doRegister2 = async () => {
|
|
342
|
+
const nativeSupport = await canEncodeAudio2("flac");
|
|
343
|
+
if (!nativeSupport) {
|
|
344
|
+
const { registerFlacEncoder } = await import("@mediabunny/flac-encoder");
|
|
345
|
+
registerFlacEncoder();
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var ensureFlacEncoderRegistered = () => {
|
|
349
|
+
if (!registrationPromise2) {
|
|
350
|
+
registrationPromise2 = doRegister2();
|
|
351
|
+
}
|
|
352
|
+
return registrationPromise2;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// src/register-mp3-encoder.ts
|
|
356
|
+
import { canEncodeAudio as canEncodeAudio3 } from "mediabunny";
|
|
357
|
+
var registrationPromise3 = null;
|
|
358
|
+
var doRegister3 = async () => {
|
|
359
|
+
const nativeSupport = await canEncodeAudio3("mp3");
|
|
360
|
+
if (!nativeSupport) {
|
|
361
|
+
const { registerMp3Encoder } = await import("@mediabunny/mp3-encoder");
|
|
362
|
+
registerMp3Encoder();
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
var ensureMp3EncoderRegistered = () => {
|
|
366
|
+
if (!registrationPromise3) {
|
|
367
|
+
registrationPromise3 = doRegister3();
|
|
368
|
+
}
|
|
369
|
+
return registrationPromise3;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// src/resolve-audio-codec.ts
|
|
198
373
|
var resolveAudioCodec = async (options) => {
|
|
199
374
|
const issues = [];
|
|
200
375
|
const { container, requestedCodec, userSpecifiedAudioCodec, bitrate } = options;
|
|
@@ -209,7 +384,16 @@ var resolveAudioCodec = async (options) => {
|
|
|
209
384
|
return { codec: null, issues };
|
|
210
385
|
}
|
|
211
386
|
const mediabunnyAudioCodec = audioCodecToMediabunnyAudioCodec(audioCodec);
|
|
212
|
-
|
|
387
|
+
if (audioCodec === "mp3") {
|
|
388
|
+
await ensureMp3EncoderRegistered();
|
|
389
|
+
}
|
|
390
|
+
if (audioCodec === "aac") {
|
|
391
|
+
await ensureAacEncoderRegistered();
|
|
392
|
+
}
|
|
393
|
+
if (audioCodec === "flac") {
|
|
394
|
+
await ensureFlacEncoderRegistered();
|
|
395
|
+
}
|
|
396
|
+
const canEncode = await canEncodeAudio4(mediabunnyAudioCodec, { bitrate });
|
|
213
397
|
if (canEncode) {
|
|
214
398
|
return { codec: audioCodec, issues };
|
|
215
399
|
}
|
|
@@ -223,8 +407,17 @@ var resolveAudioCodec = async (options) => {
|
|
|
223
407
|
}
|
|
224
408
|
for (const fallbackCodec of supportedAudioCodecs) {
|
|
225
409
|
if (fallbackCodec !== audioCodec) {
|
|
410
|
+
if (fallbackCodec === "mp3") {
|
|
411
|
+
await ensureMp3EncoderRegistered();
|
|
412
|
+
}
|
|
413
|
+
if (fallbackCodec === "aac") {
|
|
414
|
+
await ensureAacEncoderRegistered();
|
|
415
|
+
}
|
|
416
|
+
if (fallbackCodec === "flac") {
|
|
417
|
+
await ensureFlacEncoderRegistered();
|
|
418
|
+
}
|
|
226
419
|
const fallbackMediabunnyCodec = audioCodecToMediabunnyAudioCodec(fallbackCodec);
|
|
227
|
-
const canEncodeFallback = await
|
|
420
|
+
const canEncodeFallback = await canEncodeAudio4(fallbackMediabunnyCodec, {
|
|
228
421
|
bitrate
|
|
229
422
|
});
|
|
230
423
|
if (canEncodeFallback) {
|
|
@@ -263,46 +456,61 @@ var validateDimensions = (options) => {
|
|
|
263
456
|
// src/can-render-media-on-web.ts
|
|
264
457
|
var canRenderMediaOnWeb = async (options) => {
|
|
265
458
|
const issues = [];
|
|
266
|
-
if (typeof VideoEncoder === "undefined") {
|
|
267
|
-
issues.push({
|
|
268
|
-
type: "webcodecs-unavailable",
|
|
269
|
-
message: "WebCodecs API is not available in this browser. A modern browser with WebCodecs support is required.",
|
|
270
|
-
severity: "error"
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
459
|
const container = options.container ?? "mp4";
|
|
274
|
-
const videoCodec = options.videoCodec ?? getDefaultVideoCodecForContainer(container);
|
|
460
|
+
const videoCodec = options.videoCodec ?? getDefaultVideoCodecForContainer(container) ?? null;
|
|
461
|
+
const videoEnabled = !isAudioOnlyContainer(container);
|
|
275
462
|
const transparent = options.transparent ?? false;
|
|
276
463
|
const muted = options.muted ?? false;
|
|
277
464
|
const { width, height } = options;
|
|
278
465
|
const resolvedVideoBitrate = typeof options.videoBitrate === "number" ? options.videoBitrate : getQualityForWebRendererQuality(options.videoBitrate ?? "medium");
|
|
279
466
|
const resolvedAudioBitrate = typeof options.audioBitrate === "number" ? options.audioBitrate : getQualityForWebRendererQuality(options.audioBitrate ?? "medium");
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
467
|
+
if (videoEnabled) {
|
|
468
|
+
if (typeof VideoEncoder === "undefined") {
|
|
469
|
+
issues.push({
|
|
470
|
+
type: "webcodecs-unavailable",
|
|
471
|
+
message: "WebCodecs API is not available in this browser. A modern browser with WebCodecs support is required.",
|
|
472
|
+
severity: "error"
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
if (!videoCodec) {
|
|
476
|
+
issues.push({
|
|
477
|
+
type: "container-codec-mismatch",
|
|
478
|
+
message: `A video codec is required for container ${container}`,
|
|
479
|
+
severity: "error"
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
const format = containerToMediabunnyContainer(container);
|
|
483
|
+
if (!format.getSupportedCodecs().includes(codecToMediabunnyCodec(videoCodec))) {
|
|
484
|
+
issues.push({
|
|
485
|
+
type: "container-codec-mismatch",
|
|
486
|
+
message: `Codec ${videoCodec} is not supported for container ${container}`,
|
|
487
|
+
severity: "error"
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
const dimensionIssue = validateDimensions({
|
|
491
|
+
width,
|
|
492
|
+
height,
|
|
493
|
+
codec: videoCodec
|
|
494
|
+
});
|
|
495
|
+
if (dimensionIssue) {
|
|
496
|
+
issues.push(dimensionIssue);
|
|
497
|
+
}
|
|
498
|
+
const canEncodeVideoResult = await canEncodeVideo(codecToMediabunnyCodec(videoCodec), { bitrate: resolvedVideoBitrate });
|
|
499
|
+
if (!canEncodeVideoResult) {
|
|
500
|
+
issues.push({
|
|
501
|
+
type: "video-codec-unsupported",
|
|
502
|
+
message: `Video codec "${videoCodec}" cannot be encoded by this browser`,
|
|
503
|
+
severity: "error"
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
if (transparent && !["vp8", "vp9"].includes(videoCodec)) {
|
|
507
|
+
issues.push({
|
|
508
|
+
type: "transparent-video-unsupported",
|
|
509
|
+
message: `Transparent video requires VP8 or VP9 codec with WebM container. ${videoCodec} does not support alpha channel.`,
|
|
510
|
+
severity: "error"
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
}
|
|
306
514
|
}
|
|
307
515
|
let resolvedAudioCodec = null;
|
|
308
516
|
if (!muted) {
|
|
@@ -338,7 +546,7 @@ var canRenderMediaOnWeb = async (options) => {
|
|
|
338
546
|
return {
|
|
339
547
|
canRender: issues.filter((i) => i.severity === "error").length === 0,
|
|
340
548
|
issues,
|
|
341
|
-
resolvedVideoCodec: videoCodec,
|
|
549
|
+
resolvedVideoCodec: videoEnabled ? videoCodec : null,
|
|
342
550
|
resolvedAudioCodec,
|
|
343
551
|
resolvedOutputTarget
|
|
344
552
|
};
|
|
@@ -359,6 +567,15 @@ var getEncodableVideoCodecs = async (container, options) => {
|
|
|
359
567
|
};
|
|
360
568
|
var getEncodableAudioCodecs = async (container, options) => {
|
|
361
569
|
const supported = getSupportedAudioCodecsForContainer(container);
|
|
570
|
+
if (supported.includes("mp3")) {
|
|
571
|
+
await ensureMp3EncoderRegistered();
|
|
572
|
+
}
|
|
573
|
+
if (supported.includes("aac")) {
|
|
574
|
+
await ensureAacEncoderRegistered();
|
|
575
|
+
}
|
|
576
|
+
if (supported.includes("flac")) {
|
|
577
|
+
await ensureFlacEncoderRegistered();
|
|
578
|
+
}
|
|
362
579
|
const resolvedBitrate = options?.audioBitrate ? typeof options.audioBitrate === "number" ? options.audioBitrate : getQualityForWebRendererQuality(options.audioBitrate) : undefined;
|
|
363
580
|
const encodable = await mediabunnyGetEncodableAudioCodecs(supported, {
|
|
364
581
|
bitrate: resolvedBitrate
|
|
@@ -629,6 +846,7 @@ var UpdateTime = ({
|
|
|
629
846
|
}
|
|
630
847
|
}));
|
|
631
848
|
return /* @__PURE__ */ jsx(Internals2.RemotionRootContexts, {
|
|
849
|
+
visualModeEnabled: false,
|
|
632
850
|
audioEnabled,
|
|
633
851
|
videoEnabled,
|
|
634
852
|
logLevel,
|
|
@@ -637,13 +855,73 @@ var UpdateTime = ({
|
|
|
637
855
|
frameState: {
|
|
638
856
|
[compId]: frame
|
|
639
857
|
},
|
|
640
|
-
nonceContextSeed: 0,
|
|
641
858
|
children
|
|
642
859
|
});
|
|
643
860
|
};
|
|
644
861
|
|
|
645
862
|
// src/create-scaffold.tsx
|
|
646
863
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
864
|
+
var GENERIC_REACT_RENDER_ERROR_MESSAGES = new Set([
|
|
865
|
+
"Error thrown during rendering"
|
|
866
|
+
]);
|
|
867
|
+
var isMessageLikeObject = (err) => {
|
|
868
|
+
return typeof err === "object" && err !== null && "message" in err && typeof err.message === "string";
|
|
869
|
+
};
|
|
870
|
+
var unknownErrorToMessage = (err) => {
|
|
871
|
+
if (typeof err === "string") {
|
|
872
|
+
return err;
|
|
873
|
+
}
|
|
874
|
+
if (isMessageLikeObject(err)) {
|
|
875
|
+
return err.message;
|
|
876
|
+
}
|
|
877
|
+
try {
|
|
878
|
+
const serialized = JSON.stringify(err);
|
|
879
|
+
if (serialized) {
|
|
880
|
+
return serialized;
|
|
881
|
+
}
|
|
882
|
+
} catch {}
|
|
883
|
+
return String(err);
|
|
884
|
+
};
|
|
885
|
+
var setErrorCause = (error, cause) => {
|
|
886
|
+
try {
|
|
887
|
+
Object.defineProperty(error, "cause", {
|
|
888
|
+
value: cause,
|
|
889
|
+
enumerable: false,
|
|
890
|
+
configurable: true,
|
|
891
|
+
writable: true
|
|
892
|
+
});
|
|
893
|
+
} catch {}
|
|
894
|
+
};
|
|
895
|
+
var appendComponentStack = (error, componentStack) => {
|
|
896
|
+
if (!componentStack?.trim()) {
|
|
897
|
+
return error;
|
|
898
|
+
}
|
|
899
|
+
const normalizedComponentStack = componentStack.trim();
|
|
900
|
+
const stack = error.stack ?? `${error.name}: ${error.message}`;
|
|
901
|
+
if (stack.includes(normalizedComponentStack)) {
|
|
902
|
+
return error;
|
|
903
|
+
}
|
|
904
|
+
const errorTitle = `${error.name}: ${error.message}`;
|
|
905
|
+
const stackWithoutTitle = stack.startsWith(errorTitle) ? stack.slice(errorTitle.length).trimStart() : stack;
|
|
906
|
+
const stackBody = stackWithoutTitle.length > 0 ? `
|
|
907
|
+
${stackWithoutTitle}` : "";
|
|
908
|
+
error.stack = `${errorTitle}
|
|
909
|
+
For the likely root cause, see "React component stack:" after the JavaScript stack trace below.${stackBody}
|
|
910
|
+
React component stack:
|
|
911
|
+
${normalizedComponentStack}`;
|
|
912
|
+
return error;
|
|
913
|
+
};
|
|
914
|
+
var normalizeUncaughtReactError = (err, componentStack) => {
|
|
915
|
+
if (err instanceof Error) {
|
|
916
|
+
const { cause } = err;
|
|
917
|
+
const shouldUnwrapCause = cause instanceof Error && GENERIC_REACT_RENDER_ERROR_MESSAGES.has(err.message);
|
|
918
|
+
const errorToThrow = shouldUnwrapCause ? cause : err;
|
|
919
|
+
return appendComponentStack(errorToThrow, componentStack);
|
|
920
|
+
}
|
|
921
|
+
const normalized = new Error(unknownErrorToMessage(err));
|
|
922
|
+
setErrorCause(normalized, err);
|
|
923
|
+
return appendComponentStack(normalized, componentStack);
|
|
924
|
+
};
|
|
647
925
|
function checkForError(errorHolder) {
|
|
648
926
|
if (errorHolder.error) {
|
|
649
927
|
throw errorHolder.error;
|
|
@@ -670,28 +948,31 @@ function createScaffold({
|
|
|
670
948
|
if (!ReactDOM.createRoot) {
|
|
671
949
|
throw new Error("@remotion/web-renderer requires React 18 or higher");
|
|
672
950
|
}
|
|
951
|
+
const wrapper = document.createElement("div");
|
|
952
|
+
wrapper.style.position = "fixed";
|
|
953
|
+
wrapper.style.inset = "0";
|
|
954
|
+
wrapper.style.overflow = "hidden";
|
|
955
|
+
wrapper.style.visibility = "hidden";
|
|
956
|
+
wrapper.style.pointerEvents = "none";
|
|
957
|
+
wrapper.style.zIndex = "-9999";
|
|
673
958
|
const div = document.createElement("div");
|
|
674
|
-
div.style.position = "
|
|
959
|
+
div.style.position = "absolute";
|
|
960
|
+
div.style.top = "0";
|
|
961
|
+
div.style.left = "0";
|
|
675
962
|
div.style.display = "flex";
|
|
676
963
|
div.style.flexDirection = "column";
|
|
677
964
|
div.style.backgroundColor = "transparent";
|
|
678
965
|
div.style.width = `${width}px`;
|
|
679
966
|
div.style.height = `${height}px`;
|
|
680
|
-
div.style.zIndex = "-9999";
|
|
681
|
-
div.style.top = "0";
|
|
682
|
-
div.style.left = "0";
|
|
683
|
-
div.style.right = "0";
|
|
684
|
-
div.style.bottom = "0";
|
|
685
|
-
div.style.visibility = "hidden";
|
|
686
|
-
div.style.pointerEvents = "none";
|
|
687
967
|
const scaffoldClassName = `remotion-scaffold-${Math.random().toString(36).substring(2, 15)}`;
|
|
688
968
|
div.className = scaffoldClassName;
|
|
689
969
|
const cleanupCSS = Internals3.CSSUtils.injectCSS(Internals3.CSSUtils.makeDefaultPreviewCSS(`.${scaffoldClassName}`, "white"));
|
|
690
|
-
|
|
970
|
+
wrapper.appendChild(div);
|
|
971
|
+
document.body.appendChild(wrapper);
|
|
691
972
|
const errorHolder = { error: null };
|
|
692
973
|
const root = ReactDOM.createRoot(div, {
|
|
693
|
-
onUncaughtError: (err) => {
|
|
694
|
-
errorHolder.error = err
|
|
974
|
+
onUncaughtError: (err, errorInfo) => {
|
|
975
|
+
errorHolder.error = normalizeUncaughtReactError(err, errorInfo?.componentStack);
|
|
695
976
|
}
|
|
696
977
|
});
|
|
697
978
|
const delayRenderScope = {
|
|
@@ -722,7 +1003,7 @@ function createScaffold({
|
|
|
722
1003
|
{
|
|
723
1004
|
id,
|
|
724
1005
|
component: Component,
|
|
725
|
-
nonce: 0,
|
|
1006
|
+
nonce: [[0, 0]],
|
|
726
1007
|
defaultProps: {},
|
|
727
1008
|
folderName: null,
|
|
728
1009
|
parentFolderName: null,
|
|
@@ -781,6 +1062,7 @@ function createScaffold({
|
|
|
781
1062
|
[Symbol.dispose]: () => {
|
|
782
1063
|
root.unmount();
|
|
783
1064
|
div.remove();
|
|
1065
|
+
wrapper.remove();
|
|
784
1066
|
cleanupCSS();
|
|
785
1067
|
},
|
|
786
1068
|
timeUpdater,
|
|
@@ -3815,7 +4097,8 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3815
4097
|
await cleanupStaleOpfsFiles();
|
|
3816
4098
|
}
|
|
3817
4099
|
const format = containerToMediabunnyContainer(container);
|
|
3818
|
-
|
|
4100
|
+
const videoEnabled = !isAudioOnlyContainer(container);
|
|
4101
|
+
if (videoEnabled && codec && !format.getSupportedCodecs().includes(codecToMediabunnyCodec(codec))) {
|
|
3819
4102
|
return Promise.reject(new Error(`Codec ${codec} is not supported for container ${container}`));
|
|
3820
4103
|
}
|
|
3821
4104
|
const resolvedAudioBitrate = typeof audioBitrate === "number" ? audioBitrate : getQualityForWebRendererQuality(audioBitrate);
|
|
@@ -3863,7 +4146,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3863
4146
|
mediaCacheSizeInBytes,
|
|
3864
4147
|
schema: schema ?? null,
|
|
3865
4148
|
audioEnabled: !muted,
|
|
3866
|
-
videoEnabled
|
|
4149
|
+
videoEnabled,
|
|
3867
4150
|
initialFrame: 0,
|
|
3868
4151
|
defaultCodec: resolved.defaultCodec,
|
|
3869
4152
|
defaultOutName: resolved.defaultOutName
|
|
@@ -3904,7 +4187,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3904
4187
|
if (signal?.aborted) {
|
|
3905
4188
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
3906
4189
|
}
|
|
3907
|
-
const videoSampleSource = __using(__stack, makeVideoSampleSourceCleanup({
|
|
4190
|
+
const videoSampleSource = __using(__stack, videoEnabled && codec ? makeVideoSampleSourceCleanup({
|
|
3908
4191
|
codec: codecToMediabunnyCodec(codec),
|
|
3909
4192
|
bitrate: typeof videoBitrate === "number" ? videoBitrate : getQualityForWebRendererQuality(videoBitrate),
|
|
3910
4193
|
sizeChangeBehavior: "deny",
|
|
@@ -3912,15 +4195,23 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3912
4195
|
latencyMode: "quality",
|
|
3913
4196
|
keyFrameInterval: keyframeIntervalInSeconds,
|
|
3914
4197
|
alpha: transparent ? "keep" : "discard"
|
|
3915
|
-
}), 0);
|
|
3916
|
-
|
|
4198
|
+
}) : null, 0);
|
|
4199
|
+
const totalFrames = realFrameRange[1] - realFrameRange[0] + 1;
|
|
4200
|
+
const durationInSeconds = totalFrames / resolved.fps;
|
|
4201
|
+
if (videoSampleSource) {
|
|
4202
|
+
outputWithCleanup.output.addVideoTrack(videoSampleSource.videoSampleSource, {
|
|
4203
|
+
maximumPacketCount: Math.ceil(totalFrames * 1.33)
|
|
4204
|
+
});
|
|
4205
|
+
}
|
|
3917
4206
|
const audioSampleSource = __using(__stack, createAudioSampleSource({
|
|
3918
4207
|
muted,
|
|
3919
4208
|
codec: finalAudioCodec ? audioCodecToMediabunnyAudioCodec(finalAudioCodec) : null,
|
|
3920
4209
|
bitrate: resolvedAudioBitrate
|
|
3921
4210
|
}), 0);
|
|
3922
4211
|
if (audioSampleSource) {
|
|
3923
|
-
outputWithCleanup.output.addAudioTrack(audioSampleSource.audioSampleSource
|
|
4212
|
+
outputWithCleanup.output.addAudioTrack(audioSampleSource.audioSampleSource, {
|
|
4213
|
+
maximumPacketCount: Math.ceil(durationInSeconds * 100 * 1.33)
|
|
4214
|
+
});
|
|
3924
4215
|
}
|
|
3925
4216
|
await outputWithCleanup.output.start();
|
|
3926
4217
|
if (signal?.aborted) {
|
|
@@ -3947,44 +4238,49 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3947
4238
|
if (signal?.aborted) {
|
|
3948
4239
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
3949
4240
|
}
|
|
3950
|
-
const createFrameStart = performance.now();
|
|
3951
|
-
const layer = await createLayer({
|
|
3952
|
-
element: div,
|
|
3953
|
-
scale,
|
|
3954
|
-
logLevel,
|
|
3955
|
-
internalState,
|
|
3956
|
-
onlyBackgroundClipText: false,
|
|
3957
|
-
cutout: new DOMRect(0, 0, resolved.width, resolved.height)
|
|
3958
|
-
});
|
|
3959
|
-
internalState.addCreateFrameTime(performance.now() - createFrameStart);
|
|
3960
|
-
if (signal?.aborted) {
|
|
3961
|
-
throw new Error("renderMediaOnWeb() was cancelled");
|
|
3962
|
-
}
|
|
3963
4241
|
const timestamp = Math.round((frame - realFrameRange[0]) / resolved.fps * 1e6);
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
4242
|
+
let frameToEncode = null;
|
|
4243
|
+
let layerCanvas = null;
|
|
4244
|
+
if (videoEnabled) {
|
|
4245
|
+
const createFrameStart = performance.now();
|
|
4246
|
+
const layer = await createLayer({
|
|
4247
|
+
element: div,
|
|
4248
|
+
scale,
|
|
4249
|
+
logLevel,
|
|
4250
|
+
internalState,
|
|
4251
|
+
onlyBackgroundClipText: false,
|
|
4252
|
+
cutout: new DOMRect(0, 0, resolved.width, resolved.height)
|
|
4253
|
+
});
|
|
4254
|
+
internalState.addCreateFrameTime(performance.now() - createFrameStart);
|
|
4255
|
+
layerCanvas = layer.canvas;
|
|
3972
4256
|
if (signal?.aborted) {
|
|
3973
4257
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
3974
4258
|
}
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
returnedFrame,
|
|
3978
|
-
expectedWidth: Math.round(resolved.width * scale),
|
|
3979
|
-
expectedHeight: Math.round(resolved.height * scale),
|
|
3980
|
-
expectedTimestamp: timestamp
|
|
4259
|
+
const videoFrame = new VideoFrame(layer.canvas, {
|
|
4260
|
+
timestamp
|
|
3981
4261
|
});
|
|
4262
|
+
frameToEncode = videoFrame;
|
|
4263
|
+
if (onFrame) {
|
|
4264
|
+
const returnedFrame = await onFrame(videoFrame);
|
|
4265
|
+
if (signal?.aborted) {
|
|
4266
|
+
throw new Error("renderMediaOnWeb() was cancelled");
|
|
4267
|
+
}
|
|
4268
|
+
frameToEncode = validateVideoFrame({
|
|
4269
|
+
originalFrame: videoFrame,
|
|
4270
|
+
returnedFrame,
|
|
4271
|
+
expectedWidth: Math.round(resolved.width * scale),
|
|
4272
|
+
expectedHeight: Math.round(resolved.height * scale),
|
|
4273
|
+
expectedTimestamp: timestamp
|
|
4274
|
+
});
|
|
4275
|
+
}
|
|
3982
4276
|
}
|
|
4277
|
+
progress.renderedFrames++;
|
|
4278
|
+
throttledOnProgress?.({ ...progress });
|
|
3983
4279
|
const audioCombineStart = performance.now();
|
|
3984
4280
|
const assets = collectAssets.current.collectAssets();
|
|
3985
4281
|
if (onArtifact) {
|
|
3986
4282
|
await artifactsHandler.handle({
|
|
3987
|
-
imageData:
|
|
4283
|
+
imageData: layerCanvas,
|
|
3988
4284
|
frame,
|
|
3989
4285
|
assets,
|
|
3990
4286
|
onArtifact
|
|
@@ -3996,10 +4292,14 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3996
4292
|
const audio = muted ? null : onlyInlineAudio({ assets, fps: resolved.fps, timestamp });
|
|
3997
4293
|
internalState.addAudioMixingTime(performance.now() - audioCombineStart);
|
|
3998
4294
|
const addSampleStart = performance.now();
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4295
|
+
const encodingPromises = [];
|
|
4296
|
+
if (frameToEncode && videoSampleSource) {
|
|
4297
|
+
encodingPromises.push(addVideoSampleAndCloseFrame(frameToEncode, videoSampleSource.videoSampleSource));
|
|
4298
|
+
}
|
|
4299
|
+
if (audio && audioSampleSource) {
|
|
4300
|
+
encodingPromises.push(addAudioSample(audio, audioSampleSource.audioSampleSource));
|
|
4301
|
+
}
|
|
4302
|
+
await Promise.all(encodingPromises);
|
|
4003
4303
|
internalState.addAddSampleTime(performance.now() - addSampleStart);
|
|
4004
4304
|
progress.encodedFrames++;
|
|
4005
4305
|
throttledOnProgress?.({ ...progress });
|
|
@@ -4008,7 +4308,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4008
4308
|
}
|
|
4009
4309
|
}
|
|
4010
4310
|
onProgress?.({ ...progress });
|
|
4011
|
-
videoSampleSource
|
|
4311
|
+
videoSampleSource?.videoSampleSource.close();
|
|
4012
4312
|
audioSampleSource?.audioSampleSource.close();
|
|
4013
4313
|
await outputWithCleanup.output.finalize();
|
|
4014
4314
|
Internals8.Log.verbose({ logLevel, tag: "web-renderer" }, `Render timings: waitForReady=${internalState.getWaitForReadyTime().toFixed(2)}ms, createFrame=${internalState.getCreateFrameTime().toFixed(2)}ms, addSample=${internalState.getAddSampleTime().toFixed(2)}ms, audioMixing=${internalState.getAudioMixingTime().toFixed(2)}ms`);
|
|
@@ -4022,8 +4322,9 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4022
4322
|
});
|
|
4023
4323
|
await webFsTarget.close();
|
|
4024
4324
|
return {
|
|
4025
|
-
getBlob: () => {
|
|
4026
|
-
|
|
4325
|
+
getBlob: async () => {
|
|
4326
|
+
const file = await webFsTarget.getBlob();
|
|
4327
|
+
return new Blob([file], { type: getMimeType(container) });
|
|
4027
4328
|
},
|
|
4028
4329
|
internalState
|
|
4029
4330
|
};
|
|
@@ -4074,7 +4375,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4074
4375
|
};
|
|
4075
4376
|
var renderMediaOnWeb = (options) => {
|
|
4076
4377
|
const container = options.container ?? "mp4";
|
|
4077
|
-
const codec = options.videoCodec ?? getDefaultVideoCodecForContainer(container);
|
|
4378
|
+
const codec = options.videoCodec ?? getDefaultVideoCodecForContainer(container) ?? null;
|
|
4078
4379
|
onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref.catch(() => Promise.resolve()).then(() => internalRenderMediaOnWeb({
|
|
4079
4380
|
...options,
|
|
4080
4381
|
delayRenderTimeoutInMilliseconds: options.delayRenderTimeoutInMilliseconds ?? 30000,
|
|
@@ -4236,11 +4537,13 @@ var renderStillOnWeb = (options) => {
|
|
|
4236
4537
|
export {
|
|
4237
4538
|
renderStillOnWeb,
|
|
4238
4539
|
renderMediaOnWeb,
|
|
4540
|
+
isAudioOnlyContainer,
|
|
4239
4541
|
getSupportedVideoCodecsForContainer,
|
|
4240
4542
|
getSupportedAudioCodecsForContainer,
|
|
4241
4543
|
getEncodableVideoCodecs,
|
|
4242
4544
|
getEncodableAudioCodecs,
|
|
4243
4545
|
getDefaultVideoCodecForContainer,
|
|
4546
|
+
getDefaultContainerForCodec,
|
|
4244
4547
|
getDefaultAudioCodecForContainer,
|
|
4245
4548
|
canRenderMediaOnWeb
|
|
4246
4549
|
};
|