@remotion/web-renderer 4.0.401 → 4.0.403
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-media-on-web.d.ts +3 -0
- package/dist/can-render-types.d.ts +27 -0
- package/dist/check-webgl-support.d.ts +2 -0
- package/dist/create-audio-sample-source.d.ts +9 -0
- package/dist/esm/index.mjs +375 -140
- package/dist/get-encodable-codecs.d.ts +9 -0
- package/dist/index.d.ts +5 -1
- package/dist/mediabunny-mappings.d.ts +5 -0
- package/dist/render-media-on-web.d.ts +3 -1
- package/dist/renoun.d.ts +119 -0
- package/dist/resolve-audio-codec.d.ts +13 -0
- package/dist/validate-dimensions.d.ts +7 -0
- package/package.json +6 -6
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CanRenderMediaOnWebOptions, CanRenderMediaOnWebResult } from './can-render-types';
|
|
2
|
+
export type { CanRenderIssue, CanRenderMediaOnWebOptions, CanRenderMediaOnWebResult, } from './can-render-types';
|
|
3
|
+
export declare const canRenderMediaOnWeb: (options: CanRenderMediaOnWebOptions) => Promise<CanRenderMediaOnWebResult>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { WebRendererAudioCodec, WebRendererContainer, WebRendererQuality, WebRendererVideoCodec } from './mediabunny-mappings';
|
|
2
|
+
import type { WebRendererOutputTarget } from './output-target';
|
|
3
|
+
export type CanRenderIssueType = 'video-codec-unsupported' | 'audio-codec-unsupported' | 'webgl-unsupported' | 'webcodecs-unavailable' | 'container-codec-mismatch' | 'transparent-video-unsupported' | 'invalid-dimensions' | 'output-target-unsupported';
|
|
4
|
+
export type CanRenderIssue = {
|
|
5
|
+
type: CanRenderIssueType;
|
|
6
|
+
message: string;
|
|
7
|
+
severity: 'error' | 'warning';
|
|
8
|
+
};
|
|
9
|
+
export type CanRenderMediaOnWebResult = {
|
|
10
|
+
canRender: boolean;
|
|
11
|
+
issues: CanRenderIssue[];
|
|
12
|
+
resolvedVideoCodec: WebRendererVideoCodec;
|
|
13
|
+
resolvedAudioCodec: WebRendererAudioCodec | null;
|
|
14
|
+
resolvedOutputTarget: WebRendererOutputTarget;
|
|
15
|
+
};
|
|
16
|
+
export type CanRenderMediaOnWebOptions = {
|
|
17
|
+
container?: WebRendererContainer;
|
|
18
|
+
videoCodec?: WebRendererVideoCodec;
|
|
19
|
+
audioCodec?: WebRendererAudioCodec | null;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
transparent?: boolean;
|
|
23
|
+
muted?: boolean;
|
|
24
|
+
videoBitrate?: number | WebRendererQuality;
|
|
25
|
+
audioBitrate?: number | WebRendererQuality;
|
|
26
|
+
outputTarget?: WebRendererOutputTarget | null;
|
|
27
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AudioSampleSource, type Quality } from 'mediabunny';
|
|
2
|
+
export declare const createAudioSampleSource: ({ muted, codec, bitrate, }: {
|
|
3
|
+
muted: boolean;
|
|
4
|
+
codec: "aac" | "alaw" | "flac" | "mp3" | "opus" | "pcm-f32" | "pcm-f32be" | "pcm-f64" | "pcm-f64be" | "pcm-s16" | "pcm-s16be" | "pcm-s24" | "pcm-s24be" | "pcm-s32" | "pcm-s32be" | "pcm-s8" | "pcm-u8" | "ulaw" | "vorbis" | null;
|
|
5
|
+
bitrate: number | Quality;
|
|
6
|
+
}) => {
|
|
7
|
+
audioSampleSource: AudioSampleSource;
|
|
8
|
+
[Symbol.dispose]: () => void;
|
|
9
|
+
} | null;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -36,6 +36,327 @@ var __callDispose = (stack, error, hasError) => {
|
|
|
36
36
|
return next();
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
// src/can-render-media-on-web.ts
|
|
40
|
+
import { canEncodeVideo } from "mediabunny";
|
|
41
|
+
|
|
42
|
+
// src/can-use-webfs-target.ts
|
|
43
|
+
var canUseWebFsWriter = async () => {
|
|
44
|
+
if (!("storage" in navigator)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (!("getDirectory" in navigator.storage)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const directoryHandle = await navigator.storage.getDirectory();
|
|
52
|
+
const fileHandle = await directoryHandle.getFileHandle("remotion-probe-web-fs-support", {
|
|
53
|
+
create: true
|
|
54
|
+
});
|
|
55
|
+
const canUse = fileHandle.createWritable !== undefined;
|
|
56
|
+
return canUse;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/check-webgl-support.ts
|
|
63
|
+
var checkWebGLSupport = () => {
|
|
64
|
+
try {
|
|
65
|
+
const canvas = new OffscreenCanvas(1, 1);
|
|
66
|
+
const gl = canvas.getContext("webgl2") || canvas.getContext("webgl");
|
|
67
|
+
if (!gl) {
|
|
68
|
+
return {
|
|
69
|
+
type: "webgl-unsupported",
|
|
70
|
+
message: "WebGL is not supported. 3D CSS transforms will fail.",
|
|
71
|
+
severity: "error"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
} catch {
|
|
76
|
+
return {
|
|
77
|
+
type: "webgl-unsupported",
|
|
78
|
+
message: "WebGL is not supported. 3D CSS transforms will fail.",
|
|
79
|
+
severity: "error"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// src/mediabunny-mappings.ts
|
|
85
|
+
import {
|
|
86
|
+
Mp4OutputFormat,
|
|
87
|
+
QUALITY_HIGH,
|
|
88
|
+
QUALITY_LOW,
|
|
89
|
+
QUALITY_MEDIUM,
|
|
90
|
+
QUALITY_VERY_HIGH,
|
|
91
|
+
QUALITY_VERY_LOW,
|
|
92
|
+
WebMOutputFormat
|
|
93
|
+
} from "mediabunny";
|
|
94
|
+
var codecToMediabunnyCodec = (codec) => {
|
|
95
|
+
switch (codec) {
|
|
96
|
+
case "h264":
|
|
97
|
+
return "avc";
|
|
98
|
+
case "h265":
|
|
99
|
+
return "hevc";
|
|
100
|
+
case "vp8":
|
|
101
|
+
return "vp8";
|
|
102
|
+
case "vp9":
|
|
103
|
+
return "vp9";
|
|
104
|
+
case "av1":
|
|
105
|
+
return "av1";
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported codec: ${codec}`);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var containerToMediabunnyContainer = (container) => {
|
|
111
|
+
switch (container) {
|
|
112
|
+
case "mp4":
|
|
113
|
+
return new Mp4OutputFormat;
|
|
114
|
+
case "webm":
|
|
115
|
+
return new WebMOutputFormat;
|
|
116
|
+
default:
|
|
117
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var getDefaultVideoCodecForContainer = (container) => {
|
|
121
|
+
switch (container) {
|
|
122
|
+
case "mp4":
|
|
123
|
+
return "h264";
|
|
124
|
+
case "webm":
|
|
125
|
+
return "vp8";
|
|
126
|
+
default:
|
|
127
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
var getQualityForWebRendererQuality = (quality) => {
|
|
131
|
+
switch (quality) {
|
|
132
|
+
case "very-low":
|
|
133
|
+
return QUALITY_VERY_LOW;
|
|
134
|
+
case "low":
|
|
135
|
+
return QUALITY_LOW;
|
|
136
|
+
case "medium":
|
|
137
|
+
return QUALITY_MEDIUM;
|
|
138
|
+
case "high":
|
|
139
|
+
return QUALITY_HIGH;
|
|
140
|
+
case "very-high":
|
|
141
|
+
return QUALITY_VERY_HIGH;
|
|
142
|
+
default:
|
|
143
|
+
throw new Error(`Unsupported quality: ${quality}`);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var getMimeType = (container) => {
|
|
147
|
+
switch (container) {
|
|
148
|
+
case "mp4":
|
|
149
|
+
return "video/mp4";
|
|
150
|
+
case "webm":
|
|
151
|
+
return "video/webm";
|
|
152
|
+
default:
|
|
153
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var getDefaultAudioCodecForContainer = (container) => {
|
|
157
|
+
switch (container) {
|
|
158
|
+
case "mp4":
|
|
159
|
+
return "aac";
|
|
160
|
+
case "webm":
|
|
161
|
+
return "opus";
|
|
162
|
+
default:
|
|
163
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var WEB_RENDERER_VIDEO_CODECS = [
|
|
167
|
+
"h264",
|
|
168
|
+
"h265",
|
|
169
|
+
"vp8",
|
|
170
|
+
"vp9",
|
|
171
|
+
"av1"
|
|
172
|
+
];
|
|
173
|
+
var getSupportedVideoCodecsForContainer = (container) => {
|
|
174
|
+
const format = containerToMediabunnyContainer(container);
|
|
175
|
+
const allSupported = format.getSupportedVideoCodecs();
|
|
176
|
+
return WEB_RENDERER_VIDEO_CODECS.filter((codec) => allSupported.includes(codecToMediabunnyCodec(codec)));
|
|
177
|
+
};
|
|
178
|
+
var WEB_RENDERER_AUDIO_CODECS = ["aac", "opus"];
|
|
179
|
+
var getSupportedAudioCodecsForContainer = (container) => {
|
|
180
|
+
const format = containerToMediabunnyContainer(container);
|
|
181
|
+
const allSupported = format.getSupportedAudioCodecs();
|
|
182
|
+
return WEB_RENDERER_AUDIO_CODECS.filter((codec) => allSupported.includes(codec));
|
|
183
|
+
};
|
|
184
|
+
var audioCodecToMediabunnyAudioCodec = (audioCodec) => {
|
|
185
|
+
return audioCodec;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// src/resolve-audio-codec.ts
|
|
189
|
+
import { canEncodeAudio } from "mediabunny";
|
|
190
|
+
var resolveAudioCodec = async (options) => {
|
|
191
|
+
const issues = [];
|
|
192
|
+
const { container, requestedCodec, userSpecifiedAudioCodec, bitrate } = options;
|
|
193
|
+
const audioCodec = requestedCodec ?? getDefaultAudioCodecForContainer(container);
|
|
194
|
+
const supportedAudioCodecs = getSupportedAudioCodecsForContainer(container);
|
|
195
|
+
if (!supportedAudioCodecs.includes(audioCodec)) {
|
|
196
|
+
issues.push({
|
|
197
|
+
type: "audio-codec-unsupported",
|
|
198
|
+
message: `Audio codec "${audioCodec}" is not supported for container "${container}". Supported: ${supportedAudioCodecs.join(", ")}`,
|
|
199
|
+
severity: "error"
|
|
200
|
+
});
|
|
201
|
+
return { codec: null, issues };
|
|
202
|
+
}
|
|
203
|
+
const mediabunnyAudioCodec = audioCodecToMediabunnyAudioCodec(audioCodec);
|
|
204
|
+
const canEncode = await canEncodeAudio(mediabunnyAudioCodec, { bitrate });
|
|
205
|
+
if (canEncode) {
|
|
206
|
+
return { codec: audioCodec, issues };
|
|
207
|
+
}
|
|
208
|
+
if (userSpecifiedAudioCodec) {
|
|
209
|
+
issues.push({
|
|
210
|
+
type: "audio-codec-unsupported",
|
|
211
|
+
message: `Audio codec "${audioCodec}" cannot be encoded by this browser. This is common for AAC on Firefox. Try using "opus" instead.`,
|
|
212
|
+
severity: "error"
|
|
213
|
+
});
|
|
214
|
+
return { codec: null, issues };
|
|
215
|
+
}
|
|
216
|
+
for (const fallbackCodec of supportedAudioCodecs) {
|
|
217
|
+
if (fallbackCodec !== audioCodec) {
|
|
218
|
+
const fallbackMediabunnyCodec = audioCodecToMediabunnyAudioCodec(fallbackCodec);
|
|
219
|
+
const canEncodeFallback = await canEncodeAudio(fallbackMediabunnyCodec, {
|
|
220
|
+
bitrate
|
|
221
|
+
});
|
|
222
|
+
if (canEncodeFallback) {
|
|
223
|
+
issues.push({
|
|
224
|
+
type: "audio-codec-unsupported",
|
|
225
|
+
message: `Falling back from audio codec "${audioCodec}" to "${fallbackCodec}" because the original codec cannot be encoded by this browser.`,
|
|
226
|
+
severity: "warning"
|
|
227
|
+
});
|
|
228
|
+
return { codec: fallbackCodec, issues };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
issues.push({
|
|
233
|
+
type: "audio-codec-unsupported",
|
|
234
|
+
message: `No audio codec can be encoded by this browser for container "${container}".`,
|
|
235
|
+
severity: "error"
|
|
236
|
+
});
|
|
237
|
+
return { codec: null, issues };
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/validate-dimensions.ts
|
|
241
|
+
var validateDimensions = (options) => {
|
|
242
|
+
const { width, height, codec } = options;
|
|
243
|
+
if (codec === "h264" || codec === "h265") {
|
|
244
|
+
if (width % 2 !== 0 || height % 2 !== 0) {
|
|
245
|
+
return {
|
|
246
|
+
type: "invalid-dimensions",
|
|
247
|
+
message: `${codec.toUpperCase()} codec requires width and height to be multiples of 2. Got ${width}x${height}`,
|
|
248
|
+
severity: "error"
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// src/can-render-media-on-web.ts
|
|
256
|
+
var canRenderMediaOnWeb = async (options) => {
|
|
257
|
+
const issues = [];
|
|
258
|
+
if (typeof VideoEncoder === "undefined") {
|
|
259
|
+
issues.push({
|
|
260
|
+
type: "webcodecs-unavailable",
|
|
261
|
+
message: "WebCodecs API is not available in this browser. A modern browser with WebCodecs support is required.",
|
|
262
|
+
severity: "error"
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
const container = options.container ?? "mp4";
|
|
266
|
+
const videoCodec = options.videoCodec ?? getDefaultVideoCodecForContainer(container);
|
|
267
|
+
const transparent = options.transparent ?? false;
|
|
268
|
+
const muted = options.muted ?? false;
|
|
269
|
+
const { width, height } = options;
|
|
270
|
+
const resolvedVideoBitrate = typeof options.videoBitrate === "number" ? options.videoBitrate : getQualityForWebRendererQuality(options.videoBitrate ?? "medium");
|
|
271
|
+
const resolvedAudioBitrate = typeof options.audioBitrate === "number" ? options.audioBitrate : getQualityForWebRendererQuality(options.audioBitrate ?? "medium");
|
|
272
|
+
const format = containerToMediabunnyContainer(container);
|
|
273
|
+
if (!format.getSupportedCodecs().includes(codecToMediabunnyCodec(videoCodec))) {
|
|
274
|
+
issues.push({
|
|
275
|
+
type: "container-codec-mismatch",
|
|
276
|
+
message: `Codec ${videoCodec} is not supported for container ${container}`,
|
|
277
|
+
severity: "error"
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
const dimensionIssue = validateDimensions({ width, height, codec: videoCodec });
|
|
281
|
+
if (dimensionIssue) {
|
|
282
|
+
issues.push(dimensionIssue);
|
|
283
|
+
}
|
|
284
|
+
const canEncodeVideoResult = await canEncodeVideo(codecToMediabunnyCodec(videoCodec), { bitrate: resolvedVideoBitrate });
|
|
285
|
+
if (!canEncodeVideoResult) {
|
|
286
|
+
issues.push({
|
|
287
|
+
type: "video-codec-unsupported",
|
|
288
|
+
message: `Video codec "${videoCodec}" cannot be encoded by this browser`,
|
|
289
|
+
severity: "error"
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
if (transparent && !["vp8", "vp9"].includes(videoCodec)) {
|
|
293
|
+
issues.push({
|
|
294
|
+
type: "transparent-video-unsupported",
|
|
295
|
+
message: `Transparent video requires VP8 or VP9 codec with WebM container. ${videoCodec} does not support alpha channel.`,
|
|
296
|
+
severity: "error"
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
let resolvedAudioCodec = null;
|
|
300
|
+
if (!muted) {
|
|
301
|
+
const audioResult = await resolveAudioCodec({
|
|
302
|
+
container,
|
|
303
|
+
requestedCodec: options.audioCodec,
|
|
304
|
+
userSpecifiedAudioCodec: options.audioCodec !== undefined && options.audioCodec !== null,
|
|
305
|
+
bitrate: resolvedAudioBitrate
|
|
306
|
+
});
|
|
307
|
+
resolvedAudioCodec = audioResult.codec;
|
|
308
|
+
issues.push(...audioResult.issues);
|
|
309
|
+
}
|
|
310
|
+
const webglIssue = checkWebGLSupport();
|
|
311
|
+
if (webglIssue) {
|
|
312
|
+
issues.push(webglIssue);
|
|
313
|
+
}
|
|
314
|
+
const canUseWebFs = await canUseWebFsWriter();
|
|
315
|
+
let resolvedOutputTarget;
|
|
316
|
+
if (options.outputTarget === "web-fs") {
|
|
317
|
+
if (!canUseWebFs) {
|
|
318
|
+
issues.push({
|
|
319
|
+
type: "output-target-unsupported",
|
|
320
|
+
message: 'The "web-fs" output target is not supported in this browser. The File System Access API is required.',
|
|
321
|
+
severity: "error"
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
resolvedOutputTarget = "web-fs";
|
|
325
|
+
} else if (options.outputTarget === "arraybuffer") {
|
|
326
|
+
resolvedOutputTarget = "arraybuffer";
|
|
327
|
+
} else {
|
|
328
|
+
resolvedOutputTarget = canUseWebFs ? "web-fs" : "arraybuffer";
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
canRender: issues.filter((i) => i.severity === "error").length === 0,
|
|
332
|
+
issues,
|
|
333
|
+
resolvedVideoCodec: videoCodec,
|
|
334
|
+
resolvedAudioCodec,
|
|
335
|
+
resolvedOutputTarget
|
|
336
|
+
};
|
|
337
|
+
};
|
|
338
|
+
// src/get-encodable-codecs.ts
|
|
339
|
+
import {
|
|
340
|
+
getEncodableAudioCodecs as mediabunnyGetEncodableAudioCodecs,
|
|
341
|
+
getEncodableVideoCodecs as mediabunnyGetEncodableVideoCodecs
|
|
342
|
+
} from "mediabunny";
|
|
343
|
+
var getEncodableVideoCodecs = async (container, options) => {
|
|
344
|
+
const supported = getSupportedVideoCodecsForContainer(container);
|
|
345
|
+
const mediabunnyCodecs = supported.map(codecToMediabunnyCodec);
|
|
346
|
+
const resolvedBitrate = options?.videoBitrate ? typeof options.videoBitrate === "number" ? options.videoBitrate : getQualityForWebRendererQuality(options.videoBitrate) : undefined;
|
|
347
|
+
const encodable = await mediabunnyGetEncodableVideoCodecs(mediabunnyCodecs, {
|
|
348
|
+
bitrate: resolvedBitrate
|
|
349
|
+
});
|
|
350
|
+
return supported.filter((c) => encodable.includes(codecToMediabunnyCodec(c)));
|
|
351
|
+
};
|
|
352
|
+
var getEncodableAudioCodecs = async (container, options) => {
|
|
353
|
+
const supported = getSupportedAudioCodecsForContainer(container);
|
|
354
|
+
const resolvedBitrate = options?.audioBitrate ? typeof options.audioBitrate === "number" ? options.audioBitrate : getQualityForWebRendererQuality(options.audioBitrate) : undefined;
|
|
355
|
+
const encodable = await mediabunnyGetEncodableAudioCodecs(supported, {
|
|
356
|
+
bitrate: resolvedBitrate
|
|
357
|
+
});
|
|
358
|
+
return supported.filter((c) => encodable.includes(c));
|
|
359
|
+
};
|
|
39
360
|
// src/render-media-on-web.tsx
|
|
40
361
|
import { BufferTarget, StreamTarget } from "mediabunny";
|
|
41
362
|
import { Internals as Internals7 } from "remotion";
|
|
@@ -167,24 +488,21 @@ var onlyInlineAudio = ({
|
|
|
167
488
|
});
|
|
168
489
|
};
|
|
169
490
|
|
|
170
|
-
// src/
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const directoryHandle = await navigator.storage.getDirectory();
|
|
180
|
-
const fileHandle = await directoryHandle.getFileHandle("remotion-probe-web-fs-support", {
|
|
181
|
-
create: true
|
|
182
|
-
});
|
|
183
|
-
const canUse = fileHandle.createWritable !== undefined;
|
|
184
|
-
return canUse;
|
|
185
|
-
} catch {
|
|
186
|
-
return false;
|
|
491
|
+
// src/create-audio-sample-source.ts
|
|
492
|
+
import { AudioSampleSource } from "mediabunny";
|
|
493
|
+
var createAudioSampleSource = ({
|
|
494
|
+
muted,
|
|
495
|
+
codec,
|
|
496
|
+
bitrate
|
|
497
|
+
}) => {
|
|
498
|
+
if (muted || codec === null) {
|
|
499
|
+
return null;
|
|
187
500
|
}
|
|
501
|
+
const audioSampleSource = new AudioSampleSource({
|
|
502
|
+
codec,
|
|
503
|
+
bitrate
|
|
504
|
+
});
|
|
505
|
+
return { audioSampleSource, [Symbol.dispose]: () => audioSampleSource.close() };
|
|
188
506
|
};
|
|
189
507
|
|
|
190
508
|
// src/create-scaffold.tsx
|
|
@@ -398,51 +716,6 @@ var getRealFrameRange = (durationInFrames, frameRange) => {
|
|
|
398
716
|
return frameRange;
|
|
399
717
|
};
|
|
400
718
|
|
|
401
|
-
// src/get-audio-sample-source.ts
|
|
402
|
-
import {
|
|
403
|
-
AudioSampleSource
|
|
404
|
-
} from "mediabunny";
|
|
405
|
-
|
|
406
|
-
// src/get-audio-encoding-config.ts
|
|
407
|
-
import {
|
|
408
|
-
canEncodeAudio,
|
|
409
|
-
QUALITY_MEDIUM
|
|
410
|
-
} from "mediabunny";
|
|
411
|
-
var getDefaultAudioEncodingConfig = async () => {
|
|
412
|
-
const preferredDefaultAudioEncodingConfig = {
|
|
413
|
-
codec: "aac",
|
|
414
|
-
bitrate: QUALITY_MEDIUM
|
|
415
|
-
};
|
|
416
|
-
if (await canEncodeAudio(preferredDefaultAudioEncodingConfig.codec, preferredDefaultAudioEncodingConfig)) {
|
|
417
|
-
return preferredDefaultAudioEncodingConfig;
|
|
418
|
-
}
|
|
419
|
-
const backupDefaultAudioEncodingConfig = {
|
|
420
|
-
codec: "opus",
|
|
421
|
-
bitrate: QUALITY_MEDIUM
|
|
422
|
-
};
|
|
423
|
-
if (await canEncodeAudio(backupDefaultAudioEncodingConfig.codec, backupDefaultAudioEncodingConfig)) {
|
|
424
|
-
return backupDefaultAudioEncodingConfig;
|
|
425
|
-
}
|
|
426
|
-
return null;
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
// src/get-audio-sample-source.ts
|
|
430
|
-
var addAudioSampleSource = async ({
|
|
431
|
-
muted,
|
|
432
|
-
output
|
|
433
|
-
}) => {
|
|
434
|
-
if (muted) {
|
|
435
|
-
return null;
|
|
436
|
-
}
|
|
437
|
-
const defaultAudioEncodingConfig = await getDefaultAudioEncodingConfig();
|
|
438
|
-
if (!defaultAudioEncodingConfig) {
|
|
439
|
-
throw new Error("No default audio encoding config found");
|
|
440
|
-
}
|
|
441
|
-
const audioSampleSource = new AudioSampleSource(defaultAudioEncodingConfig);
|
|
442
|
-
output.addAudioTrack(audioSampleSource);
|
|
443
|
-
return { audioSampleSource, [Symbol.dispose]: () => audioSampleSource.close() };
|
|
444
|
-
};
|
|
445
|
-
|
|
446
719
|
// src/internal-state.ts
|
|
447
720
|
var makeInternalState = () => {
|
|
448
721
|
let drawnPrecomposedPixels = 0;
|
|
@@ -513,79 +786,6 @@ var makeVideoSampleSourceCleanup = (encodingConfig) => {
|
|
|
513
786
|
};
|
|
514
787
|
};
|
|
515
788
|
|
|
516
|
-
// src/mediabunny-mappings.ts
|
|
517
|
-
import {
|
|
518
|
-
Mp4OutputFormat,
|
|
519
|
-
QUALITY_HIGH,
|
|
520
|
-
QUALITY_LOW,
|
|
521
|
-
QUALITY_MEDIUM as QUALITY_MEDIUM2,
|
|
522
|
-
QUALITY_VERY_HIGH,
|
|
523
|
-
QUALITY_VERY_LOW,
|
|
524
|
-
WebMOutputFormat
|
|
525
|
-
} from "mediabunny";
|
|
526
|
-
var codecToMediabunnyCodec = (codec) => {
|
|
527
|
-
switch (codec) {
|
|
528
|
-
case "h264":
|
|
529
|
-
return "avc";
|
|
530
|
-
case "h265":
|
|
531
|
-
return "hevc";
|
|
532
|
-
case "vp8":
|
|
533
|
-
return "vp8";
|
|
534
|
-
case "vp9":
|
|
535
|
-
return "vp9";
|
|
536
|
-
case "av1":
|
|
537
|
-
return "av1";
|
|
538
|
-
default:
|
|
539
|
-
throw new Error(`Unsupported codec: ${codec}`);
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
|
-
var containerToMediabunnyContainer = (container) => {
|
|
543
|
-
switch (container) {
|
|
544
|
-
case "mp4":
|
|
545
|
-
return new Mp4OutputFormat;
|
|
546
|
-
case "webm":
|
|
547
|
-
return new WebMOutputFormat;
|
|
548
|
-
default:
|
|
549
|
-
throw new Error(`Unsupported container: ${container}`);
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
var getDefaultVideoCodecForContainer = (container) => {
|
|
553
|
-
switch (container) {
|
|
554
|
-
case "mp4":
|
|
555
|
-
return "h264";
|
|
556
|
-
case "webm":
|
|
557
|
-
return "vp8";
|
|
558
|
-
default:
|
|
559
|
-
throw new Error(`Unsupported container: ${container}`);
|
|
560
|
-
}
|
|
561
|
-
};
|
|
562
|
-
var getQualityForWebRendererQuality = (quality) => {
|
|
563
|
-
switch (quality) {
|
|
564
|
-
case "very-low":
|
|
565
|
-
return QUALITY_VERY_LOW;
|
|
566
|
-
case "low":
|
|
567
|
-
return QUALITY_LOW;
|
|
568
|
-
case "medium":
|
|
569
|
-
return QUALITY_MEDIUM2;
|
|
570
|
-
case "high":
|
|
571
|
-
return QUALITY_HIGH;
|
|
572
|
-
case "very-high":
|
|
573
|
-
return QUALITY_VERY_HIGH;
|
|
574
|
-
default:
|
|
575
|
-
throw new Error(`Unsupported quality: ${quality}`);
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
var getMimeType = (container) => {
|
|
579
|
-
switch (container) {
|
|
580
|
-
case "mp4":
|
|
581
|
-
return "video/mp4";
|
|
582
|
-
case "webm":
|
|
583
|
-
return "video/webm";
|
|
584
|
-
default:
|
|
585
|
-
throw new Error(`Unsupported container: ${container}`);
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
|
|
589
789
|
// src/render-operations-queue.ts
|
|
590
790
|
var onlyOneRenderAtATimeQueue = {
|
|
591
791
|
ref: Promise.resolve()
|
|
@@ -1362,7 +1562,7 @@ var calculateTransforms = ({
|
|
|
1362
1562
|
if (!elementComputedStyle) {
|
|
1363
1563
|
throw new Error("Element computed style not found");
|
|
1364
1564
|
}
|
|
1365
|
-
const needs3DTransformViaWebGL = !totalMatrix.
|
|
1565
|
+
const needs3DTransformViaWebGL = !totalMatrix.is2D;
|
|
1366
1566
|
const needsMaskImage = maskImageInfo !== null;
|
|
1367
1567
|
return {
|
|
1368
1568
|
dimensions,
|
|
@@ -2817,13 +3017,16 @@ var processNode = async ({
|
|
|
2817
3017
|
});
|
|
2818
3018
|
}
|
|
2819
3019
|
if (precompositing.needs3DTransformViaWebGL) {
|
|
2820
|
-
|
|
3020
|
+
const t = handle3dTransform({
|
|
2821
3021
|
matrix: totalMatrix,
|
|
2822
3022
|
precomposeRect,
|
|
2823
3023
|
tempCanvas: drawable,
|
|
2824
3024
|
rectAfterTransforms,
|
|
2825
3025
|
internalState
|
|
2826
3026
|
});
|
|
3027
|
+
if (t) {
|
|
3028
|
+
drawable = t;
|
|
3029
|
+
}
|
|
2827
3030
|
}
|
|
2828
3031
|
const previousTransform = context.getTransform();
|
|
2829
3032
|
if (drawable) {
|
|
@@ -3429,6 +3632,8 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3429
3632
|
mediaCacheSizeInBytes,
|
|
3430
3633
|
schema,
|
|
3431
3634
|
videoCodec: codec,
|
|
3635
|
+
audioCodec: unresolvedAudioCodec,
|
|
3636
|
+
audioBitrate,
|
|
3432
3637
|
container,
|
|
3433
3638
|
signal,
|
|
3434
3639
|
onProgress,
|
|
@@ -3453,6 +3658,23 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3453
3658
|
if (codec && !format.getSupportedCodecs().includes(codecToMediabunnyCodec(codec))) {
|
|
3454
3659
|
return Promise.reject(new Error(`Codec ${codec} is not supported for container ${container}`));
|
|
3455
3660
|
}
|
|
3661
|
+
const resolvedAudioBitrate = typeof audioBitrate === "number" ? audioBitrate : getQualityForWebRendererQuality(audioBitrate);
|
|
3662
|
+
let finalAudioCodec = null;
|
|
3663
|
+
if (!muted) {
|
|
3664
|
+
const audioResult = await resolveAudioCodec({
|
|
3665
|
+
container,
|
|
3666
|
+
requestedCodec: unresolvedAudioCodec,
|
|
3667
|
+
userSpecifiedAudioCodec: unresolvedAudioCodec !== undefined && unresolvedAudioCodec !== null,
|
|
3668
|
+
bitrate: resolvedAudioBitrate
|
|
3669
|
+
});
|
|
3670
|
+
for (const issue of audioResult.issues) {
|
|
3671
|
+
if (issue.severity === "error") {
|
|
3672
|
+
return Promise.reject(new Error(issue.message));
|
|
3673
|
+
}
|
|
3674
|
+
Internals7.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, issue.message);
|
|
3675
|
+
}
|
|
3676
|
+
finalAudioCodec = audioResult.codec;
|
|
3677
|
+
}
|
|
3456
3678
|
const resolved = await Internals7.resolveVideoConfig({
|
|
3457
3679
|
calculateMetadata: composition.calculateMetadata ?? null,
|
|
3458
3680
|
signal: signal ?? new AbortController().signal,
|
|
@@ -3521,10 +3743,14 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3521
3743
|
alpha: transparent ? "keep" : "discard"
|
|
3522
3744
|
}), 0);
|
|
3523
3745
|
outputWithCleanup.output.addVideoTrack(videoSampleSource.videoSampleSource);
|
|
3524
|
-
const audioSampleSource = __using(__stack,
|
|
3746
|
+
const audioSampleSource = __using(__stack, createAudioSampleSource({
|
|
3525
3747
|
muted,
|
|
3526
|
-
|
|
3748
|
+
codec: finalAudioCodec ? audioCodecToMediabunnyAudioCodec(finalAudioCodec) : null,
|
|
3749
|
+
bitrate: resolvedAudioBitrate
|
|
3527
3750
|
}), 0);
|
|
3751
|
+
if (audioSampleSource) {
|
|
3752
|
+
outputWithCleanup.output.addAudioTrack(audioSampleSource.audioSampleSource);
|
|
3753
|
+
}
|
|
3528
3754
|
await outputWithCleanup.output.start();
|
|
3529
3755
|
if (signal?.aborted) {
|
|
3530
3756
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
@@ -3677,6 +3903,8 @@ var renderMediaOnWeb = (options) => {
|
|
|
3677
3903
|
schema: options.schema ?? undefined,
|
|
3678
3904
|
mediaCacheSizeInBytes: options.mediaCacheSizeInBytes ?? null,
|
|
3679
3905
|
videoCodec: codec,
|
|
3906
|
+
audioCodec: options.audioCodec ?? null,
|
|
3907
|
+
audioBitrate: options.audioBitrate ?? "medium",
|
|
3680
3908
|
container,
|
|
3681
3909
|
signal: options.signal ?? null,
|
|
3682
3910
|
onProgress: options.onProgress ?? null,
|
|
@@ -3812,5 +4040,12 @@ var renderStillOnWeb = (options) => {
|
|
|
3812
4040
|
};
|
|
3813
4041
|
export {
|
|
3814
4042
|
renderStillOnWeb,
|
|
3815
|
-
renderMediaOnWeb
|
|
4043
|
+
renderMediaOnWeb,
|
|
4044
|
+
getSupportedVideoCodecsForContainer,
|
|
4045
|
+
getSupportedAudioCodecsForContainer,
|
|
4046
|
+
getEncodableVideoCodecs,
|
|
4047
|
+
getEncodableAudioCodecs,
|
|
4048
|
+
getDefaultVideoCodecForContainer,
|
|
4049
|
+
getDefaultAudioCodecForContainer,
|
|
4050
|
+
canRenderMediaOnWeb
|
|
3816
4051
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type WebRendererAudioCodec, type WebRendererContainer, type WebRendererQuality, type WebRendererVideoCodec } from './mediabunny-mappings';
|
|
2
|
+
export type GetEncodableVideoCodecsOptions = {
|
|
3
|
+
videoBitrate?: number | WebRendererQuality;
|
|
4
|
+
};
|
|
5
|
+
export type GetEncodableAudioCodecsOptions = {
|
|
6
|
+
audioBitrate?: number | WebRendererQuality;
|
|
7
|
+
};
|
|
8
|
+
export declare const getEncodableVideoCodecs: (container: WebRendererContainer, options?: GetEncodableVideoCodecsOptions | undefined) => Promise<WebRendererVideoCodec[]>;
|
|
9
|
+
export declare const getEncodableAudioCodecs: (container: WebRendererContainer, options?: GetEncodableAudioCodecsOptions | undefined) => Promise<WebRendererAudioCodec[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import './symbol-dispose';
|
|
2
2
|
export type { EmittedArtifact, WebRendererOnArtifact } from './artifact';
|
|
3
|
+
export { canRenderMediaOnWeb } from './can-render-media-on-web';
|
|
4
|
+
export type { CanRenderIssue, CanRenderMediaOnWebOptions, CanRenderMediaOnWebResult, } from './can-render-media-on-web';
|
|
3
5
|
export type { FrameRange } from './frame-range';
|
|
4
|
-
export
|
|
6
|
+
export { getEncodableAudioCodecs, getEncodableVideoCodecs, type GetEncodableAudioCodecsOptions, type GetEncodableVideoCodecsOptions, } from './get-encodable-codecs';
|
|
7
|
+
export { getDefaultAudioCodecForContainer, getDefaultVideoCodecForContainer, getSupportedAudioCodecsForContainer, getSupportedVideoCodecsForContainer, } from './mediabunny-mappings';
|
|
8
|
+
export type { WebRendererAudioCodec, WebRendererContainer, WebRendererQuality, WebRendererVideoCodec, } from './mediabunny-mappings';
|
|
5
9
|
export type { WebRendererOutputTarget } from './output-target';
|
|
6
10
|
export { renderMediaOnWeb } from './render-media-on-web';
|
|
7
11
|
export type { RenderMediaOnWebOptions, RenderMediaOnWebProgress, RenderMediaOnWebProgressCallback, RenderMediaOnWebResult, } from './render-media-on-web';
|
|
@@ -2,9 +2,14 @@ import type { Quality } from 'mediabunny';
|
|
|
2
2
|
import { type OutputFormat } from 'mediabunny';
|
|
3
3
|
export type WebRendererVideoCodec = 'h264' | 'h265' | 'vp8' | 'vp9' | 'av1';
|
|
4
4
|
export type WebRendererContainer = 'mp4' | 'webm';
|
|
5
|
+
export type WebRendererAudioCodec = 'aac' | 'opus';
|
|
5
6
|
export type WebRendererQuality = 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
|
|
6
7
|
export declare const codecToMediabunnyCodec: (codec: WebRendererVideoCodec) => "av1" | "avc" | "hevc" | "vp8" | "vp9";
|
|
7
8
|
export declare const containerToMediabunnyContainer: (container: WebRendererContainer) => OutputFormat;
|
|
8
9
|
export declare const getDefaultVideoCodecForContainer: (container: WebRendererContainer) => WebRendererVideoCodec;
|
|
9
10
|
export declare const getQualityForWebRendererQuality: (quality: WebRendererQuality) => Quality;
|
|
10
11
|
export declare const getMimeType: (container: WebRendererContainer) => string;
|
|
12
|
+
export declare const getDefaultAudioCodecForContainer: (container: WebRendererContainer) => WebRendererAudioCodec;
|
|
13
|
+
export declare const getSupportedVideoCodecsForContainer: (container: WebRendererContainer) => WebRendererVideoCodec[];
|
|
14
|
+
export declare const getSupportedAudioCodecsForContainer: (container: WebRendererContainer) => WebRendererAudioCodec[];
|
|
15
|
+
export declare const audioCodecToMediabunnyAudioCodec: (audioCodec: WebRendererAudioCodec) => "aac" | "alaw" | "flac" | "mp3" | "opus" | "pcm-f32" | "pcm-f32be" | "pcm-f64" | "pcm-f64be" | "pcm-s16" | "pcm-s16be" | "pcm-s24" | "pcm-s24be" | "pcm-s32" | "pcm-s32be" | "pcm-s8" | "pcm-u8" | "ulaw" | "vorbis";
|
|
@@ -3,7 +3,7 @@ import type { AnyZodObject, z } from 'zod';
|
|
|
3
3
|
import { type WebRendererOnArtifact } from './artifact';
|
|
4
4
|
import { type FrameRange } from './frame-range';
|
|
5
5
|
import type { InternalState } from './internal-state';
|
|
6
|
-
import type { WebRendererContainer, WebRendererQuality } from './mediabunny-mappings';
|
|
6
|
+
import type { WebRendererAudioCodec, WebRendererContainer, WebRendererQuality } from './mediabunny-mappings';
|
|
7
7
|
import { type WebRendererVideoCodec } from './mediabunny-mappings';
|
|
8
8
|
import type { WebRendererOutputTarget } from './output-target';
|
|
9
9
|
import type { CompositionCalculateMetadataOrExplicit } from './props-if-has-props';
|
|
@@ -35,6 +35,8 @@ type OptionalRenderMediaOnWebOptions<Schema extends AnyZodObject> = {
|
|
|
35
35
|
schema: Schema | undefined;
|
|
36
36
|
mediaCacheSizeInBytes: number | null;
|
|
37
37
|
videoCodec: WebRendererVideoCodec;
|
|
38
|
+
audioCodec: WebRendererAudioCodec | null;
|
|
39
|
+
audioBitrate: number | WebRendererQuality;
|
|
38
40
|
container: WebRendererContainer;
|
|
39
41
|
signal: AbortSignal | null;
|
|
40
42
|
onProgress: RenderMediaOnWebProgressCallback | null;
|
package/dist/renoun.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/** Image format for encoded screenshot output. */
|
|
2
|
+
export type ImageFormat = 'png' | 'jpeg' | 'webp';
|
|
3
|
+
/** Options for rendering a screenshot to canvas. */
|
|
4
|
+
export interface RenderOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Canvas background color. Set to `null` (or omit) for a transparent canvas.
|
|
7
|
+
* When provided, the string is passed directly to `fillStyle`.
|
|
8
|
+
*/
|
|
9
|
+
backgroundColor?: string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Optional existing canvas to render into.
|
|
12
|
+
* When omitted, a new canvas element is created.
|
|
13
|
+
*/
|
|
14
|
+
canvas?: HTMLCanvasElement;
|
|
15
|
+
/**
|
|
16
|
+
* Rendering scale factor. Defaults to `window.devicePixelRatio` (or `1`).
|
|
17
|
+
*/
|
|
18
|
+
scale?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Crop origin X (CSS pixels) relative to the element's left edge.
|
|
21
|
+
* Defaults to the element's left edge.
|
|
22
|
+
*/
|
|
23
|
+
x?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Crop origin Y (CSS pixels) relative to the element's top edge.
|
|
26
|
+
* Defaults to the element's top edge.
|
|
27
|
+
*/
|
|
28
|
+
y?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Output width in CSS pixels. Defaults to the element's width.
|
|
31
|
+
*/
|
|
32
|
+
width?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Output height in CSS pixels. Defaults to the element's height.
|
|
35
|
+
*/
|
|
36
|
+
height?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Controls how `position: fixed` elements outside the captured subtree are
|
|
39
|
+
* handled.
|
|
40
|
+
*
|
|
41
|
+
* - `none` – ignore all fixed elements outside `element`.
|
|
42
|
+
* - `intersecting` – include fixed elements whose bounding rect intersects the capture rect.
|
|
43
|
+
* - `all` – include all fixed elements that overlap the viewport.
|
|
44
|
+
*/
|
|
45
|
+
includeFixed?: 'none' | 'intersecting' | 'all';
|
|
46
|
+
}
|
|
47
|
+
/** Options for encoding a canvas to an image format. */
|
|
48
|
+
export interface EncodeOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Image format to encode. Defaults to `'png'`.
|
|
51
|
+
*/
|
|
52
|
+
format?: ImageFormat;
|
|
53
|
+
/**
|
|
54
|
+
* Image quality for lossy formats (`jpeg`, `webp`). A number between `0` and `1`.
|
|
55
|
+
* Ignored for `png`. Defaults to `0.92`.
|
|
56
|
+
*/
|
|
57
|
+
quality?: number;
|
|
58
|
+
}
|
|
59
|
+
/** Combined options for one-shot screenshot methods that render and encode. */
|
|
60
|
+
export type ScreenshotOptions = RenderOptions & EncodeOptions;
|
|
61
|
+
/**
|
|
62
|
+
* A promise-like object representing a screenshot capture. The underlying
|
|
63
|
+
* render happens once; subsequent calls to `.canvas()`, `.blob()`, or `.url()`
|
|
64
|
+
* reuse the same rendered canvas.
|
|
65
|
+
*/
|
|
66
|
+
export interface ScreenshotTask extends Promise<HTMLCanvasElement> {
|
|
67
|
+
/** Returns the rendered canvas. */
|
|
68
|
+
canvas(): Promise<HTMLCanvasElement>;
|
|
69
|
+
/** Encodes the rendered canvas to a Blob. */
|
|
70
|
+
blob(options?: EncodeOptions): Promise<Blob>;
|
|
71
|
+
/**
|
|
72
|
+
* Encodes the rendered canvas to a Blob and creates an object URL.
|
|
73
|
+
* Remember to call `URL.revokeObjectURL(url)` when done to avoid memory leaks.
|
|
74
|
+
*/
|
|
75
|
+
url(options?: EncodeOptions): Promise<string>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Renders a DOM element into a canvas using modern browser features.
|
|
79
|
+
*
|
|
80
|
+
* Returns a `ScreenshotTask` that is both a Promise and provides methods
|
|
81
|
+
* to encode the rendered canvas. The underlying render happens once;
|
|
82
|
+
* subsequent calls to `.canvas()`, `.blob()`, or `.url()` reuse the same result.
|
|
83
|
+
*
|
|
84
|
+
* This implementation targets evergreen browsers only and assumes a real DOM +
|
|
85
|
+
* Canvas2D environment (not Node.js).
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Capture handle pattern - render once, encode multiple ways
|
|
89
|
+
* const shot = screenshot(element, { scale: 2 })
|
|
90
|
+
* const canvas = await shot.canvas()
|
|
91
|
+
* const pngBlob = await shot.blob({ format: 'png' })
|
|
92
|
+
* const webpUrl = await shot.url({ format: 'webp', quality: 0.9 })
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* // Direct await returns the canvas
|
|
96
|
+
* const canvas = await screenshot(element)
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* // One-shot convenience methods
|
|
100
|
+
* const canvas = await screenshot.canvas(element, { scale: 2 })
|
|
101
|
+
* const blob = await screenshot.blob(element, { format: 'jpeg', quality: 0.85 })
|
|
102
|
+
* const url = await screenshot.url(element, { format: 'png' })
|
|
103
|
+
*/
|
|
104
|
+
declare function screenshot(target: Element | string, options?: RenderOptions): ScreenshotTask;
|
|
105
|
+
declare namespace screenshot {
|
|
106
|
+
var canvas: (target: string | Element, options?: RenderOptions | undefined) => Promise<HTMLCanvasElement>;
|
|
107
|
+
}
|
|
108
|
+
declare namespace screenshot {
|
|
109
|
+
var blob: (target: string | Element, options?: ScreenshotOptions | undefined) => Promise<Blob>;
|
|
110
|
+
}
|
|
111
|
+
declare namespace screenshot {
|
|
112
|
+
var url: (target: string | Element, options?: ScreenshotOptions | undefined) => Promise<string>;
|
|
113
|
+
}
|
|
114
|
+
export { screenshot };
|
|
115
|
+
declare global {
|
|
116
|
+
interface CanvasRenderingContext2D {
|
|
117
|
+
_filterPolyfillValue?: string;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Quality } from 'mediabunny';
|
|
2
|
+
import type { CanRenderIssue } from './can-render-types';
|
|
3
|
+
import { type WebRendererAudioCodec, type WebRendererContainer } from './mediabunny-mappings';
|
|
4
|
+
export type ResolveAudioCodecResult = {
|
|
5
|
+
codec: WebRendererAudioCodec | null;
|
|
6
|
+
issues: CanRenderIssue[];
|
|
7
|
+
};
|
|
8
|
+
export declare const resolveAudioCodec: (options: {
|
|
9
|
+
container: WebRendererContainer;
|
|
10
|
+
requestedCodec: WebRendererAudioCodec | null | undefined;
|
|
11
|
+
userSpecifiedAudioCodec: boolean;
|
|
12
|
+
bitrate: number | Quality;
|
|
13
|
+
}) => Promise<ResolveAudioCodecResult>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CanRenderIssue } from './can-render-types';
|
|
2
|
+
import type { WebRendererVideoCodec } from './mediabunny-mappings';
|
|
3
|
+
export declare const validateDimensions: (options: {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
codec: WebRendererVideoCodec;
|
|
7
|
+
}) => CanRenderIssue | null;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/web-renderer"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/web-renderer",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.403",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"sideEffects": false,
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"author": "Remotion <jonny@remotion.dev>",
|
|
19
19
|
"license": "UNLICENSED",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@remotion/licensing": "4.0.
|
|
22
|
-
"remotion": "4.0.
|
|
21
|
+
"@remotion/licensing": "4.0.403",
|
|
22
|
+
"remotion": "4.0.403",
|
|
23
23
|
"mediabunny": "1.27.3"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
27
|
-
"@remotion/player": "4.0.
|
|
28
|
-
"@remotion/media": "4.0.
|
|
26
|
+
"@remotion/eslint-config-internal": "4.0.403",
|
|
27
|
+
"@remotion/player": "4.0.403",
|
|
28
|
+
"@remotion/media": "4.0.403",
|
|
29
29
|
"@typescript/native-preview": "7.0.0-dev.20260105.1",
|
|
30
30
|
"@vitejs/plugin-react": "4.1.0",
|
|
31
31
|
"@vitest/browser-playwright": "4.0.9",
|