@remotion/renderer 4.0.278 → 4.0.279
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/assets/calculate-asset-positions.js +0 -1
- package/dist/assets/ffmpeg-volume-expression.d.ts +1 -2
- package/dist/assets/ffmpeg-volume-expression.js +3 -5
- package/dist/assets/types.d.ts +0 -1
- package/dist/can-concat-seamlessly.d.ts +4 -0
- package/dist/can-concat-seamlessly.js +17 -0
- package/dist/client.d.ts +2 -2
- package/dist/combine-chunks.d.ts +39 -0
- package/dist/{combine-videos.js → combine-chunks.js} +50 -7
- package/dist/esm/error-handling.mjs +8 -0
- package/dist/esm/index.mjs +2150 -2086
- package/dist/index.d.ts +30 -22
- package/dist/index.js +8 -3
- package/dist/options/index.d.ts +2 -2
- package/dist/options/metadata.d.ts +1 -1
- package/dist/options/webhook-custom-data.d.ts +1 -1
- package/dist/print-useful-error-message.js +8 -0
- package/dist/render-media.d.ts +2 -1
- package/dist/render-media.js +7 -8
- package/dist/stringify-ffmpeg-filter.js +0 -1
- package/dist/validate-even-dimensions-with-codec.d.ts +4 -1
- package/dist/validate-even-dimensions-with-codec.js +14 -4
- package/package.json +15 -15
- package/dist/combine-videos.d.ts +0 -27
package/dist/esm/index.mjs
CHANGED
|
@@ -4059,536 +4059,386 @@ var validCodecs = [
|
|
|
4059
4059
|
];
|
|
4060
4060
|
var DEFAULT_CODEC = "h264";
|
|
4061
4061
|
|
|
4062
|
-
// src/
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
import { join as join2 } from "path";
|
|
4069
|
-
import { VERSION as VERSION2 } from "remotion/version";
|
|
4070
|
-
|
|
4071
|
-
// src/options/separate-audio.tsx
|
|
4072
|
-
var DEFAULT = null;
|
|
4073
|
-
var cliFlag = "separate-audio-to";
|
|
4074
|
-
var separateAudioOption = {
|
|
4075
|
-
cliFlag,
|
|
4076
|
-
description: () => `If set, the audio will not be included in the main output but rendered as a separate file at the location you pass. It is recommended to use an absolute path. If a relative path is passed, it is relative to the Remotion Root.`,
|
|
4077
|
-
docLink: "https://remotion.dev/docs/renderer/render-media",
|
|
4078
|
-
getValue: ({ commandLine }) => {
|
|
4079
|
-
if (commandLine[cliFlag]) {
|
|
4080
|
-
return {
|
|
4081
|
-
source: "cli",
|
|
4082
|
-
value: commandLine[cliFlag]
|
|
4083
|
-
};
|
|
4084
|
-
}
|
|
4085
|
-
return {
|
|
4086
|
-
source: "default",
|
|
4087
|
-
value: DEFAULT
|
|
4088
|
-
};
|
|
4089
|
-
},
|
|
4090
|
-
name: "Separate audio to",
|
|
4091
|
-
setConfig: () => {
|
|
4092
|
-
throw new Error("Not implemented");
|
|
4093
|
-
},
|
|
4094
|
-
ssrName: "separateAudioTo",
|
|
4095
|
-
type: "string"
|
|
4062
|
+
// src/convert-to-positive-frame-index.ts
|
|
4063
|
+
var convertToPositiveFrameIndex = ({
|
|
4064
|
+
frame,
|
|
4065
|
+
durationInFrames
|
|
4066
|
+
}) => {
|
|
4067
|
+
return frame < 0 ? durationInFrames - frame : frame;
|
|
4096
4068
|
};
|
|
4097
4069
|
|
|
4098
|
-
// src/
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
vp9: ["opus", "pcm-16"],
|
|
4112
|
-
wav: ["pcm-16"]
|
|
4113
|
-
};
|
|
4114
|
-
var _satisfies = supportedAudioCodecs;
|
|
4115
|
-
if (_satisfies) {
|
|
4116
|
-
}
|
|
4117
|
-
var mapAudioCodecToFfmpegAudioCodecName = (audioCodec) => {
|
|
4118
|
-
if (audioCodec === "aac") {
|
|
4119
|
-
return "libfdk_aac";
|
|
4120
|
-
}
|
|
4121
|
-
if (audioCodec === "mp3") {
|
|
4122
|
-
return "libmp3lame";
|
|
4123
|
-
}
|
|
4124
|
-
if (audioCodec === "opus") {
|
|
4125
|
-
return "libopus";
|
|
4070
|
+
// src/symbolicate-stacktrace.ts
|
|
4071
|
+
import { readFileSync } from "fs";
|
|
4072
|
+
import path6 from "path";
|
|
4073
|
+
import { SourceMapConsumer } from "source-map";
|
|
4074
|
+
function extractSourceMapUrl(fileContents) {
|
|
4075
|
+
const regex = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/gm;
|
|
4076
|
+
let match = null;
|
|
4077
|
+
for (;; ) {
|
|
4078
|
+
const next = regex.exec(fileContents);
|
|
4079
|
+
if (next === null || next === undefined) {
|
|
4080
|
+
break;
|
|
4081
|
+
}
|
|
4082
|
+
match = next;
|
|
4126
4083
|
}
|
|
4127
|
-
if (
|
|
4128
|
-
return
|
|
4084
|
+
if (!match?.[1]) {
|
|
4085
|
+
return null;
|
|
4129
4086
|
}
|
|
4130
|
-
|
|
4131
|
-
}
|
|
4132
|
-
var
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
"h264-mkv": {
|
|
4136
|
-
lossless: "pcm-16",
|
|
4137
|
-
compressed: "pcm-16"
|
|
4138
|
-
},
|
|
4139
|
-
"h264-ts": {
|
|
4140
|
-
lossless: "pcm-16",
|
|
4141
|
-
compressed: "aac"
|
|
4142
|
-
},
|
|
4143
|
-
aac: {
|
|
4144
|
-
lossless: "pcm-16",
|
|
4145
|
-
compressed: "aac"
|
|
4146
|
-
},
|
|
4147
|
-
gif: {
|
|
4148
|
-
lossless: null,
|
|
4149
|
-
compressed: null
|
|
4150
|
-
},
|
|
4151
|
-
h264: {
|
|
4152
|
-
lossless: "pcm-16",
|
|
4153
|
-
compressed: "aac"
|
|
4154
|
-
},
|
|
4155
|
-
h265: {
|
|
4156
|
-
lossless: "pcm-16",
|
|
4157
|
-
compressed: "aac"
|
|
4158
|
-
},
|
|
4159
|
-
mp3: {
|
|
4160
|
-
lossless: "pcm-16",
|
|
4161
|
-
compressed: "mp3"
|
|
4162
|
-
},
|
|
4163
|
-
prores: {
|
|
4164
|
-
lossless: "pcm-16",
|
|
4165
|
-
compressed: "pcm-16"
|
|
4166
|
-
},
|
|
4167
|
-
vp8: {
|
|
4168
|
-
lossless: "pcm-16",
|
|
4169
|
-
compressed: "opus"
|
|
4170
|
-
},
|
|
4171
|
-
vp9: {
|
|
4172
|
-
lossless: "pcm-16",
|
|
4173
|
-
compressed: "opus"
|
|
4174
|
-
},
|
|
4175
|
-
wav: {
|
|
4176
|
-
lossless: "pcm-16",
|
|
4177
|
-
compressed: "pcm-16"
|
|
4087
|
+
return match[1].toString();
|
|
4088
|
+
}
|
|
4089
|
+
var getSourceMapFromRemoteUrl = async (url) => {
|
|
4090
|
+
if (!url.endsWith(".js.map")) {
|
|
4091
|
+
throw new Error(`The URL ${url} does not seem to be a valid source map URL.`);
|
|
4178
4092
|
}
|
|
4093
|
+
const obj = await fetchUrl(url);
|
|
4094
|
+
return new SourceMapConsumer(obj);
|
|
4179
4095
|
};
|
|
4180
|
-
var
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
"pcm-16": "wav"
|
|
4185
|
-
};
|
|
4186
|
-
var getExtensionFromAudioCodec = (audioCodec) => {
|
|
4187
|
-
if (extensionMap[audioCodec]) {
|
|
4188
|
-
return extensionMap[audioCodec];
|
|
4096
|
+
var getSourceMap = (filePath, fileContents, type) => {
|
|
4097
|
+
const sm = extractSourceMapUrl(fileContents);
|
|
4098
|
+
if (sm === null) {
|
|
4099
|
+
return Promise.resolve(null);
|
|
4189
4100
|
}
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
preferLossless,
|
|
4196
|
-
separateAudioTo
|
|
4197
|
-
}) => {
|
|
4198
|
-
let derivedFromSeparateAudioToExtension = null;
|
|
4199
|
-
if (separateAudioTo) {
|
|
4200
|
-
const extension = separateAudioTo.split(".").pop();
|
|
4201
|
-
for (const [key, value] of Object.entries(extensionMap)) {
|
|
4202
|
-
if (value === extension) {
|
|
4203
|
-
derivedFromSeparateAudioToExtension = key;
|
|
4204
|
-
if (!supportedAudioCodecs[codec].includes(derivedFromSeparateAudioToExtension) && derivedFromSeparateAudioToExtension) {
|
|
4205
|
-
throw new Error(`The codec is ${codec} but the audio codec derived from --${separateAudioOption.cliFlag} is ${derivedFromSeparateAudioToExtension}. The only supported codecs are: ${supportedAudioCodecs[codec].join(", ")}`);
|
|
4206
|
-
}
|
|
4207
|
-
}
|
|
4101
|
+
if (sm.indexOf("data:") === 0) {
|
|
4102
|
+
const base64 = /^data:application\/json;([\w=:"-]+;)*base64,/;
|
|
4103
|
+
const match2 = sm.match(base64);
|
|
4104
|
+
if (!match2) {
|
|
4105
|
+
throw new Error("Sorry, non-base64 inline source-map encoding is not supported.");
|
|
4208
4106
|
}
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4107
|
+
const converted = window.atob(sm.substring(match2[0].length));
|
|
4108
|
+
try {
|
|
4109
|
+
const sourceMapConsumer = new SourceMapConsumer(JSON.parse(converted));
|
|
4110
|
+
return Promise.resolve(sourceMapConsumer);
|
|
4111
|
+
} catch {
|
|
4112
|
+
return Promise.resolve(null);
|
|
4214
4113
|
}
|
|
4215
|
-
return selected;
|
|
4216
4114
|
}
|
|
4217
|
-
if (
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
}
|
|
4221
|
-
return getDefaultAudioCodec({ codec, preferLossless });
|
|
4115
|
+
if (type === "local") {
|
|
4116
|
+
const newFilePath = path6.join(path6.dirname(filePath), sm);
|
|
4117
|
+
return Promise.resolve(new SourceMapConsumer(readFileSync(newFilePath, "utf8")));
|
|
4222
4118
|
}
|
|
4223
|
-
|
|
4224
|
-
|
|
4119
|
+
const index = filePath.lastIndexOf("/");
|
|
4120
|
+
const url = filePath.substring(0, index + 1) + sm;
|
|
4121
|
+
return getSourceMapFromRemoteUrl(url);
|
|
4122
|
+
};
|
|
4123
|
+
var fetchUrl = async (url) => {
|
|
4124
|
+
const res = await readFile(url);
|
|
4125
|
+
return new Promise((resolve, reject) => {
|
|
4126
|
+
let downloaded = "";
|
|
4127
|
+
res.on("data", (d) => {
|
|
4128
|
+
downloaded += d;
|
|
4129
|
+
});
|
|
4130
|
+
res.on("end", () => {
|
|
4131
|
+
resolve(downloaded);
|
|
4132
|
+
});
|
|
4133
|
+
res.on("error", (err) => reject(err));
|
|
4134
|
+
});
|
|
4135
|
+
};
|
|
4136
|
+
function getLinesAround(line, count, lines) {
|
|
4137
|
+
const result = [];
|
|
4138
|
+
for (let index = Math.max(0, line - 1 - count) + 1;index <= Math.min(lines.length - 1, line - 1 + count); ++index) {
|
|
4139
|
+
result.push({
|
|
4140
|
+
lineNumber: index + 1,
|
|
4141
|
+
content: lines[index],
|
|
4142
|
+
highlight: index + 1 === line
|
|
4143
|
+
});
|
|
4225
4144
|
}
|
|
4226
|
-
return
|
|
4145
|
+
return result;
|
|
4146
|
+
}
|
|
4147
|
+
var getOriginalPosition = (source_map, line, column) => {
|
|
4148
|
+
const result = source_map.originalPositionFor({
|
|
4149
|
+
line,
|
|
4150
|
+
column
|
|
4151
|
+
});
|
|
4152
|
+
return { line: result.line, column: result.column, source: result.source };
|
|
4227
4153
|
};
|
|
4228
|
-
var
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4154
|
+
var symbolicateStackTraceFromRemoteFrames = async (frames) => {
|
|
4155
|
+
const uniqueFileNames = [
|
|
4156
|
+
...new Set(frames.map((f) => f.fileName).filter((f) => f.startsWith("http://") || f.startsWith("https://")).filter(truthy))
|
|
4157
|
+
];
|
|
4158
|
+
const maps = await Promise.all(uniqueFileNames.map((fileName) => {
|
|
4159
|
+
return getSourceMapFromRemoteFile(fileName);
|
|
4160
|
+
}));
|
|
4161
|
+
const mapValues = {};
|
|
4162
|
+
for (let i = 0;i < uniqueFileNames.length; i++) {
|
|
4163
|
+
mapValues[uniqueFileNames[i]] = maps[i];
|
|
4164
|
+
}
|
|
4165
|
+
return symbolicateFromSources(frames, mapValues);
|
|
4233
4166
|
};
|
|
4234
|
-
var
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
_audioCodec = null;
|
|
4240
|
-
return;
|
|
4241
|
-
}
|
|
4242
|
-
if (!validAudioCodecs.includes(audioCodec)) {
|
|
4243
|
-
throw new Error(`Audio codec must be one of the following: ${validAudioCodecs.join(", ")}, but got ${audioCodec}`);
|
|
4244
|
-
}
|
|
4245
|
-
_audioCodec = audioCodec;
|
|
4246
|
-
},
|
|
4247
|
-
getValue: ({ commandLine }) => {
|
|
4248
|
-
if (commandLine[cliFlag2]) {
|
|
4249
|
-
const codec = commandLine[cliFlag2];
|
|
4250
|
-
if (!validAudioCodecs.includes(commandLine[cliFlag2])) {
|
|
4251
|
-
throw new Error(`Audio codec must be one of the following: ${validAudioCodecs.join(", ")}, but got ${codec}`);
|
|
4252
|
-
}
|
|
4253
|
-
return {
|
|
4254
|
-
source: "cli",
|
|
4255
|
-
value: commandLine[cliFlag2]
|
|
4256
|
-
};
|
|
4257
|
-
}
|
|
4258
|
-
if (_audioCodec !== null) {
|
|
4259
|
-
return {
|
|
4260
|
-
source: "config",
|
|
4261
|
-
value: _audioCodec
|
|
4262
|
-
};
|
|
4167
|
+
var symbolicateFromSources = (frames, mapValues) => {
|
|
4168
|
+
return frames.map((frame) => {
|
|
4169
|
+
const map = mapValues[frame.fileName];
|
|
4170
|
+
if (!map) {
|
|
4171
|
+
return null;
|
|
4263
4172
|
}
|
|
4264
|
-
return
|
|
4265
|
-
|
|
4266
|
-
value: null
|
|
4267
|
-
};
|
|
4268
|
-
},
|
|
4269
|
-
description: () => `Set the format of the audio that is embedded in the video. Not all codec and audio codec combinations are supported and certain combinations require a certain file extension and container format. See the table in the docs to see possible combinations.`,
|
|
4270
|
-
docLink: "https://www.remotion.dev/docs/encoding/#audio-codec",
|
|
4271
|
-
name: "Audio Codec",
|
|
4272
|
-
ssrName,
|
|
4273
|
-
type: "aac"
|
|
4173
|
+
return symbolicateStackFrame(frame, map);
|
|
4174
|
+
}).filter(truthy).filter((f) => f.originalScriptCode !== null);
|
|
4274
4175
|
};
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
const
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
}
|
|
4176
|
+
var symbolicateStackFrame = (frame, map) => {
|
|
4177
|
+
const pos = getOriginalPosition(map, frame.lineNumber, frame.columnNumber);
|
|
4178
|
+
const hasSource = pos.source ? map.sourceContentFor(pos.source, false) : null;
|
|
4179
|
+
const scriptCode = hasSource && pos.line ? getLinesAround(pos.line, 3, hasSource.split(`
|
|
4180
|
+
`)) : null;
|
|
4181
|
+
return {
|
|
4182
|
+
originalColumnNumber: pos.column,
|
|
4183
|
+
originalFileName: pos.source,
|
|
4184
|
+
originalFunctionName: frame.functionName,
|
|
4185
|
+
originalLineNumber: pos.line,
|
|
4186
|
+
originalScriptCode: scriptCode
|
|
4187
|
+
};
|
|
4188
|
+
};
|
|
4189
|
+
var getSourceMapFromRemoteFile = async (fileName) => {
|
|
4190
|
+
const fileContents = await fetchUrl(fileName);
|
|
4191
|
+
return getSourceMap(fileName, fileContents, "remote");
|
|
4192
|
+
};
|
|
4193
|
+
var getSourceMapFromLocalFile = (fileName) => {
|
|
4194
|
+
const fileContents = readFileSync(fileName, "utf8");
|
|
4195
|
+
return getSourceMap(fileName, fileContents, "local");
|
|
4287
4196
|
};
|
|
4288
4197
|
|
|
4289
|
-
// src/
|
|
4290
|
-
|
|
4198
|
+
// src/error-handling/handle-javascript-exception.ts
|
|
4199
|
+
import { NoReactInternals as NoReactInternals5 } from "remotion/no-react";
|
|
4291
4200
|
|
|
4292
|
-
// src/
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4201
|
+
// src/delay-render-embedded-stack.ts
|
|
4202
|
+
import { NoReactInternals as NoReactInternals4 } from "remotion/no-react";
|
|
4203
|
+
|
|
4204
|
+
// src/parse-browser-error-stack.ts
|
|
4205
|
+
var regexValidFrame_Chrome = /^\s*(at|in)\s.+(:\d+)/;
|
|
4206
|
+
var regexValidFrame_FireFox = /(^|@)\S+:\d+|.+line\s+\d+\s+>\s+(eval|Function).+/;
|
|
4207
|
+
var regexExtractLocation = /\(?(.+?)(?::(\d+))?(?::(\d+))?\)?$/;
|
|
4208
|
+
function extractLocation(token) {
|
|
4209
|
+
const execed = regexExtractLocation.exec(token);
|
|
4210
|
+
if (!execed) {
|
|
4211
|
+
throw new Error("Could not match in extractLocation");
|
|
4212
|
+
}
|
|
4213
|
+
return execed.slice(1).map((v) => {
|
|
4214
|
+
const p = Number(v);
|
|
4215
|
+
if (!isNaN(p)) {
|
|
4216
|
+
return p;
|
|
4217
|
+
}
|
|
4218
|
+
return v;
|
|
4219
|
+
});
|
|
4220
|
+
}
|
|
4221
|
+
var makeStackFrame = ({
|
|
4222
|
+
functionName,
|
|
4223
|
+
fileName,
|
|
4224
|
+
lineNumber,
|
|
4225
|
+
columnNumber
|
|
4312
4226
|
}) => {
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
Log.verbose({ indent, logLevel }, `Combining audio with re-encoding, command: ${command.join(" ")}`);
|
|
4339
|
-
try {
|
|
4340
|
-
const task = callFf({
|
|
4341
|
-
args: command,
|
|
4342
|
-
bin: "ffmpeg",
|
|
4343
|
-
indent,
|
|
4344
|
-
logLevel,
|
|
4345
|
-
binariesDirectory,
|
|
4346
|
-
cancelSignal
|
|
4347
|
-
});
|
|
4348
|
-
task.stderr?.on("data", (data) => {
|
|
4349
|
-
const utf8 = data.toString("utf8");
|
|
4350
|
-
const parsed = parseFfmpegProgress(utf8, fps);
|
|
4351
|
-
if (parsed === undefined) {
|
|
4352
|
-
Log.verbose({ indent, logLevel }, utf8);
|
|
4353
|
-
} else {
|
|
4354
|
-
onProgress(parsed);
|
|
4355
|
-
Log.verbose({ indent, logLevel }, `Encoded ${parsed} audio frames`);
|
|
4227
|
+
if (functionName && functionName.indexOf("Object.") === 0) {
|
|
4228
|
+
functionName = functionName.slice("Object.".length);
|
|
4229
|
+
}
|
|
4230
|
+
if (functionName === "friendlySyntaxErrorLabel" || functionName === "exports.__esModule" || functionName === "<anonymous>" || !functionName) {
|
|
4231
|
+
functionName = null;
|
|
4232
|
+
}
|
|
4233
|
+
return {
|
|
4234
|
+
columnNumber,
|
|
4235
|
+
fileName,
|
|
4236
|
+
functionName,
|
|
4237
|
+
lineNumber
|
|
4238
|
+
};
|
|
4239
|
+
};
|
|
4240
|
+
var parseStack = (stack) => {
|
|
4241
|
+
const frames = stack.filter((e) => regexValidFrame_Chrome.test(e) || regexValidFrame_FireFox.test(e)).map((e) => {
|
|
4242
|
+
if (regexValidFrame_FireFox.test(e)) {
|
|
4243
|
+
let isEval = false;
|
|
4244
|
+
if (/ > (eval|Function)/.test(e)) {
|
|
4245
|
+
e = e.replace(/ line (\d+)(?: > eval line \d+)* > (eval|Function):\d+:\d+/g, ":$1");
|
|
4246
|
+
isEval = true;
|
|
4247
|
+
}
|
|
4248
|
+
const _data = e.split(/[@]/g);
|
|
4249
|
+
const _last = _data.pop();
|
|
4250
|
+
if (!_last) {
|
|
4251
|
+
throw new Error("could not get last");
|
|
4356
4252
|
}
|
|
4253
|
+
const [_fileName, _lineNumber, _columnNumber] = extractLocation(_last);
|
|
4254
|
+
return makeStackFrame({
|
|
4255
|
+
functionName: _data.join("@") || (isEval ? "eval" : null),
|
|
4256
|
+
fileName: _fileName,
|
|
4257
|
+
lineNumber: _lineNumber,
|
|
4258
|
+
columnNumber: _columnNumber
|
|
4259
|
+
});
|
|
4260
|
+
}
|
|
4261
|
+
if (e.indexOf("(eval ") !== -1) {
|
|
4262
|
+
e = e.replace(/(\(eval at [^()]*)|(\),.*$)/g, "");
|
|
4263
|
+
}
|
|
4264
|
+
if (e.indexOf("(at ") !== -1) {
|
|
4265
|
+
e = e.replace(/\(at /, "(");
|
|
4266
|
+
}
|
|
4267
|
+
const data = e.trim().split(/\s+/g).slice(1);
|
|
4268
|
+
const last = data.pop();
|
|
4269
|
+
if (!last) {
|
|
4270
|
+
throw new Error("could not get last");
|
|
4271
|
+
}
|
|
4272
|
+
const [fileName, lineNumber, columnNumber] = extractLocation(last);
|
|
4273
|
+
return makeStackFrame({
|
|
4274
|
+
functionName: data.join(" ") || null,
|
|
4275
|
+
fileName,
|
|
4276
|
+
lineNumber,
|
|
4277
|
+
columnNumber
|
|
4357
4278
|
});
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4279
|
+
});
|
|
4280
|
+
return frames;
|
|
4281
|
+
};
|
|
4282
|
+
|
|
4283
|
+
// src/delay-render-embedded-stack.ts
|
|
4284
|
+
var parseDelayRenderEmbeddedStack = (message) => {
|
|
4285
|
+
const index = message.indexOf(NoReactInternals4.DELAY_RENDER_CALLSTACK_TOKEN);
|
|
4286
|
+
if (index === -1) {
|
|
4287
|
+
return null;
|
|
4364
4288
|
}
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
indent,
|
|
4370
|
-
logLevel,
|
|
4371
|
-
output,
|
|
4372
|
-
chunkDurationInSeconds,
|
|
4373
|
-
addRemotionMetadata,
|
|
4374
|
-
fps,
|
|
4375
|
-
binariesDirectory,
|
|
4376
|
-
cancelSignal,
|
|
4377
|
-
onProgress
|
|
4378
|
-
}) => {
|
|
4379
|
-
const startConcatenating = Date.now();
|
|
4380
|
-
const fileList = files.map((p, i) => {
|
|
4381
|
-
const isLast = i === files.length - 1;
|
|
4382
|
-
const targetStart = i * chunkDurationInSeconds;
|
|
4383
|
-
const endStart = (i + 1) * chunkDurationInSeconds;
|
|
4384
|
-
const startTime = getClosestAlignedTime(targetStart) * 1e6;
|
|
4385
|
-
const endTime = getClosestAlignedTime(endStart) * 1e6;
|
|
4386
|
-
const realDuration = endTime - startTime;
|
|
4387
|
-
let inpoint = 0;
|
|
4388
|
-
if (i > 0) {
|
|
4389
|
-
inpoint = durationOf1Frame * 4;
|
|
4390
|
-
}
|
|
4391
|
-
const outpoint = (i === 0 ? durationOf1Frame * 2 : inpoint) + realDuration - (isLast ? 0 : durationOf1Frame);
|
|
4392
|
-
return [`file '${p}'`, `inpoint ${inpoint}us`, `outpoint ${outpoint}us`].filter(truthy).join(`
|
|
4393
|
-
`);
|
|
4394
|
-
}).join(`
|
|
4395
|
-
`);
|
|
4396
|
-
const fileListTxt = join2(filelistDir, "audio-files.txt");
|
|
4397
|
-
writeFileSync(fileListTxt, fileList);
|
|
4398
|
-
const command = [
|
|
4399
|
-
"-hide_banner",
|
|
4400
|
-
"-f",
|
|
4401
|
-
"concat",
|
|
4402
|
-
"-safe",
|
|
4403
|
-
"0",
|
|
4404
|
-
"-i",
|
|
4405
|
-
fileListTxt,
|
|
4406
|
-
"-c:a",
|
|
4407
|
-
"copy",
|
|
4408
|
-
"-vn",
|
|
4409
|
-
addRemotionMetadata ? `-metadata` : null,
|
|
4410
|
-
addRemotionMetadata ? `comment=Made with Remotion ${VERSION2}` : null,
|
|
4411
|
-
"-y",
|
|
4412
|
-
output
|
|
4413
|
-
];
|
|
4414
|
-
Log.verbose({ indent, logLevel }, `Combining AAC audio seamlessly, command: ${command.join(" ")}`);
|
|
4415
|
-
try {
|
|
4416
|
-
const task = callFf({
|
|
4417
|
-
args: command,
|
|
4418
|
-
bin: "ffmpeg",
|
|
4419
|
-
indent,
|
|
4420
|
-
logLevel,
|
|
4421
|
-
binariesDirectory,
|
|
4422
|
-
cancelSignal
|
|
4423
|
-
});
|
|
4424
|
-
task.stderr?.on("data", (data) => {
|
|
4425
|
-
const utf8 = data.toString("utf8");
|
|
4426
|
-
const parsed = parseFfmpegProgress(utf8, fps);
|
|
4427
|
-
if (parsed !== undefined) {
|
|
4428
|
-
onProgress(parsed);
|
|
4429
|
-
Log.verbose({ indent, logLevel }, `Encoded ${parsed} audio frames`);
|
|
4430
|
-
}
|
|
4431
|
-
});
|
|
4432
|
-
await task;
|
|
4433
|
-
Log.verbose({ indent, logLevel }, `Combined audio seamlessly in ${Date.now() - startConcatenating}ms`);
|
|
4434
|
-
return output;
|
|
4435
|
-
} catch (e) {
|
|
4436
|
-
rmSync2(fileListTxt, { recursive: true });
|
|
4437
|
-
Log.error({ indent, logLevel }, e);
|
|
4438
|
-
throw e;
|
|
4439
|
-
}
|
|
4440
|
-
};
|
|
4441
|
-
var createCombinedAudio = ({
|
|
4442
|
-
seamless,
|
|
4443
|
-
filelistDir,
|
|
4444
|
-
files,
|
|
4445
|
-
indent,
|
|
4446
|
-
logLevel,
|
|
4447
|
-
audioBitrate,
|
|
4448
|
-
resolvedAudioCodec,
|
|
4449
|
-
output,
|
|
4450
|
-
chunkDurationInSeconds,
|
|
4451
|
-
addRemotionMetadata,
|
|
4452
|
-
binariesDirectory,
|
|
4453
|
-
fps,
|
|
4454
|
-
cancelSignal,
|
|
4455
|
-
onProgress
|
|
4456
|
-
}) => {
|
|
4457
|
-
if (seamless) {
|
|
4458
|
-
return combineAudioSeamlessly({
|
|
4459
|
-
filelistDir,
|
|
4460
|
-
files,
|
|
4461
|
-
indent,
|
|
4462
|
-
logLevel,
|
|
4463
|
-
output,
|
|
4464
|
-
chunkDurationInSeconds,
|
|
4465
|
-
addRemotionMetadata,
|
|
4466
|
-
binariesDirectory,
|
|
4467
|
-
fps,
|
|
4468
|
-
cancelSignal,
|
|
4469
|
-
onProgress
|
|
4470
|
-
});
|
|
4471
|
-
}
|
|
4472
|
-
return encodeAudio({
|
|
4473
|
-
filelistDir,
|
|
4474
|
-
files,
|
|
4475
|
-
resolvedAudioCodec,
|
|
4476
|
-
audioBitrate,
|
|
4477
|
-
output,
|
|
4478
|
-
indent,
|
|
4479
|
-
logLevel,
|
|
4480
|
-
addRemotionMetadata,
|
|
4481
|
-
binariesDirectory,
|
|
4482
|
-
fps,
|
|
4483
|
-
cancelSignal,
|
|
4484
|
-
onProgress
|
|
4485
|
-
});
|
|
4289
|
+
const msg = message.substring(index + NoReactInternals4.DELAY_RENDER_CALLSTACK_TOKEN.length).trim();
|
|
4290
|
+
const parsed = parseStack(msg.split(`
|
|
4291
|
+
`));
|
|
4292
|
+
return parsed;
|
|
4486
4293
|
};
|
|
4487
4294
|
|
|
4488
|
-
// src/
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4295
|
+
// src/error-handling/symbolicateable-error.ts
|
|
4296
|
+
class SymbolicateableError extends Error {
|
|
4297
|
+
stackFrame;
|
|
4298
|
+
delayRenderCall;
|
|
4299
|
+
frame;
|
|
4300
|
+
chunk;
|
|
4301
|
+
constructor({
|
|
4302
|
+
message,
|
|
4303
|
+
stack,
|
|
4304
|
+
stackFrame,
|
|
4305
|
+
frame,
|
|
4306
|
+
name,
|
|
4307
|
+
chunk
|
|
4308
|
+
}) {
|
|
4309
|
+
super(message);
|
|
4310
|
+
this.stack = stack;
|
|
4311
|
+
this.stackFrame = stackFrame;
|
|
4312
|
+
this.frame = frame;
|
|
4313
|
+
this.chunk = chunk;
|
|
4314
|
+
this.name = name;
|
|
4315
|
+
this.delayRenderCall = stack ? parseDelayRenderEmbeddedStack(stack) : null;
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4492
4318
|
|
|
4493
|
-
// src/
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4319
|
+
// src/error-handling/handle-javascript-exception.ts
|
|
4320
|
+
class ErrorWithStackFrame extends Error {
|
|
4321
|
+
symbolicatedStackFrames;
|
|
4322
|
+
frame;
|
|
4323
|
+
chunk;
|
|
4324
|
+
name;
|
|
4325
|
+
delayRenderCall;
|
|
4326
|
+
constructor({
|
|
4327
|
+
message,
|
|
4328
|
+
symbolicatedStackFrames,
|
|
4329
|
+
frame,
|
|
4330
|
+
name,
|
|
4331
|
+
delayRenderCall,
|
|
4332
|
+
stack,
|
|
4333
|
+
chunk
|
|
4334
|
+
}) {
|
|
4335
|
+
super(message);
|
|
4336
|
+
this.symbolicatedStackFrames = symbolicatedStackFrames;
|
|
4337
|
+
this.frame = frame;
|
|
4338
|
+
this.chunk = chunk;
|
|
4339
|
+
this.name = name;
|
|
4340
|
+
this.delayRenderCall = delayRenderCall;
|
|
4341
|
+
this.stack = stack;
|
|
4497
4342
|
}
|
|
4498
|
-
|
|
4499
|
-
|
|
4343
|
+
}
|
|
4344
|
+
var cleanUpErrorMessage = (exception) => {
|
|
4345
|
+
let errorMessage = exception.exceptionDetails.exception?.description;
|
|
4346
|
+
if (!errorMessage) {
|
|
4347
|
+
return null;
|
|
4500
4348
|
}
|
|
4501
|
-
|
|
4502
|
-
}
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
filelistDir,
|
|
4509
|
-
numberOfGifLoops,
|
|
4510
|
-
output,
|
|
4511
|
-
indent,
|
|
4512
|
-
logLevel,
|
|
4513
|
-
onProgress,
|
|
4514
|
-
files,
|
|
4515
|
-
addRemotionMetadata,
|
|
4516
|
-
binariesDirectory,
|
|
4517
|
-
cancelSignal
|
|
4518
|
-
}) => {
|
|
4519
|
-
const fileList = files.map((p) => `file '${p}'`).join(`
|
|
4349
|
+
const errorType = exception.exceptionDetails.exception?.className;
|
|
4350
|
+
const prefix = `${errorType}: `;
|
|
4351
|
+
if (errorMessage.startsWith(prefix)) {
|
|
4352
|
+
errorMessage = errorMessage.substring(prefix.length);
|
|
4353
|
+
}
|
|
4354
|
+
const frames = exception.exceptionDetails.stackTrace?.callFrames.length ?? 0;
|
|
4355
|
+
const split = errorMessage.split(`
|
|
4520
4356
|
`);
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
"-f",
|
|
4529
|
-
"concat",
|
|
4530
|
-
"-safe",
|
|
4531
|
-
"0",
|
|
4532
|
-
"-i",
|
|
4533
|
-
fileListTxt,
|
|
4534
|
-
numberOfGifLoops === null ? null : "-loop",
|
|
4535
|
-
numberOfGifLoops === null ? null : convertNumberOfGifLoopsToFfmpegSyntax(numberOfGifLoops),
|
|
4536
|
-
codec === "gif" ? "-filter_complex" : null,
|
|
4537
|
-
codec === "gif" ? "split[v],palettegen,[v]paletteuse" : null,
|
|
4538
|
-
"-an",
|
|
4539
|
-
"-c:v",
|
|
4540
|
-
encoder,
|
|
4541
|
-
codec === "h265" ? "-tag:v" : null,
|
|
4542
|
-
codec === "h265" ? "hvc1" : null,
|
|
4543
|
-
addRemotionMetadata ? `-metadata` : null,
|
|
4544
|
-
addRemotionMetadata ? `comment=Made with Remotion ${VERSION3}` : null,
|
|
4545
|
-
"-y",
|
|
4546
|
-
output
|
|
4547
|
-
].filter(truthy);
|
|
4548
|
-
const doesReencode = encoder !== "copy";
|
|
4549
|
-
const startTime = Date.now();
|
|
4550
|
-
Log.verbose({ indent, logLevel }, `Combining video ${doesReencode ? "with reencoding" : "without reencoding"}, command: ${command.join(" ")}`);
|
|
4551
|
-
try {
|
|
4552
|
-
const task = callFf({
|
|
4553
|
-
args: command,
|
|
4554
|
-
bin: "ffmpeg",
|
|
4555
|
-
indent,
|
|
4556
|
-
logLevel,
|
|
4557
|
-
binariesDirectory,
|
|
4558
|
-
cancelSignal
|
|
4559
|
-
});
|
|
4560
|
-
task.stderr?.on("data", (data) => {
|
|
4561
|
-
const parsed = parseFfmpegProgress(data.toString("utf8"), fps);
|
|
4562
|
-
if (parsed === undefined) {
|
|
4563
|
-
Log.verbose({ indent, logLevel }, data.toString("utf8"));
|
|
4564
|
-
} else {
|
|
4565
|
-
Log.verbose({ indent, logLevel }, `Encoded ${parsed} video frames`);
|
|
4566
|
-
onProgress(parsed);
|
|
4567
|
-
}
|
|
4568
|
-
});
|
|
4569
|
-
await task;
|
|
4570
|
-
Log.verbose({ indent, logLevel }, `Finished combining video in ${Date.now() - startTime}ms`);
|
|
4571
|
-
return output;
|
|
4572
|
-
} catch (e) {
|
|
4573
|
-
rmSync3(fileListTxt, { recursive: true });
|
|
4574
|
-
throw e;
|
|
4357
|
+
return split.slice(0, Math.max(1, split.length - frames)).join(`
|
|
4358
|
+
`);
|
|
4359
|
+
};
|
|
4360
|
+
var removeDelayRenderStack = (message) => {
|
|
4361
|
+
const index = message.indexOf(NoReactInternals5.DELAY_RENDER_CALLSTACK_TOKEN);
|
|
4362
|
+
if (index === -1) {
|
|
4363
|
+
return message;
|
|
4575
4364
|
}
|
|
4365
|
+
return message.substring(0, index);
|
|
4576
4366
|
};
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4367
|
+
var callFrameToStackFrame = (callFrame) => {
|
|
4368
|
+
return {
|
|
4369
|
+
columnNumber: callFrame.columnNumber,
|
|
4370
|
+
fileName: callFrame.url,
|
|
4371
|
+
functionName: callFrame.functionName,
|
|
4372
|
+
lineNumber: callFrame.lineNumber
|
|
4373
|
+
};
|
|
4582
4374
|
};
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4375
|
+
var handleJavascriptException = ({
|
|
4376
|
+
page,
|
|
4377
|
+
onError,
|
|
4378
|
+
frame
|
|
4379
|
+
}) => {
|
|
4380
|
+
const client = page._client();
|
|
4381
|
+
const handler = (exception) => {
|
|
4382
|
+
const rawErrorMessage = exception.exceptionDetails.exception?.description;
|
|
4383
|
+
const cleanErrorMessage = cleanUpErrorMessage(exception);
|
|
4384
|
+
if (!cleanErrorMessage) {
|
|
4385
|
+
console.error(exception);
|
|
4386
|
+
const err = new Error(rawErrorMessage);
|
|
4387
|
+
err.stack = rawErrorMessage;
|
|
4388
|
+
onError(err);
|
|
4389
|
+
return;
|
|
4390
|
+
}
|
|
4391
|
+
if (!exception.exceptionDetails.stackTrace) {
|
|
4392
|
+
const err = new Error(removeDelayRenderStack(cleanErrorMessage));
|
|
4393
|
+
err.stack = rawErrorMessage;
|
|
4394
|
+
onError(err);
|
|
4395
|
+
return;
|
|
4396
|
+
}
|
|
4397
|
+
const errorType = exception.exceptionDetails.exception?.className;
|
|
4398
|
+
const symbolicatedErr = new SymbolicateableError({
|
|
4399
|
+
message: removeDelayRenderStack(cleanErrorMessage),
|
|
4400
|
+
stackFrame: exception.exceptionDetails.stackTrace.callFrames.map((f) => callFrameToStackFrame(f)),
|
|
4401
|
+
frame,
|
|
4402
|
+
name: errorType,
|
|
4403
|
+
stack: exception.exceptionDetails.exception?.description,
|
|
4404
|
+
chunk: null
|
|
4405
|
+
});
|
|
4406
|
+
onError(symbolicatedErr);
|
|
4407
|
+
};
|
|
4408
|
+
client.on("Runtime.exceptionThrown", handler);
|
|
4409
|
+
return () => {
|
|
4410
|
+
client.off("Runtime.exceptionThrown", handler);
|
|
4411
|
+
return Promise.resolve();
|
|
4412
|
+
};
|
|
4413
|
+
};
|
|
4414
|
+
|
|
4415
|
+
// src/error-handling/symbolicate-error.ts
|
|
4416
|
+
var symbolicateError = async (symbolicateableError) => {
|
|
4417
|
+
const { delayRenderCall, stackFrame } = symbolicateableError;
|
|
4418
|
+
const [mainErrorFrames, delayRenderFrames] = await Promise.all([
|
|
4419
|
+
stackFrame ? symbolicateStackTraceFromRemoteFrames(stackFrame) : null,
|
|
4420
|
+
delayRenderCall ? symbolicateStackTraceFromRemoteFrames(delayRenderCall) : null
|
|
4421
|
+
].filter(truthy));
|
|
4422
|
+
const symbolicatedErr = new ErrorWithStackFrame({
|
|
4423
|
+
message: symbolicateableError.message,
|
|
4424
|
+
symbolicatedStackFrames: mainErrorFrames,
|
|
4425
|
+
frame: symbolicateableError.frame,
|
|
4426
|
+
name: symbolicateableError.name,
|
|
4427
|
+
delayRenderCall: delayRenderFrames,
|
|
4428
|
+
stack: symbolicateableError.stack,
|
|
4429
|
+
chunk: symbolicateableError.chunk
|
|
4430
|
+
});
|
|
4431
|
+
return symbolicatedErr;
|
|
4432
|
+
};
|
|
4433
|
+
|
|
4434
|
+
// src/file-extensions.ts
|
|
4435
|
+
var defaultFileExtensionMap = {
|
|
4436
|
+
"h264-mkv": {
|
|
4437
|
+
default: "mkv",
|
|
4438
|
+
forAudioCodec: {
|
|
4439
|
+
"pcm-16": { possible: ["mkv"], default: "mkv" },
|
|
4440
|
+
mp3: { possible: ["mkv"], default: "mkv" }
|
|
4441
|
+
}
|
|
4592
4442
|
},
|
|
4593
4443
|
"h264-ts": {
|
|
4594
4444
|
default: "ts",
|
|
@@ -4665,1385 +4515,768 @@ var defaultFileExtensionMap = {
|
|
|
4665
4515
|
}
|
|
4666
4516
|
};
|
|
4667
4517
|
|
|
4668
|
-
// src/
|
|
4669
|
-
var
|
|
4670
|
-
if (
|
|
4671
|
-
|
|
4672
|
-
}
|
|
4673
|
-
const map = defaultFileExtensionMap[codec];
|
|
4674
|
-
if (audioCodec === null) {
|
|
4675
|
-
return map.default;
|
|
4518
|
+
// src/frame-range.ts
|
|
4519
|
+
var validateFrameRange = (frameRange) => {
|
|
4520
|
+
if (frameRange === null) {
|
|
4521
|
+
return;
|
|
4676
4522
|
}
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4523
|
+
if (typeof frameRange === "number") {
|
|
4524
|
+
if (frameRange < 0) {
|
|
4525
|
+
throw new TypeError("Frame must be a non-negative number, got " + frameRange);
|
|
4526
|
+
}
|
|
4527
|
+
if (!Number.isFinite(frameRange)) {
|
|
4528
|
+
throw new TypeError("Frame must be a finite number, got " + frameRange);
|
|
4529
|
+
}
|
|
4530
|
+
if (!Number.isInteger(frameRange)) {
|
|
4531
|
+
throw new Error(`Frame must be an integer, but got a float (${frameRange})`);
|
|
4532
|
+
}
|
|
4533
|
+
return;
|
|
4680
4534
|
}
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
fileExtMap.default,
|
|
4692
|
-
...possibleExtensionsForAudioCodec.flat(1)
|
|
4693
|
-
];
|
|
4694
|
-
for (const extension of allPossibleExtensions) {
|
|
4695
|
-
if (!map[extension]) {
|
|
4696
|
-
map[extension] = [];
|
|
4535
|
+
if (Array.isArray(frameRange)) {
|
|
4536
|
+
if (frameRange.length !== 2) {
|
|
4537
|
+
throw new TypeError("Frame range must be a tuple, got an array with length " + frameRange.length);
|
|
4538
|
+
}
|
|
4539
|
+
for (const value of frameRange) {
|
|
4540
|
+
if (typeof value !== "number") {
|
|
4541
|
+
throw new Error(`Each value of frame range must be a number, but got ${typeof value} (${JSON.stringify(value)})`);
|
|
4542
|
+
}
|
|
4543
|
+
if (!Number.isFinite(value)) {
|
|
4544
|
+
throw new TypeError("Each value of frame range must be finite, but got " + value);
|
|
4697
4545
|
}
|
|
4698
|
-
if (!
|
|
4699
|
-
|
|
4546
|
+
if (!Number.isInteger(value)) {
|
|
4547
|
+
throw new Error(`Each value of frame range must be an integer, but got a float (${value})`);
|
|
4548
|
+
}
|
|
4549
|
+
if (value < 0) {
|
|
4550
|
+
throw new Error(`Each value of frame range must be non-negative, but got ${value}`);
|
|
4700
4551
|
}
|
|
4701
4552
|
}
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
hevc: "h265",
|
|
4710
|
-
m4a: "aac",
|
|
4711
|
-
m4b: "aac",
|
|
4712
|
-
mkv: "h264-mkv",
|
|
4713
|
-
mov: "prores",
|
|
4714
|
-
mp3: "mp3",
|
|
4715
|
-
mp4: "h264",
|
|
4716
|
-
mpeg: "aac",
|
|
4717
|
-
mpg: "aac",
|
|
4718
|
-
mxf: "prores",
|
|
4719
|
-
wav: "wav",
|
|
4720
|
-
webm: "vp8",
|
|
4721
|
-
ts: "h264-ts"
|
|
4553
|
+
const [first, second] = frameRange;
|
|
4554
|
+
if (second < first) {
|
|
4555
|
+
throw new Error("The second value of frame range must be not smaller than the first one, but got " + frameRange.join("-"));
|
|
4556
|
+
}
|
|
4557
|
+
return;
|
|
4558
|
+
}
|
|
4559
|
+
throw new TypeError("Frame range must be a number or a tuple of numbers, but got object of type " + typeof frameRange);
|
|
4722
4560
|
};
|
|
4723
4561
|
|
|
4724
|
-
// src/
|
|
4725
|
-
import {
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4562
|
+
// src/get-compositions.ts
|
|
4563
|
+
import { NoReactInternals as NoReactInternals8 } from "remotion/no-react";
|
|
4564
|
+
|
|
4565
|
+
// src/to-megabytes.ts
|
|
4566
|
+
function toMegabytes(bytes) {
|
|
4567
|
+
const mb = bytes / 1024 / 1024;
|
|
4568
|
+
return `${Math.round(mb * 10) / 10} Mb`;
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
// src/browser/browser-download-progress-bar.ts
|
|
4572
|
+
var defaultBrowserDownloadProgress = ({
|
|
4573
|
+
indent,
|
|
4574
|
+
logLevel,
|
|
4575
|
+
api
|
|
4576
|
+
}) => ({ chromeMode }) => {
|
|
4577
|
+
if (chromeMode === "chrome-for-testing") {
|
|
4578
|
+
Log.info({ indent, logLevel }, "Downloading Chrome for Testing https://www.remotion.dev/chrome-for-testing");
|
|
4579
|
+
} else {
|
|
4580
|
+
Log.info({ indent, logLevel }, "Downloading Chrome Headless Shell https://www.remotion.dev/chrome-headless-shell");
|
|
4581
|
+
}
|
|
4582
|
+
Log.info({ indent, logLevel }, `Customize this behavior by adding a onBrowserDownload function to ${api}.`);
|
|
4583
|
+
let lastProgress = 0;
|
|
4584
|
+
return {
|
|
4585
|
+
onProgress: (progress) => {
|
|
4586
|
+
if (progress.downloadedBytes > lastProgress + 1e7 || progress.percent === 1) {
|
|
4587
|
+
lastProgress = progress.downloadedBytes;
|
|
4588
|
+
if (chromeMode === "chrome-for-testing") {
|
|
4589
|
+
Log.info({ indent, logLevel }, `Downloading Chrome for Testing - ${toMegabytes(progress.downloadedBytes)}/${toMegabytes(progress.totalSizeInBytes)}`);
|
|
4590
|
+
} else {
|
|
4591
|
+
Log.info({ indent, logLevel }, `Downloading Chrome Headless Shell - ${toMegabytes(progress.downloadedBytes)}/${toMegabytes(progress.totalSizeInBytes)}`);
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
},
|
|
4595
|
+
version: null
|
|
4730
4596
|
};
|
|
4731
|
-
Object.keys(metadata).forEach((key) => {
|
|
4732
|
-
const lowercaseKey = key.toLowerCase();
|
|
4733
|
-
if (lowercaseKey === "comment") {
|
|
4734
|
-
newMetadata[lowercaseKey] = `${defaultComment}; ${metadata[key]}`;
|
|
4735
|
-
} else {
|
|
4736
|
-
newMetadata[lowercaseKey] = metadata[key];
|
|
4737
|
-
}
|
|
4738
|
-
});
|
|
4739
|
-
const metadataArgs = Object.entries(newMetadata).map(([key, value]) => ["-metadata", `${key}=${value}`]);
|
|
4740
|
-
return metadataArgs.flat(1);
|
|
4741
4597
|
};
|
|
4742
4598
|
|
|
4743
|
-
// src/
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4599
|
+
// src/open-browser.ts
|
|
4600
|
+
import fs9 from "node:fs";
|
|
4601
|
+
import os3 from "node:os";
|
|
4602
|
+
import path9 from "node:path";
|
|
4603
|
+
|
|
4604
|
+
// src/browser/Launcher.ts
|
|
4605
|
+
var launchChrome = async ({
|
|
4606
|
+
args,
|
|
4607
|
+
executablePath,
|
|
4608
|
+
defaultViewport,
|
|
4748
4609
|
indent,
|
|
4749
4610
|
logLevel,
|
|
4750
|
-
|
|
4751
|
-
binariesDirectory,
|
|
4752
|
-
fps,
|
|
4753
|
-
cancelSignal,
|
|
4754
|
-
addFaststart,
|
|
4755
|
-
metadata
|
|
4611
|
+
userDataDir
|
|
4756
4612
|
}) => {
|
|
4757
|
-
const
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
audioOutput,
|
|
4765
|
-
videoOutput ? "-c:v" : null,
|
|
4766
|
-
videoOutput ? "copy" : null,
|
|
4767
|
-
audioOutput ? "-c:a" : null,
|
|
4768
|
-
audioOutput ? "copy" : null,
|
|
4769
|
-
addFaststart ? "-movflags" : null,
|
|
4770
|
-
addFaststart ? "faststart" : null,
|
|
4771
|
-
...makeMetadataArgs(metadata ?? {}),
|
|
4772
|
-
"-y",
|
|
4773
|
-
output
|
|
4774
|
-
].filter(truthy);
|
|
4775
|
-
Log.verbose({ indent, logLevel }, "Combining command: ", command);
|
|
4776
|
-
const task = callFf({
|
|
4777
|
-
bin: "ffmpeg",
|
|
4778
|
-
args: command,
|
|
4779
|
-
indent,
|
|
4613
|
+
const timeout = 60000;
|
|
4614
|
+
const browser = await HeadlessBrowser.create({
|
|
4615
|
+
defaultViewport,
|
|
4616
|
+
args,
|
|
4617
|
+
executablePath,
|
|
4618
|
+
timeout,
|
|
4619
|
+
userDataDir,
|
|
4780
4620
|
logLevel,
|
|
4781
|
-
|
|
4782
|
-
cancelSignal
|
|
4621
|
+
indent
|
|
4783
4622
|
});
|
|
4784
|
-
task.stderr?.on("data", (data) => {
|
|
4785
|
-
const utf8 = data.toString("utf8");
|
|
4786
|
-
const parsed = parseFfmpegProgress(utf8, fps);
|
|
4787
|
-
if (parsed === undefined) {
|
|
4788
|
-
if (!utf8.includes("Estimating duration from bitrate, this may be inaccurate")) {
|
|
4789
|
-
Log.verbose({ indent, logLevel }, utf8);
|
|
4790
|
-
}
|
|
4791
|
-
} else {
|
|
4792
|
-
Log.verbose({ indent, logLevel }, `Combined ${parsed} frames`);
|
|
4793
|
-
onProgress(parsed);
|
|
4794
|
-
}
|
|
4795
|
-
});
|
|
4796
|
-
await task;
|
|
4797
|
-
Log.verbose({ indent, logLevel }, `Muxing done in ${Date.now() - startTime}ms`);
|
|
4798
|
-
};
|
|
4799
|
-
|
|
4800
|
-
// src/combine-videos.ts
|
|
4801
|
-
var codecSupportsFastStart = {
|
|
4802
|
-
"h264-mkv": false,
|
|
4803
|
-
"h264-ts": false,
|
|
4804
|
-
h264: true,
|
|
4805
|
-
h265: true,
|
|
4806
|
-
aac: false,
|
|
4807
|
-
gif: false,
|
|
4808
|
-
mp3: false,
|
|
4809
|
-
prores: false,
|
|
4810
|
-
vp8: false,
|
|
4811
|
-
vp9: false,
|
|
4812
|
-
wav: false
|
|
4813
|
-
};
|
|
4814
|
-
var combineChunks = async ({
|
|
4815
|
-
files,
|
|
4816
|
-
filelistDir,
|
|
4817
|
-
output,
|
|
4818
|
-
onProgress,
|
|
4819
|
-
numberOfFrames,
|
|
4820
|
-
codec,
|
|
4821
|
-
fps,
|
|
4822
|
-
numberOfGifLoops,
|
|
4823
|
-
resolvedAudioCodec,
|
|
4824
|
-
audioBitrate,
|
|
4825
|
-
indent,
|
|
4826
|
-
logLevel,
|
|
4827
|
-
chunkDurationInSeconds,
|
|
4828
|
-
binariesDirectory,
|
|
4829
|
-
cancelSignal,
|
|
4830
|
-
seamlessAudio,
|
|
4831
|
-
seamlessVideo,
|
|
4832
|
-
muted,
|
|
4833
|
-
metadata
|
|
4834
|
-
}) => {
|
|
4835
|
-
const shouldCreateAudio = resolvedAudioCodec !== null && !muted;
|
|
4836
|
-
const shouldCreateVideo = !isAudioCodec(codec);
|
|
4837
|
-
const videoOutput = shouldCreateVideo ? join4(filelistDir, `video.${getFileExtensionFromCodec(codec, resolvedAudioCodec)}`) : null;
|
|
4838
|
-
const audioOutput = shouldCreateAudio ? join4(filelistDir, `audio.${getExtensionFromAudioCodec(resolvedAudioCodec)}`) : null;
|
|
4839
|
-
const audioFiles = files.filter((f) => f.endsWith("audio"));
|
|
4840
|
-
const videoFiles = files.filter((f) => f.endsWith("video"));
|
|
4841
|
-
let concatenatedAudio = 0;
|
|
4842
|
-
let concatenatedVideo = 0;
|
|
4843
|
-
let muxing = 0;
|
|
4844
|
-
const updateProgress = () => {
|
|
4845
|
-
const totalFrames = (shouldCreateAudio ? numberOfFrames : 0) + (shouldCreateVideo ? numberOfFrames : 0) + numberOfFrames;
|
|
4846
|
-
const actualProgress = concatenatedAudio + concatenatedVideo + muxing;
|
|
4847
|
-
onProgress(actualProgress / totalFrames * numberOfFrames);
|
|
4848
|
-
};
|
|
4849
|
-
Log.verbose({ indent, logLevel }, `Combining chunks, audio = ${shouldCreateAudio === false ? "no" : seamlessAudio ? "seamlessly" : "normally"}, video = ${shouldCreateVideo === false ? "no" : seamlessVideo ? "seamlessly" : "normally"}`);
|
|
4850
|
-
await Promise.all([
|
|
4851
|
-
shouldCreateAudio && audioOutput ? createCombinedAudio({
|
|
4852
|
-
audioBitrate,
|
|
4853
|
-
filelistDir,
|
|
4854
|
-
files: audioFiles,
|
|
4855
|
-
indent,
|
|
4856
|
-
logLevel,
|
|
4857
|
-
output: audioOutput,
|
|
4858
|
-
resolvedAudioCodec,
|
|
4859
|
-
seamless: seamlessAudio,
|
|
4860
|
-
chunkDurationInSeconds,
|
|
4861
|
-
addRemotionMetadata: !shouldCreateVideo,
|
|
4862
|
-
binariesDirectory,
|
|
4863
|
-
fps,
|
|
4864
|
-
cancelSignal,
|
|
4865
|
-
onProgress: (frames) => {
|
|
4866
|
-
concatenatedAudio = frames;
|
|
4867
|
-
updateProgress();
|
|
4868
|
-
}
|
|
4869
|
-
}) : null,
|
|
4870
|
-
shouldCreateVideo && !seamlessVideo && videoOutput ? combineVideoStreams({
|
|
4871
|
-
codec,
|
|
4872
|
-
filelistDir,
|
|
4873
|
-
fps,
|
|
4874
|
-
indent,
|
|
4875
|
-
logLevel,
|
|
4876
|
-
numberOfGifLoops,
|
|
4877
|
-
output: videoOutput,
|
|
4878
|
-
files: videoFiles,
|
|
4879
|
-
addRemotionMetadata: !shouldCreateAudio,
|
|
4880
|
-
binariesDirectory,
|
|
4881
|
-
cancelSignal,
|
|
4882
|
-
onProgress: (frames) => {
|
|
4883
|
-
concatenatedVideo = frames;
|
|
4884
|
-
updateProgress();
|
|
4885
|
-
}
|
|
4886
|
-
}) : null
|
|
4887
|
-
].filter(truthy));
|
|
4888
4623
|
try {
|
|
4889
|
-
await
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
updateProgress();
|
|
4896
|
-
},
|
|
4897
|
-
output,
|
|
4898
|
-
videoOutput: seamlessVideo ? combineVideoStreamsSeamlessly({ files: videoFiles }) : videoOutput,
|
|
4899
|
-
binariesDirectory,
|
|
4900
|
-
fps,
|
|
4901
|
-
cancelSignal,
|
|
4902
|
-
addFaststart: codecSupportsFastStart[codec],
|
|
4903
|
-
metadata
|
|
4904
|
-
});
|
|
4905
|
-
onProgress(numberOfFrames);
|
|
4906
|
-
rmSync4(filelistDir, { recursive: true });
|
|
4907
|
-
} catch (err) {
|
|
4908
|
-
rmSync4(filelistDir, { recursive: true });
|
|
4909
|
-
throw err;
|
|
4624
|
+
await browser.waitForTarget((t) => {
|
|
4625
|
+
return t.type() === "page";
|
|
4626
|
+
}, { timeout });
|
|
4627
|
+
} catch (error) {
|
|
4628
|
+
await browser.close({ silent: false });
|
|
4629
|
+
throw error;
|
|
4910
4630
|
}
|
|
4631
|
+
return browser;
|
|
4911
4632
|
};
|
|
4912
4633
|
|
|
4913
|
-
// src/
|
|
4914
|
-
|
|
4915
|
-
frame,
|
|
4916
|
-
durationInFrames
|
|
4917
|
-
}) => {
|
|
4918
|
-
return frame < 0 ? durationInFrames - frame : frame;
|
|
4919
|
-
};
|
|
4634
|
+
// src/ensure-browser.ts
|
|
4635
|
+
import fs7 from "fs";
|
|
4920
4636
|
|
|
4921
|
-
// src/
|
|
4922
|
-
import
|
|
4923
|
-
import
|
|
4924
|
-
import
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4637
|
+
// src/browser/BrowserFetcher.ts
|
|
4638
|
+
import * as fs6 from "node:fs";
|
|
4639
|
+
import * as os2 from "node:os";
|
|
4640
|
+
import * as path8 from "node:path";
|
|
4641
|
+
import extractZip from "extract-zip";
|
|
4642
|
+
import { promisify } from "node:util";
|
|
4643
|
+
|
|
4644
|
+
// src/browser/get-download-destination.ts
|
|
4645
|
+
import fs5 from "node:fs";
|
|
4646
|
+
import path7 from "node:path";
|
|
4647
|
+
var getDownloadsCacheDir = () => {
|
|
4648
|
+
const cwd = process.cwd();
|
|
4649
|
+
let dir = cwd;
|
|
4928
4650
|
for (;; ) {
|
|
4929
|
-
|
|
4930
|
-
|
|
4651
|
+
try {
|
|
4652
|
+
if (fs5.statSync(path7.join(dir, "package.json")).isFile()) {
|
|
4653
|
+
break;
|
|
4654
|
+
}
|
|
4655
|
+
} catch (e) {
|
|
4656
|
+
}
|
|
4657
|
+
const parent = path7.dirname(dir);
|
|
4658
|
+
if (dir === parent) {
|
|
4659
|
+
dir = undefined;
|
|
4931
4660
|
break;
|
|
4932
4661
|
}
|
|
4933
|
-
|
|
4662
|
+
dir = parent;
|
|
4934
4663
|
}
|
|
4935
|
-
if (!
|
|
4936
|
-
return
|
|
4664
|
+
if (!dir) {
|
|
4665
|
+
return path7.resolve(cwd, ".remotion");
|
|
4937
4666
|
}
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
var getSourceMapFromRemoteUrl = async (url) => {
|
|
4941
|
-
if (!url.endsWith(".js.map")) {
|
|
4942
|
-
throw new Error(`The URL ${url} does not seem to be a valid source map URL.`);
|
|
4667
|
+
if (process.versions.pnp === "1") {
|
|
4668
|
+
return path7.resolve(dir, ".pnp/.remotion");
|
|
4943
4669
|
}
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
};
|
|
4947
|
-
var getSourceMap = (filePath, fileContents, type) => {
|
|
4948
|
-
const sm = extractSourceMapUrl(fileContents);
|
|
4949
|
-
if (sm === null) {
|
|
4950
|
-
return Promise.resolve(null);
|
|
4670
|
+
if (process.versions.pnp === "3") {
|
|
4671
|
+
return path7.resolve(dir, ".yarn/.remotion");
|
|
4951
4672
|
}
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
}
|
|
4673
|
+
return path7.resolve(dir, "node_modules/.remotion");
|
|
4674
|
+
};
|
|
4675
|
+
|
|
4676
|
+
// src/browser/BrowserFetcher.ts
|
|
4677
|
+
var TESTED_VERSION = "133.0.6943.0";
|
|
4678
|
+
var PLAYWRIGHT_VERSION = "1155";
|
|
4679
|
+
function getChromeDownloadUrl({
|
|
4680
|
+
platform: platform2,
|
|
4681
|
+
version,
|
|
4682
|
+
chromeMode
|
|
4683
|
+
}) {
|
|
4684
|
+
if (platform2 === "linux-arm64") {
|
|
4685
|
+
return `https://playwright.azureedge.net/builds/chromium/${version ?? PLAYWRIGHT_VERSION}/chromium-headless-shell-linux-arm64.zip`;
|
|
4965
4686
|
}
|
|
4966
|
-
if (
|
|
4967
|
-
|
|
4968
|
-
return Promise.resolve(new SourceMapConsumer(readFileSync(newFilePath, "utf8")));
|
|
4687
|
+
if (chromeMode === "headless-shell") {
|
|
4688
|
+
return `https://storage.googleapis.com/chrome-for-testing-public/${version ?? TESTED_VERSION}/${platform2}/chrome-headless-shell-${platform2}.zip`;
|
|
4969
4689
|
}
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
res.on("data", (d) => {
|
|
4979
|
-
downloaded += d;
|
|
4980
|
-
});
|
|
4981
|
-
res.on("end", () => {
|
|
4982
|
-
resolve(downloaded);
|
|
4690
|
+
return `https://storage.googleapis.com/chrome-for-testing-public/${version ?? TESTED_VERSION}/${platform2}/chrome-${platform2}.zip`;
|
|
4691
|
+
}
|
|
4692
|
+
var mkdirAsync = fs6.promises.mkdir;
|
|
4693
|
+
var unlinkAsync = promisify(fs6.unlink.bind(fs6));
|
|
4694
|
+
function existsAsync(filePath) {
|
|
4695
|
+
return new Promise((resolve2) => {
|
|
4696
|
+
fs6.access(filePath, (err) => {
|
|
4697
|
+
return resolve2(!err);
|
|
4983
4698
|
});
|
|
4984
|
-
res.on("error", (err) => reject(err));
|
|
4985
4699
|
});
|
|
4986
|
-
};
|
|
4987
|
-
function getLinesAround(line, count, lines) {
|
|
4988
|
-
const result = [];
|
|
4989
|
-
for (let index = Math.max(0, line - 1 - count) + 1;index <= Math.min(lines.length - 1, line - 1 + count); ++index) {
|
|
4990
|
-
result.push({
|
|
4991
|
-
lineNumber: index + 1,
|
|
4992
|
-
content: lines[index],
|
|
4993
|
-
highlight: index + 1 === line
|
|
4994
|
-
});
|
|
4995
|
-
}
|
|
4996
|
-
return result;
|
|
4997
4700
|
}
|
|
4998
|
-
var
|
|
4999
|
-
const
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
4701
|
+
var getPlatform = () => {
|
|
4702
|
+
const platform2 = os2.platform();
|
|
4703
|
+
switch (platform2) {
|
|
4704
|
+
case "darwin":
|
|
4705
|
+
return os2.arch() === "arm64" ? "mac-arm64" : "mac-x64";
|
|
4706
|
+
case "linux":
|
|
4707
|
+
return os2.arch() === "arm64" ? "linux-arm64" : "linux64";
|
|
4708
|
+
case "win32":
|
|
4709
|
+
return "win64";
|
|
4710
|
+
default:
|
|
4711
|
+
throw new Error("Unsupported platform: " + platform2);
|
|
4712
|
+
}
|
|
5004
4713
|
};
|
|
5005
|
-
var
|
|
5006
|
-
const
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
4714
|
+
var getDownloadsFolder = (chromeMode) => {
|
|
4715
|
+
const destination = chromeMode === "headless-shell" ? "chrome-headless-shell" : "chrome-for-testing";
|
|
4716
|
+
return path8.join(getDownloadsCacheDir(), destination);
|
|
4717
|
+
};
|
|
4718
|
+
var downloadBrowser = async ({
|
|
4719
|
+
logLevel,
|
|
4720
|
+
indent,
|
|
4721
|
+
onProgress,
|
|
4722
|
+
version,
|
|
4723
|
+
chromeMode
|
|
4724
|
+
}) => {
|
|
4725
|
+
const platform2 = getPlatform();
|
|
4726
|
+
const downloadURL = getChromeDownloadUrl({ platform: platform2, version, chromeMode });
|
|
4727
|
+
const fileName = downloadURL.split("/").pop();
|
|
4728
|
+
if (!fileName) {
|
|
4729
|
+
throw new Error(`A malformed download URL was found: ${downloadURL}.`);
|
|
5015
4730
|
}
|
|
5016
|
-
|
|
4731
|
+
const downloadsFolder = getDownloadsFolder(chromeMode);
|
|
4732
|
+
const archivePath = path8.join(downloadsFolder, fileName);
|
|
4733
|
+
const outputPath = getFolderPath(downloadsFolder, platform2);
|
|
4734
|
+
if (await existsAsync(outputPath)) {
|
|
4735
|
+
return getRevisionInfo(chromeMode);
|
|
4736
|
+
}
|
|
4737
|
+
if (!await existsAsync(downloadsFolder)) {
|
|
4738
|
+
await mkdirAsync(downloadsFolder, {
|
|
4739
|
+
recursive: true
|
|
4740
|
+
});
|
|
4741
|
+
}
|
|
4742
|
+
if (os2.platform() !== "darwin" && os2.platform() !== "linux" && os2.arch() === "arm64") {
|
|
4743
|
+
throw new Error([
|
|
4744
|
+
"Chrome Headless Shell is not available for Windows for arm64 architecture."
|
|
4745
|
+
].join(`
|
|
4746
|
+
`));
|
|
4747
|
+
}
|
|
4748
|
+
try {
|
|
4749
|
+
await downloadFile({
|
|
4750
|
+
url: downloadURL,
|
|
4751
|
+
to: () => archivePath,
|
|
4752
|
+
onProgress: (progress) => {
|
|
4753
|
+
if (progress.totalSize === null || progress.percent === null) {
|
|
4754
|
+
throw new Error("Expected totalSize and percent to be defined");
|
|
4755
|
+
}
|
|
4756
|
+
onProgress({
|
|
4757
|
+
downloadedBytes: progress.downloaded,
|
|
4758
|
+
totalSizeInBytes: progress.totalSize,
|
|
4759
|
+
percent: progress.percent
|
|
4760
|
+
});
|
|
4761
|
+
},
|
|
4762
|
+
indent,
|
|
4763
|
+
logLevel
|
|
4764
|
+
});
|
|
4765
|
+
await extractZip(archivePath, { dir: outputPath });
|
|
4766
|
+
const chromePath = path8.join(outputPath, "chrome-linux", "chrome");
|
|
4767
|
+
const chromeHeadlessShellPath = path8.join(outputPath, "chrome-linux", "chrome-headless-shell");
|
|
4768
|
+
if (fs6.existsSync(chromePath)) {
|
|
4769
|
+
fs6.renameSync(chromePath, chromeHeadlessShellPath);
|
|
4770
|
+
}
|
|
4771
|
+
const chromeLinuxFolder = path8.join(outputPath, "chrome-linux");
|
|
4772
|
+
if (fs6.existsSync(chromeLinuxFolder)) {
|
|
4773
|
+
fs6.renameSync(chromeLinuxFolder, path8.join(outputPath, "chrome-headless-shell-linux-arm64"));
|
|
4774
|
+
}
|
|
4775
|
+
} catch (err) {
|
|
4776
|
+
return Promise.reject(err);
|
|
4777
|
+
} finally {
|
|
4778
|
+
if (await existsAsync(archivePath)) {
|
|
4779
|
+
await unlinkAsync(archivePath);
|
|
4780
|
+
}
|
|
4781
|
+
}
|
|
4782
|
+
const revisionInfo = getRevisionInfo(chromeMode);
|
|
4783
|
+
makeFileExecutableIfItIsNot(revisionInfo.executablePath);
|
|
4784
|
+
return revisionInfo;
|
|
5017
4785
|
};
|
|
5018
|
-
var
|
|
5019
|
-
return
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
4786
|
+
var getFolderPath = (downloadsFolder, platform2) => {
|
|
4787
|
+
return path8.resolve(downloadsFolder, platform2);
|
|
4788
|
+
};
|
|
4789
|
+
var getExecutablePath2 = (chromeMode) => {
|
|
4790
|
+
const downloadsFolder = getDownloadsFolder(chromeMode);
|
|
4791
|
+
const platform2 = getPlatform();
|
|
4792
|
+
const folderPath = getFolderPath(downloadsFolder, platform2);
|
|
4793
|
+
if (chromeMode === "chrome-for-testing") {
|
|
4794
|
+
if (platform2 === "mac-arm64" || platform2 === "mac-x64") {
|
|
4795
|
+
return path8.join(folderPath, `chrome-${platform2}`, "Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing");
|
|
5023
4796
|
}
|
|
5024
|
-
|
|
5025
|
-
|
|
4797
|
+
if (platform2 === "win64") {
|
|
4798
|
+
return path8.join(folderPath, "chrome-win64", "chrome.exe");
|
|
4799
|
+
}
|
|
4800
|
+
if (platform2 === "linux64" || platform2 === "linux-arm64") {
|
|
4801
|
+
return path8.join(folderPath, "chrome-linux64", "chrome");
|
|
4802
|
+
}
|
|
4803
|
+
throw new Error("unsupported platform" + platform2);
|
|
4804
|
+
}
|
|
4805
|
+
if (chromeMode === "headless-shell") {
|
|
4806
|
+
return path8.join(folderPath, `chrome-headless-shell-${platform2}`, platform2 === "win64" ? "chrome-headless-shell.exe" : platform2 === "linux-arm64" ? "headless_shell" : "chrome-headless-shell");
|
|
4807
|
+
}
|
|
4808
|
+
throw new Error("unsupported chrome mode" + chromeMode);
|
|
5026
4809
|
};
|
|
5027
|
-
var
|
|
5028
|
-
const
|
|
5029
|
-
const
|
|
5030
|
-
const
|
|
5031
|
-
|
|
4810
|
+
var getRevisionInfo = (chromeMode) => {
|
|
4811
|
+
const executablePath = getExecutablePath2(chromeMode);
|
|
4812
|
+
const downloadsFolder = getDownloadsFolder(chromeMode);
|
|
4813
|
+
const platform2 = getPlatform();
|
|
4814
|
+
const folderPath = getFolderPath(downloadsFolder, platform2);
|
|
4815
|
+
const url = getChromeDownloadUrl({ platform: platform2, version: null, chromeMode });
|
|
4816
|
+
const local = fs6.existsSync(folderPath);
|
|
5032
4817
|
return {
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
originalScriptCode: scriptCode
|
|
4818
|
+
executablePath,
|
|
4819
|
+
folderPath,
|
|
4820
|
+
local,
|
|
4821
|
+
url
|
|
5038
4822
|
};
|
|
5039
4823
|
};
|
|
5040
|
-
var getSourceMapFromRemoteFile = async (fileName) => {
|
|
5041
|
-
const fileContents = await fetchUrl(fileName);
|
|
5042
|
-
return getSourceMap(fileName, fileContents, "remote");
|
|
5043
|
-
};
|
|
5044
|
-
var getSourceMapFromLocalFile = (fileName) => {
|
|
5045
|
-
const fileContents = readFileSync(fileName, "utf8");
|
|
5046
|
-
return getSourceMap(fileName, fileContents, "local");
|
|
5047
|
-
};
|
|
5048
|
-
|
|
5049
|
-
// src/error-handling/handle-javascript-exception.ts
|
|
5050
|
-
import { NoReactInternals as NoReactInternals5 } from "remotion/no-react";
|
|
5051
4824
|
|
|
5052
|
-
// src/
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
4825
|
+
// src/ensure-browser.ts
|
|
4826
|
+
var currentEnsureBrowserOperation = Promise.resolve();
|
|
4827
|
+
var internalEnsureBrowserUncapped = async ({
|
|
4828
|
+
indent,
|
|
4829
|
+
logLevel,
|
|
4830
|
+
browserExecutable,
|
|
4831
|
+
onBrowserDownload,
|
|
4832
|
+
chromeMode
|
|
4833
|
+
}) => {
|
|
4834
|
+
const status = getBrowserStatus({ browserExecutable, chromeMode });
|
|
4835
|
+
if (status.type === "no-browser") {
|
|
4836
|
+
const { onProgress, version } = onBrowserDownload({ chromeMode });
|
|
4837
|
+
await downloadBrowser({ indent, logLevel, onProgress, version, chromeMode });
|
|
5063
4838
|
}
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
4839
|
+
const newStatus = getBrowserStatus({ browserExecutable, chromeMode });
|
|
4840
|
+
return newStatus;
|
|
4841
|
+
};
|
|
4842
|
+
var internalEnsureBrowser = (options) => {
|
|
4843
|
+
currentEnsureBrowserOperation = currentEnsureBrowserOperation.then(() => internalEnsureBrowserUncapped(options));
|
|
4844
|
+
return currentEnsureBrowserOperation;
|
|
4845
|
+
};
|
|
4846
|
+
var getBrowserStatus = ({
|
|
4847
|
+
browserExecutable,
|
|
4848
|
+
chromeMode
|
|
4849
|
+
}) => {
|
|
4850
|
+
if (browserExecutable) {
|
|
4851
|
+
if (!fs7.existsSync(browserExecutable)) {
|
|
4852
|
+
throw new Error(`"browserExecutable" was specified as '${browserExecutable}' but the path doesn't exist. Pass "null" for "browserExecutable" to download a browser automatically.`);
|
|
5068
4853
|
}
|
|
5069
|
-
return
|
|
4854
|
+
return { path: browserExecutable, type: "user-defined-path" };
|
|
4855
|
+
}
|
|
4856
|
+
const revision = getRevisionInfo(chromeMode);
|
|
4857
|
+
if (revision.local && fs7.existsSync(revision.executablePath)) {
|
|
4858
|
+
return { path: revision.executablePath, type: "local-puppeteer-browser" };
|
|
4859
|
+
}
|
|
4860
|
+
return { type: "no-browser" };
|
|
4861
|
+
};
|
|
4862
|
+
var ensureBrowser = (options) => {
|
|
4863
|
+
const indent = false;
|
|
4864
|
+
const logLevel = options?.logLevel ?? "info";
|
|
4865
|
+
return internalEnsureBrowser({
|
|
4866
|
+
browserExecutable: options?.browserExecutable ?? null,
|
|
4867
|
+
indent,
|
|
4868
|
+
logLevel: options?.logLevel ?? "info",
|
|
4869
|
+
onBrowserDownload: options?.onBrowserDownload ?? defaultBrowserDownloadProgress({
|
|
4870
|
+
api: "ensureBrowser()",
|
|
4871
|
+
indent: false,
|
|
4872
|
+
logLevel
|
|
4873
|
+
}),
|
|
4874
|
+
chromeMode: options?.chromeMode ?? "headless-shell"
|
|
5070
4875
|
});
|
|
5071
|
-
}
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
4876
|
+
};
|
|
4877
|
+
|
|
4878
|
+
// src/get-local-browser-executable.ts
|
|
4879
|
+
import fs8 from "node:fs";
|
|
4880
|
+
var getBrowserStatus2 = ({
|
|
4881
|
+
browserExecutablePath,
|
|
4882
|
+
indent,
|
|
4883
|
+
logLevel,
|
|
4884
|
+
chromeMode
|
|
5077
4885
|
}) => {
|
|
5078
|
-
if (
|
|
5079
|
-
|
|
4886
|
+
if (browserExecutablePath) {
|
|
4887
|
+
if (!fs8.existsSync(browserExecutablePath)) {
|
|
4888
|
+
Log.warn({ indent, logLevel }, `Browser executable was specified as '${browserExecutablePath}' but the path doesn't exist.`);
|
|
4889
|
+
}
|
|
4890
|
+
return { path: browserExecutablePath, type: "user-defined-path" };
|
|
5080
4891
|
}
|
|
5081
|
-
|
|
5082
|
-
|
|
4892
|
+
const revision = getRevisionInfo(chromeMode);
|
|
4893
|
+
if (revision.local && fs8.existsSync(revision.executablePath)) {
|
|
4894
|
+
return { path: revision.executablePath, type: "local-puppeteer-browser" };
|
|
5083
4895
|
}
|
|
5084
|
-
return {
|
|
5085
|
-
columnNumber,
|
|
5086
|
-
fileName,
|
|
5087
|
-
functionName,
|
|
5088
|
-
lineNumber
|
|
5089
|
-
};
|
|
4896
|
+
return { type: "no-browser" };
|
|
5090
4897
|
};
|
|
5091
|
-
var
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
throw new Error("could not get last");
|
|
5103
|
-
}
|
|
5104
|
-
const [_fileName, _lineNumber, _columnNumber] = extractLocation(_last);
|
|
5105
|
-
return makeStackFrame({
|
|
5106
|
-
functionName: _data.join("@") || (isEval ? "eval" : null),
|
|
5107
|
-
fileName: _fileName,
|
|
5108
|
-
lineNumber: _lineNumber,
|
|
5109
|
-
columnNumber: _columnNumber
|
|
5110
|
-
});
|
|
5111
|
-
}
|
|
5112
|
-
if (e.indexOf("(eval ") !== -1) {
|
|
5113
|
-
e = e.replace(/(\(eval at [^()]*)|(\),.*$)/g, "");
|
|
5114
|
-
}
|
|
5115
|
-
if (e.indexOf("(at ") !== -1) {
|
|
5116
|
-
e = e.replace(/\(at /, "(");
|
|
5117
|
-
}
|
|
5118
|
-
const data = e.trim().split(/\s+/g).slice(1);
|
|
5119
|
-
const last = data.pop();
|
|
5120
|
-
if (!last) {
|
|
5121
|
-
throw new Error("could not get last");
|
|
5122
|
-
}
|
|
5123
|
-
const [fileName, lineNumber, columnNumber] = extractLocation(last);
|
|
5124
|
-
return makeStackFrame({
|
|
5125
|
-
functionName: data.join(" ") || null,
|
|
5126
|
-
fileName,
|
|
5127
|
-
lineNumber,
|
|
5128
|
-
columnNumber
|
|
5129
|
-
});
|
|
4898
|
+
var getLocalBrowserExecutable = ({
|
|
4899
|
+
preferredBrowserExecutable,
|
|
4900
|
+
logLevel,
|
|
4901
|
+
indent,
|
|
4902
|
+
chromeMode
|
|
4903
|
+
}) => {
|
|
4904
|
+
const status = getBrowserStatus2({
|
|
4905
|
+
browserExecutablePath: preferredBrowserExecutable,
|
|
4906
|
+
indent,
|
|
4907
|
+
logLevel,
|
|
4908
|
+
chromeMode
|
|
5130
4909
|
});
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
// src/delay-render-embedded-stack.ts
|
|
5135
|
-
var parseDelayRenderEmbeddedStack = (message) => {
|
|
5136
|
-
const index = message.indexOf(NoReactInternals4.DELAY_RENDER_CALLSTACK_TOKEN);
|
|
5137
|
-
if (index === -1) {
|
|
5138
|
-
return null;
|
|
4910
|
+
if (status.type === "no-browser") {
|
|
4911
|
+
throw new TypeError("No browser found for rendering frames! Please open a GitHub issue and describe " + "how you reached this error: https://remotion.dev/issue");
|
|
5139
4912
|
}
|
|
5140
|
-
|
|
5141
|
-
const parsed = parseStack(msg.split(`
|
|
5142
|
-
`));
|
|
5143
|
-
return parsed;
|
|
4913
|
+
return status.path;
|
|
5144
4914
|
};
|
|
5145
4915
|
|
|
5146
|
-
// src/
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
frame,
|
|
5157
|
-
name,
|
|
5158
|
-
chunk
|
|
5159
|
-
}) {
|
|
5160
|
-
super(message);
|
|
5161
|
-
this.stack = stack;
|
|
5162
|
-
this.stackFrame = stackFrame;
|
|
5163
|
-
this.frame = frame;
|
|
5164
|
-
this.chunk = chunk;
|
|
5165
|
-
this.name = name;
|
|
5166
|
-
this.delayRenderCall = stack ? parseDelayRenderEmbeddedStack(stack) : null;
|
|
4916
|
+
// src/get-available-memory.ts
|
|
4917
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
4918
|
+
import { freemem } from "node:os";
|
|
4919
|
+
var getFreeMemoryFromProcMeminfo = () => {
|
|
4920
|
+
const data = readFileSync2("/proc/meminfo", "utf-8");
|
|
4921
|
+
const lines = data.split(`
|
|
4922
|
+
`);
|
|
4923
|
+
const memAvailableLine = lines.find((line) => line.startsWith("MemAvailable"));
|
|
4924
|
+
if (!memAvailableLine) {
|
|
4925
|
+
throw new Error("MemAvailable not found in /proc/meminfo");
|
|
5167
4926
|
}
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
class ErrorWithStackFrame extends Error {
|
|
5172
|
-
symbolicatedStackFrames;
|
|
5173
|
-
frame;
|
|
5174
|
-
chunk;
|
|
5175
|
-
name;
|
|
5176
|
-
delayRenderCall;
|
|
5177
|
-
constructor({
|
|
5178
|
-
message,
|
|
5179
|
-
symbolicatedStackFrames,
|
|
5180
|
-
frame,
|
|
5181
|
-
name,
|
|
5182
|
-
delayRenderCall,
|
|
5183
|
-
stack,
|
|
5184
|
-
chunk
|
|
5185
|
-
}) {
|
|
5186
|
-
super(message);
|
|
5187
|
-
this.symbolicatedStackFrames = symbolicatedStackFrames;
|
|
5188
|
-
this.frame = frame;
|
|
5189
|
-
this.chunk = chunk;
|
|
5190
|
-
this.name = name;
|
|
5191
|
-
this.delayRenderCall = delayRenderCall;
|
|
5192
|
-
this.stack = stack;
|
|
4927
|
+
const matches = memAvailableLine.match(/(\d+)\s+(\w+)/);
|
|
4928
|
+
if (!matches || matches.length !== 3) {
|
|
4929
|
+
throw new Error("Failed to parse MemAvailable value");
|
|
5193
4930
|
}
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
4931
|
+
const value = parseInt(matches[1], 10);
|
|
4932
|
+
const unit = matches[2].toLowerCase();
|
|
4933
|
+
switch (unit) {
|
|
4934
|
+
case "kb":
|
|
4935
|
+
return value * 1024;
|
|
4936
|
+
case "mb":
|
|
4937
|
+
return value * 1024 * 1024;
|
|
4938
|
+
case "gb":
|
|
4939
|
+
return value * 1024 * 1024 * 1024;
|
|
4940
|
+
default:
|
|
4941
|
+
throw new Error(`Unknown unit: ${unit}`);
|
|
5199
4942
|
}
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
if (
|
|
5203
|
-
|
|
4943
|
+
};
|
|
4944
|
+
var maxLambdaMemory = () => {
|
|
4945
|
+
if (process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE) {
|
|
4946
|
+
return parseInt(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE, 10) * 1024 * 1024;
|
|
5204
4947
|
}
|
|
5205
|
-
|
|
5206
|
-
const split = errorMessage.split(`
|
|
5207
|
-
`);
|
|
5208
|
-
return split.slice(0, Math.max(1, split.length - frames)).join(`
|
|
5209
|
-
`);
|
|
4948
|
+
return Infinity;
|
|
5210
4949
|
};
|
|
5211
|
-
var
|
|
5212
|
-
const
|
|
5213
|
-
if (
|
|
5214
|
-
|
|
4950
|
+
var getAvailableMemory = (logLevel) => {
|
|
4951
|
+
const maxMemory = maxLambdaMemory();
|
|
4952
|
+
if (existsSync3("/proc/meminfo")) {
|
|
4953
|
+
try {
|
|
4954
|
+
const val = getFreeMemoryFromProcMeminfo();
|
|
4955
|
+
if (val !== null) {
|
|
4956
|
+
return Math.min(val, maxMemory);
|
|
4957
|
+
}
|
|
4958
|
+
} catch (err) {
|
|
4959
|
+
Log.warn({ indent: false, logLevel }, "Tried to get available memory from /proc/meminfo but failed. Falling back to os.freemem(). Error:");
|
|
4960
|
+
Log.warn({ indent: false, logLevel }, err);
|
|
4961
|
+
}
|
|
5215
4962
|
}
|
|
5216
|
-
return
|
|
4963
|
+
return Math.min(freemem(), maxMemory);
|
|
5217
4964
|
};
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
4965
|
+
|
|
4966
|
+
// src/get-cpu-count.ts
|
|
4967
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
4968
|
+
import { cpus } from "node:os";
|
|
4969
|
+
var getConcurrencyFromNProc = () => {
|
|
4970
|
+
try {
|
|
4971
|
+
return parseInt(execSync2("nproc", { stdio: "pipe" }).toString().trim(), 10);
|
|
4972
|
+
} catch {
|
|
4973
|
+
return null;
|
|
4974
|
+
}
|
|
5225
4975
|
};
|
|
5226
|
-
var
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
const rawErrorMessage = exception.exceptionDetails.exception?.description;
|
|
5234
|
-
const cleanErrorMessage = cleanUpErrorMessage(exception);
|
|
5235
|
-
if (!cleanErrorMessage) {
|
|
5236
|
-
console.error(exception);
|
|
5237
|
-
const err = new Error(rawErrorMessage);
|
|
5238
|
-
err.stack = rawErrorMessage;
|
|
5239
|
-
onError(err);
|
|
5240
|
-
return;
|
|
5241
|
-
}
|
|
5242
|
-
if (!exception.exceptionDetails.stackTrace) {
|
|
5243
|
-
const err = new Error(removeDelayRenderStack(cleanErrorMessage));
|
|
5244
|
-
err.stack = rawErrorMessage;
|
|
5245
|
-
onError(err);
|
|
5246
|
-
return;
|
|
5247
|
-
}
|
|
5248
|
-
const errorType = exception.exceptionDetails.exception?.className;
|
|
5249
|
-
const symbolicatedErr = new SymbolicateableError({
|
|
5250
|
-
message: removeDelayRenderStack(cleanErrorMessage),
|
|
5251
|
-
stackFrame: exception.exceptionDetails.stackTrace.callFrames.map((f) => callFrameToStackFrame(f)),
|
|
5252
|
-
frame,
|
|
5253
|
-
name: errorType,
|
|
5254
|
-
stack: exception.exceptionDetails.exception?.description,
|
|
5255
|
-
chunk: null
|
|
5256
|
-
});
|
|
5257
|
-
onError(symbolicatedErr);
|
|
5258
|
-
};
|
|
5259
|
-
client.on("Runtime.exceptionThrown", handler);
|
|
5260
|
-
return () => {
|
|
5261
|
-
client.off("Runtime.exceptionThrown", handler);
|
|
5262
|
-
return Promise.resolve();
|
|
5263
|
-
};
|
|
4976
|
+
var getCpuCount = () => {
|
|
4977
|
+
const node = cpus().length;
|
|
4978
|
+
const nproc = getConcurrencyFromNProc();
|
|
4979
|
+
if (nproc === null) {
|
|
4980
|
+
return node;
|
|
4981
|
+
}
|
|
4982
|
+
return Math.min(nproc, node);
|
|
5264
4983
|
};
|
|
5265
4984
|
|
|
5266
|
-
// src/
|
|
5267
|
-
var
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
const
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
frame: symbolicateableError.frame,
|
|
5277
|
-
name: symbolicateableError.name,
|
|
5278
|
-
delayRenderCall: delayRenderFrames,
|
|
5279
|
-
stack: symbolicateableError.stack,
|
|
5280
|
-
chunk: symbolicateableError.chunk
|
|
5281
|
-
});
|
|
5282
|
-
return symbolicatedErr;
|
|
4985
|
+
// src/get-video-threads-flag.ts
|
|
4986
|
+
var MEMORY_USAGE_PER_THREAD = 400000000;
|
|
4987
|
+
var RESERVED_MEMORY = 2000000000;
|
|
4988
|
+
var getIdealVideoThreadsFlag = (logLevel) => {
|
|
4989
|
+
const freeMemory = getAvailableMemory(logLevel);
|
|
4990
|
+
const cpus2 = getCpuCount();
|
|
4991
|
+
const maxRecommendedBasedOnCpus = cpus2 * 2 / 3;
|
|
4992
|
+
const maxRecommendedBasedOnMemory = (freeMemory - RESERVED_MEMORY) / MEMORY_USAGE_PER_THREAD;
|
|
4993
|
+
const maxRecommended = Math.min(maxRecommendedBasedOnCpus, maxRecommendedBasedOnMemory);
|
|
4994
|
+
return Math.max(1, Math.round(maxRecommended));
|
|
5283
4995
|
};
|
|
5284
4996
|
|
|
5285
|
-
// src/
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
}
|
|
5300
|
-
return;
|
|
5301
|
-
}
|
|
5302
|
-
if (Array.isArray(frameRange)) {
|
|
5303
|
-
if (frameRange.length !== 2) {
|
|
5304
|
-
throw new TypeError("Frame range must be a tuple, got an array with length " + frameRange.length);
|
|
5305
|
-
}
|
|
5306
|
-
for (const value of frameRange) {
|
|
5307
|
-
if (typeof value !== "number") {
|
|
5308
|
-
throw new Error(`Each value of frame range must be a number, but got ${typeof value} (${JSON.stringify(value)})`);
|
|
5309
|
-
}
|
|
5310
|
-
if (!Number.isFinite(value)) {
|
|
5311
|
-
throw new TypeError("Each value of frame range must be finite, but got " + value);
|
|
5312
|
-
}
|
|
5313
|
-
if (!Number.isInteger(value)) {
|
|
5314
|
-
throw new Error(`Each value of frame range must be an integer, but got a float (${value})`);
|
|
5315
|
-
}
|
|
5316
|
-
if (value < 0) {
|
|
5317
|
-
throw new Error(`Each value of frame range must be non-negative, but got ${value}`);
|
|
5318
|
-
}
|
|
5319
|
-
}
|
|
5320
|
-
const [first, second] = frameRange;
|
|
5321
|
-
if (second < first) {
|
|
5322
|
-
throw new Error("The second value of frame range must be not smaller than the first one, but got " + frameRange.join("-"));
|
|
5323
|
-
}
|
|
5324
|
-
return;
|
|
4997
|
+
// src/options/gl.tsx
|
|
4998
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
4999
|
+
var validOpenGlRenderers = [
|
|
5000
|
+
"swangle",
|
|
5001
|
+
"angle",
|
|
5002
|
+
"egl",
|
|
5003
|
+
"swiftshader",
|
|
5004
|
+
"vulkan",
|
|
5005
|
+
"angle-egl"
|
|
5006
|
+
];
|
|
5007
|
+
var DEFAULT_OPENGL_RENDERER = null;
|
|
5008
|
+
var validateOpenGlRenderer = (option) => {
|
|
5009
|
+
if (option === null) {
|
|
5010
|
+
return null;
|
|
5325
5011
|
}
|
|
5326
|
-
|
|
5327
|
-
};
|
|
5328
|
-
|
|
5329
|
-
// src/get-compositions.ts
|
|
5330
|
-
import { NoReactInternals as NoReactInternals8 } from "remotion/no-react";
|
|
5331
|
-
|
|
5332
|
-
// src/to-megabytes.ts
|
|
5333
|
-
function toMegabytes(bytes) {
|
|
5334
|
-
const mb = bytes / 1024 / 1024;
|
|
5335
|
-
return `${Math.round(mb * 10) / 10} Mb`;
|
|
5336
|
-
}
|
|
5337
|
-
|
|
5338
|
-
// src/browser/browser-download-progress-bar.ts
|
|
5339
|
-
var defaultBrowserDownloadProgress = ({
|
|
5340
|
-
indent,
|
|
5341
|
-
logLevel,
|
|
5342
|
-
api
|
|
5343
|
-
}) => ({ chromeMode }) => {
|
|
5344
|
-
if (chromeMode === "chrome-for-testing") {
|
|
5345
|
-
Log.info({ indent, logLevel }, "Downloading Chrome for Testing https://www.remotion.dev/chrome-for-testing");
|
|
5346
|
-
} else {
|
|
5347
|
-
Log.info({ indent, logLevel }, "Downloading Chrome Headless Shell https://www.remotion.dev/chrome-headless-shell");
|
|
5012
|
+
if (!validOpenGlRenderers.includes(option)) {
|
|
5013
|
+
throw new TypeError(`${option} is not a valid GL backend. Accepted values: ${validOpenGlRenderers.join(", ")}`);
|
|
5348
5014
|
}
|
|
5349
|
-
|
|
5350
|
-
let lastProgress = 0;
|
|
5351
|
-
return {
|
|
5352
|
-
onProgress: (progress) => {
|
|
5353
|
-
if (progress.downloadedBytes > lastProgress + 1e7 || progress.percent === 1) {
|
|
5354
|
-
lastProgress = progress.downloadedBytes;
|
|
5355
|
-
if (chromeMode === "chrome-for-testing") {
|
|
5356
|
-
Log.info({ indent, logLevel }, `Downloading Chrome for Testing - ${toMegabytes(progress.downloadedBytes)}/${toMegabytes(progress.totalSizeInBytes)}`);
|
|
5357
|
-
} else {
|
|
5358
|
-
Log.info({ indent, logLevel }, `Downloading Chrome Headless Shell - ${toMegabytes(progress.downloadedBytes)}/${toMegabytes(progress.totalSizeInBytes)}`);
|
|
5359
|
-
}
|
|
5360
|
-
}
|
|
5361
|
-
},
|
|
5362
|
-
version: null
|
|
5363
|
-
};
|
|
5015
|
+
return option;
|
|
5364
5016
|
};
|
|
5365
5017
|
|
|
5366
5018
|
// src/open-browser.ts
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
var launchChrome = async ({
|
|
5373
|
-
args,
|
|
5374
|
-
executablePath,
|
|
5375
|
-
defaultViewport,
|
|
5376
|
-
indent,
|
|
5377
|
-
logLevel,
|
|
5378
|
-
userDataDir
|
|
5379
|
-
}) => {
|
|
5380
|
-
const timeout = 60000;
|
|
5381
|
-
const browser = await HeadlessBrowser.create({
|
|
5382
|
-
defaultViewport,
|
|
5383
|
-
args,
|
|
5384
|
-
executablePath,
|
|
5385
|
-
timeout,
|
|
5386
|
-
userDataDir,
|
|
5387
|
-
logLevel,
|
|
5388
|
-
indent
|
|
5389
|
-
});
|
|
5390
|
-
try {
|
|
5391
|
-
await browser.waitForTarget((t) => {
|
|
5392
|
-
return t.type() === "page";
|
|
5393
|
-
}, { timeout });
|
|
5394
|
-
} catch (error) {
|
|
5395
|
-
await browser.close({ silent: false });
|
|
5396
|
-
throw error;
|
|
5397
|
-
}
|
|
5398
|
-
return browser;
|
|
5399
|
-
};
|
|
5400
|
-
|
|
5401
|
-
// src/ensure-browser.ts
|
|
5402
|
-
import fs7 from "fs";
|
|
5403
|
-
|
|
5404
|
-
// src/browser/BrowserFetcher.ts
|
|
5405
|
-
import * as fs6 from "node:fs";
|
|
5406
|
-
import * as os2 from "node:os";
|
|
5407
|
-
import * as path8 from "node:path";
|
|
5408
|
-
import extractZip from "extract-zip";
|
|
5409
|
-
import { promisify } from "node:util";
|
|
5410
|
-
|
|
5411
|
-
// src/browser/get-download-destination.ts
|
|
5412
|
-
import fs5 from "node:fs";
|
|
5413
|
-
import path7 from "node:path";
|
|
5414
|
-
var getDownloadsCacheDir = () => {
|
|
5415
|
-
const cwd = process.cwd();
|
|
5416
|
-
let dir = cwd;
|
|
5417
|
-
for (;; ) {
|
|
5418
|
-
try {
|
|
5419
|
-
if (fs5.statSync(path7.join(dir, "package.json")).isFile()) {
|
|
5420
|
-
break;
|
|
5421
|
-
}
|
|
5422
|
-
} catch (e) {
|
|
5423
|
-
}
|
|
5424
|
-
const parent = path7.dirname(dir);
|
|
5425
|
-
if (dir === parent) {
|
|
5426
|
-
dir = undefined;
|
|
5427
|
-
break;
|
|
5428
|
-
}
|
|
5429
|
-
dir = parent;
|
|
5430
|
-
}
|
|
5431
|
-
if (!dir) {
|
|
5432
|
-
return path7.resolve(cwd, ".remotion");
|
|
5433
|
-
}
|
|
5434
|
-
if (process.versions.pnp === "1") {
|
|
5435
|
-
return path7.resolve(dir, ".pnp/.remotion");
|
|
5019
|
+
var featuresToEnable = (option) => {
|
|
5020
|
+
const renderer = option ?? DEFAULT_OPENGL_RENDERER;
|
|
5021
|
+
const enableAlways = ["NetworkService", "NetworkServiceInProcess"];
|
|
5022
|
+
if (renderer === "vulkan") {
|
|
5023
|
+
return [...enableAlways, "Vulkan", "UseSkiaRenderer"];
|
|
5436
5024
|
}
|
|
5437
|
-
if (
|
|
5438
|
-
return
|
|
5025
|
+
if (renderer === "angle-egl") {
|
|
5026
|
+
return [...enableAlways, "VaapiVideoDecoder"];
|
|
5439
5027
|
}
|
|
5440
|
-
return
|
|
5028
|
+
return enableAlways;
|
|
5441
5029
|
};
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
platform: platform2,
|
|
5448
|
-
version,
|
|
5449
|
-
chromeMode
|
|
5450
|
-
}) {
|
|
5451
|
-
if (platform2 === "linux-arm64") {
|
|
5452
|
-
return `https://playwright.azureedge.net/builds/chromium/${version ?? PLAYWRIGHT_VERSION}/chromium-headless-shell-linux-arm64.zip`;
|
|
5030
|
+
var getOpenGlRenderer = (option) => {
|
|
5031
|
+
const renderer = option ?? DEFAULT_OPENGL_RENDERER;
|
|
5032
|
+
validateOpenGlRenderer(renderer);
|
|
5033
|
+
if (renderer === "swangle") {
|
|
5034
|
+
return ["--use-gl=angle", "--use-angle=swiftshader"];
|
|
5453
5035
|
}
|
|
5454
|
-
if (
|
|
5455
|
-
return
|
|
5036
|
+
if (renderer === "angle-egl") {
|
|
5037
|
+
return ["--use-gl=angle", "--use-angle=gl-egl"];
|
|
5456
5038
|
}
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
});
|
|
5467
|
-
}
|
|
5468
|
-
var getPlatform = () => {
|
|
5469
|
-
const platform2 = os2.platform();
|
|
5470
|
-
switch (platform2) {
|
|
5471
|
-
case "darwin":
|
|
5472
|
-
return os2.arch() === "arm64" ? "mac-arm64" : "mac-x64";
|
|
5473
|
-
case "linux":
|
|
5474
|
-
return os2.arch() === "arm64" ? "linux-arm64" : "linux64";
|
|
5475
|
-
case "win32":
|
|
5476
|
-
return "win64";
|
|
5477
|
-
default:
|
|
5478
|
-
throw new Error("Unsupported platform: " + platform2);
|
|
5039
|
+
if (renderer === "vulkan") {
|
|
5040
|
+
return [
|
|
5041
|
+
"--use-angle=vulkan",
|
|
5042
|
+
"--use-vulkan=native",
|
|
5043
|
+
"--disable-vulkan-fallback-to-gl-for-testing",
|
|
5044
|
+
"--disable-vulkan-surface",
|
|
5045
|
+
"--ignore-gpu-blocklist",
|
|
5046
|
+
"--enable-gpu"
|
|
5047
|
+
];
|
|
5479
5048
|
}
|
|
5049
|
+
if (renderer === null) {
|
|
5050
|
+
return [];
|
|
5051
|
+
}
|
|
5052
|
+
return [`--use-gl=${renderer}`];
|
|
5480
5053
|
};
|
|
5481
|
-
var
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
logLevel,
|
|
5054
|
+
var internalOpenBrowser = async ({
|
|
5055
|
+
browser,
|
|
5056
|
+
browserExecutable,
|
|
5057
|
+
chromiumOptions,
|
|
5058
|
+
forceDeviceScaleFactor,
|
|
5487
5059
|
indent,
|
|
5488
|
-
|
|
5489
|
-
|
|
5060
|
+
viewport,
|
|
5061
|
+
logLevel,
|
|
5062
|
+
onBrowserDownload,
|
|
5490
5063
|
chromeMode
|
|
5491
5064
|
}) => {
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
const fileName = downloadURL.split("/").pop();
|
|
5495
|
-
if (!fileName) {
|
|
5496
|
-
throw new Error(`A malformed download URL was found: ${downloadURL}.`);
|
|
5497
|
-
}
|
|
5498
|
-
const downloadsFolder = getDownloadsFolder(chromeMode);
|
|
5499
|
-
const archivePath = path8.join(downloadsFolder, fileName);
|
|
5500
|
-
const outputPath = getFolderPath(downloadsFolder, platform2);
|
|
5501
|
-
if (await existsAsync(outputPath)) {
|
|
5502
|
-
return getRevisionInfo(chromeMode);
|
|
5503
|
-
}
|
|
5504
|
-
if (!await existsAsync(downloadsFolder)) {
|
|
5505
|
-
await mkdirAsync(downloadsFolder, {
|
|
5506
|
-
recursive: true
|
|
5507
|
-
});
|
|
5508
|
-
}
|
|
5509
|
-
if (os2.platform() !== "darwin" && os2.platform() !== "linux" && os2.arch() === "arm64") {
|
|
5510
|
-
throw new Error([
|
|
5511
|
-
"Chrome Headless Shell is not available for Windows for arm64 architecture."
|
|
5512
|
-
].join(`
|
|
5513
|
-
`));
|
|
5065
|
+
if (browser === "firefox") {
|
|
5066
|
+
throw new TypeError("Firefox supported is not yet turned on. Stay tuned for the future.");
|
|
5514
5067
|
}
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
const chromePath = path8.join(outputPath, "chrome-linux", "chrome");
|
|
5534
|
-
const chromeHeadlessShellPath = path8.join(outputPath, "chrome-linux", "chrome-headless-shell");
|
|
5535
|
-
if (fs6.existsSync(chromePath)) {
|
|
5536
|
-
fs6.renameSync(chromePath, chromeHeadlessShellPath);
|
|
5537
|
-
}
|
|
5538
|
-
const chromeLinuxFolder = path8.join(outputPath, "chrome-linux");
|
|
5539
|
-
if (fs6.existsSync(chromeLinuxFolder)) {
|
|
5540
|
-
fs6.renameSync(chromeLinuxFolder, path8.join(outputPath, "chrome-headless-shell-linux-arm64"));
|
|
5541
|
-
}
|
|
5542
|
-
} catch (err) {
|
|
5543
|
-
return Promise.reject(err);
|
|
5544
|
-
} finally {
|
|
5545
|
-
if (await existsAsync(archivePath)) {
|
|
5546
|
-
await unlinkAsync(archivePath);
|
|
5547
|
-
}
|
|
5548
|
-
}
|
|
5549
|
-
const revisionInfo = getRevisionInfo(chromeMode);
|
|
5550
|
-
makeFileExecutableIfItIsNot(revisionInfo.executablePath);
|
|
5551
|
-
return revisionInfo;
|
|
5552
|
-
};
|
|
5553
|
-
var getFolderPath = (downloadsFolder, platform2) => {
|
|
5554
|
-
return path8.resolve(downloadsFolder, platform2);
|
|
5555
|
-
};
|
|
5556
|
-
var getExecutablePath2 = (chromeMode) => {
|
|
5557
|
-
const downloadsFolder = getDownloadsFolder(chromeMode);
|
|
5558
|
-
const platform2 = getPlatform();
|
|
5559
|
-
const folderPath = getFolderPath(downloadsFolder, platform2);
|
|
5560
|
-
if (chromeMode === "chrome-for-testing") {
|
|
5561
|
-
if (platform2 === "mac-arm64" || platform2 === "mac-x64") {
|
|
5562
|
-
return path8.join(folderPath, `chrome-${platform2}`, "Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing");
|
|
5563
|
-
}
|
|
5564
|
-
if (platform2 === "win64") {
|
|
5565
|
-
return path8.join(folderPath, "chrome-win64", "chrome.exe");
|
|
5566
|
-
}
|
|
5567
|
-
if (platform2 === "linux64" || platform2 === "linux-arm64") {
|
|
5568
|
-
return path8.join(folderPath, "chrome-linux64", "chrome");
|
|
5569
|
-
}
|
|
5570
|
-
throw new Error("unsupported platform" + platform2);
|
|
5571
|
-
}
|
|
5572
|
-
if (chromeMode === "headless-shell") {
|
|
5573
|
-
return path8.join(folderPath, `chrome-headless-shell-${platform2}`, platform2 === "win64" ? "chrome-headless-shell.exe" : platform2 === "linux-arm64" ? "headless_shell" : "chrome-headless-shell");
|
|
5068
|
+
await internalEnsureBrowser({
|
|
5069
|
+
browserExecutable,
|
|
5070
|
+
logLevel,
|
|
5071
|
+
indent,
|
|
5072
|
+
onBrowserDownload,
|
|
5073
|
+
chromeMode
|
|
5074
|
+
});
|
|
5075
|
+
const executablePath = getLocalBrowserExecutable({
|
|
5076
|
+
preferredBrowserExecutable: browserExecutable,
|
|
5077
|
+
logLevel,
|
|
5078
|
+
indent,
|
|
5079
|
+
chromeMode
|
|
5080
|
+
});
|
|
5081
|
+
const customGlRenderer = getOpenGlRenderer(chromiumOptions.gl ?? null);
|
|
5082
|
+
const enableMultiProcessOnLinux = chromiumOptions.enableMultiProcessOnLinux ?? true;
|
|
5083
|
+
Log.verbose({ indent, logLevel, tag: "openBrowser()" }, `Opening browser: gl = ${chromiumOptions.gl}, executable = ${executablePath}, enableMultiProcessOnLinux = ${enableMultiProcessOnLinux}`);
|
|
5084
|
+
if (chromiumOptions.userAgent) {
|
|
5085
|
+
Log.verbose({ indent, logLevel: "verbose", tag: "openBrowser()" }, `Using custom user agent: ${chromiumOptions.userAgent}`);
|
|
5574
5086
|
}
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
var getRevisionInfo = (chromeMode) => {
|
|
5578
|
-
const executablePath = getExecutablePath2(chromeMode);
|
|
5579
|
-
const downloadsFolder = getDownloadsFolder(chromeMode);
|
|
5580
|
-
const platform2 = getPlatform();
|
|
5581
|
-
const folderPath = getFolderPath(downloadsFolder, platform2);
|
|
5582
|
-
const url = getChromeDownloadUrl({ platform: platform2, version: null, chromeMode });
|
|
5583
|
-
const local = fs6.existsSync(folderPath);
|
|
5584
|
-
return {
|
|
5087
|
+
const userDataDir = await fs9.promises.mkdtemp(path9.join(os3.tmpdir(), "puppeteer_dev_chrome_profile-"));
|
|
5088
|
+
const browserInstance = await launchChrome({
|
|
5585
5089
|
executablePath,
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5090
|
+
logLevel,
|
|
5091
|
+
indent,
|
|
5092
|
+
userDataDir,
|
|
5093
|
+
args: [
|
|
5094
|
+
"about:blank",
|
|
5095
|
+
"--allow-pre-commit-input",
|
|
5096
|
+
"--disable-background-networking",
|
|
5097
|
+
`--enable-features=${featuresToEnable(chromiumOptions.gl).join(",")}`,
|
|
5098
|
+
"--disable-background-timer-throttling",
|
|
5099
|
+
"--disable-backgrounding-occluded-windows",
|
|
5100
|
+
"--disable-breakpad",
|
|
5101
|
+
"--disable-client-side-phishing-detection",
|
|
5102
|
+
"--disable-component-extensions-with-background-pages",
|
|
5103
|
+
"--disable-default-apps",
|
|
5104
|
+
"--disable-dev-shm-usage",
|
|
5105
|
+
"--no-proxy-server",
|
|
5106
|
+
"--proxy-server='direct://'",
|
|
5107
|
+
"--proxy-bypass-list=*",
|
|
5108
|
+
"--force-gpu-mem-available-mb=4096",
|
|
5109
|
+
"--disable-hang-monitor",
|
|
5110
|
+
"--disable-extensions",
|
|
5111
|
+
"--allow-chrome-scheme-url",
|
|
5112
|
+
"--disable-ipc-flooding-protection",
|
|
5113
|
+
"--disable-popup-blocking",
|
|
5114
|
+
"--disable-prompt-on-repost",
|
|
5115
|
+
"--disable-renderer-backgrounding",
|
|
5116
|
+
"--disable-sync",
|
|
5117
|
+
"--force-color-profile=srgb",
|
|
5118
|
+
"--metrics-recording-only",
|
|
5119
|
+
"--mute-audio",
|
|
5120
|
+
"--no-first-run",
|
|
5121
|
+
`--video-threads=${getIdealVideoThreadsFlag(logLevel)}`,
|
|
5122
|
+
"--enable-automation",
|
|
5123
|
+
"--password-store=basic",
|
|
5124
|
+
"--use-mock-keychain",
|
|
5125
|
+
"--enable-blink-features=IdleDetection",
|
|
5126
|
+
"--export-tagged-pdf",
|
|
5127
|
+
"--intensive-wake-up-throttling-policy=0",
|
|
5128
|
+
chromiumOptions.headless ?? true ? chromeMode === "chrome-for-testing" ? "--headless=new" : "--headless=old" : null,
|
|
5129
|
+
"--no-sandbox",
|
|
5130
|
+
"--disable-setuid-sandbox",
|
|
5131
|
+
...customGlRenderer,
|
|
5132
|
+
"--disable-background-media-suspend",
|
|
5133
|
+
process.platform === "linux" && chromiumOptions.gl !== "vulkan" && !enableMultiProcessOnLinux ? "--single-process" : null,
|
|
5134
|
+
"--allow-running-insecure-content",
|
|
5135
|
+
"--disable-component-update",
|
|
5136
|
+
"--disable-domain-reliability",
|
|
5137
|
+
"--disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,AvoidUnnecessaryBeforeUnloadCheckSync,IntensiveWakeUpThrottling",
|
|
5138
|
+
"--disable-print-preview",
|
|
5139
|
+
"--disable-site-isolation-trials",
|
|
5140
|
+
"--disk-cache-size=268435456",
|
|
5141
|
+
"--hide-scrollbars",
|
|
5142
|
+
"--no-default-browser-check",
|
|
5143
|
+
"--no-pings",
|
|
5144
|
+
"--font-render-hinting=none",
|
|
5145
|
+
"--no-zygote",
|
|
5146
|
+
"--ignore-gpu-blocklist",
|
|
5147
|
+
"--enable-unsafe-webgpu",
|
|
5148
|
+
typeof forceDeviceScaleFactor === "undefined" ? null : `--force-device-scale-factor=${forceDeviceScaleFactor}`,
|
|
5149
|
+
chromiumOptions.ignoreCertificateErrors ? "--ignore-certificate-errors" : null,
|
|
5150
|
+
...chromiumOptions?.disableWebSecurity ? ["--disable-web-security"] : [],
|
|
5151
|
+
chromiumOptions?.userAgent ? `--user-agent="${chromiumOptions.userAgent}"` : null,
|
|
5152
|
+
"--remote-debugging-port=0",
|
|
5153
|
+
`--user-data-dir=${userDataDir}`
|
|
5154
|
+
].filter(Boolean),
|
|
5155
|
+
defaultViewport: viewport ?? {
|
|
5156
|
+
height: 720,
|
|
5157
|
+
width: 1280,
|
|
5158
|
+
deviceScaleFactor: 1
|
|
5620
5159
|
}
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
return { path: revision.executablePath, type: "local-puppeteer-browser" };
|
|
5626
|
-
}
|
|
5627
|
-
return { type: "no-browser" };
|
|
5160
|
+
});
|
|
5161
|
+
const pages = await browserInstance.pages();
|
|
5162
|
+
await pages[0]?.close();
|
|
5163
|
+
return browserInstance;
|
|
5628
5164
|
};
|
|
5629
|
-
var
|
|
5165
|
+
var openBrowser = (browser, options) => {
|
|
5166
|
+
const { browserExecutable, chromiumOptions, forceDeviceScaleFactor } = options ?? {};
|
|
5630
5167
|
const indent = false;
|
|
5631
|
-
const logLevel = options?.logLevel ?? "info";
|
|
5632
|
-
return
|
|
5633
|
-
|
|
5168
|
+
const logLevel = options?.logLevel ?? (options?.shouldDumpIo ? "verbose" : "info");
|
|
5169
|
+
return internalOpenBrowser({
|
|
5170
|
+
browser,
|
|
5171
|
+
browserExecutable: browserExecutable ?? null,
|
|
5172
|
+
chromiumOptions: chromiumOptions ?? {},
|
|
5173
|
+
forceDeviceScaleFactor,
|
|
5634
5174
|
indent,
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
indent
|
|
5639
|
-
logLevel
|
|
5175
|
+
viewport: null,
|
|
5176
|
+
logLevel,
|
|
5177
|
+
onBrowserDownload: defaultBrowserDownloadProgress({
|
|
5178
|
+
indent,
|
|
5179
|
+
logLevel,
|
|
5180
|
+
api: "openBrowser()"
|
|
5640
5181
|
}),
|
|
5641
5182
|
chromeMode: options?.chromeMode ?? "headless-shell"
|
|
5642
5183
|
});
|
|
5643
5184
|
};
|
|
5644
5185
|
|
|
5645
|
-
// src/get-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5186
|
+
// src/get-browser-instance.ts
|
|
5187
|
+
var getPageAndCleanupFn = async ({
|
|
5188
|
+
passedInInstance,
|
|
5189
|
+
browserExecutable,
|
|
5190
|
+
chromiumOptions,
|
|
5191
|
+
forceDeviceScaleFactor,
|
|
5649
5192
|
indent,
|
|
5650
5193
|
logLevel,
|
|
5651
|
-
|
|
5194
|
+
onBrowserDownload,
|
|
5195
|
+
chromeMode,
|
|
5196
|
+
pageIndex,
|
|
5197
|
+
onBrowserLog
|
|
5652
5198
|
}) => {
|
|
5653
|
-
if (
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
return {
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
}
|
|
5671
|
-
|
|
5672
|
-
|
|
5199
|
+
if (passedInInstance) {
|
|
5200
|
+
const page = await passedInInstance.newPage({
|
|
5201
|
+
context: () => null,
|
|
5202
|
+
logLevel,
|
|
5203
|
+
indent,
|
|
5204
|
+
pageIndex,
|
|
5205
|
+
onBrowserLog
|
|
5206
|
+
});
|
|
5207
|
+
return {
|
|
5208
|
+
page,
|
|
5209
|
+
cleanupPage: () => {
|
|
5210
|
+
page.close().catch((err) => {
|
|
5211
|
+
if (!err.message.includes("Target closed")) {
|
|
5212
|
+
Log.error({ indent, logLevel }, "Was not able to close puppeteer page", err);
|
|
5213
|
+
}
|
|
5214
|
+
});
|
|
5215
|
+
return Promise.resolve();
|
|
5216
|
+
}
|
|
5217
|
+
};
|
|
5218
|
+
}
|
|
5219
|
+
const browserInstance = await internalOpenBrowser({
|
|
5220
|
+
browser: DEFAULT_BROWSER,
|
|
5221
|
+
browserExecutable,
|
|
5222
|
+
chromiumOptions,
|
|
5223
|
+
forceDeviceScaleFactor,
|
|
5673
5224
|
indent,
|
|
5225
|
+
viewport: null,
|
|
5674
5226
|
logLevel,
|
|
5227
|
+
onBrowserDownload,
|
|
5675
5228
|
chromeMode
|
|
5676
5229
|
});
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
}
|
|
5694
|
-
const matches = memAvailableLine.match(/(\d+)\s+(\w+)/);
|
|
5695
|
-
if (!matches || matches.length !== 3) {
|
|
5696
|
-
throw new Error("Failed to parse MemAvailable value");
|
|
5697
|
-
}
|
|
5698
|
-
const value = parseInt(matches[1], 10);
|
|
5699
|
-
const unit = matches[2].toLowerCase();
|
|
5700
|
-
switch (unit) {
|
|
5701
|
-
case "kb":
|
|
5702
|
-
return value * 1024;
|
|
5703
|
-
case "mb":
|
|
5704
|
-
return value * 1024 * 1024;
|
|
5705
|
-
case "gb":
|
|
5706
|
-
return value * 1024 * 1024 * 1024;
|
|
5707
|
-
default:
|
|
5708
|
-
throw new Error(`Unknown unit: ${unit}`);
|
|
5709
|
-
}
|
|
5710
|
-
};
|
|
5711
|
-
var maxLambdaMemory = () => {
|
|
5712
|
-
if (process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE) {
|
|
5713
|
-
return parseInt(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE, 10) * 1024 * 1024;
|
|
5714
|
-
}
|
|
5715
|
-
return Infinity;
|
|
5716
|
-
};
|
|
5717
|
-
var getAvailableMemory = (logLevel) => {
|
|
5718
|
-
const maxMemory = maxLambdaMemory();
|
|
5719
|
-
if (existsSync3("/proc/meminfo")) {
|
|
5720
|
-
try {
|
|
5721
|
-
const val = getFreeMemoryFromProcMeminfo();
|
|
5722
|
-
if (val !== null) {
|
|
5723
|
-
return Math.min(val, maxMemory);
|
|
5724
|
-
}
|
|
5725
|
-
} catch (err) {
|
|
5726
|
-
Log.warn({ indent: false, logLevel }, "Tried to get available memory from /proc/meminfo but failed. Falling back to os.freemem(). Error:");
|
|
5727
|
-
Log.warn({ indent: false, logLevel }, err);
|
|
5230
|
+
const browserPage = await browserInstance.newPage({
|
|
5231
|
+
context: () => null,
|
|
5232
|
+
logLevel,
|
|
5233
|
+
indent,
|
|
5234
|
+
pageIndex,
|
|
5235
|
+
onBrowserLog
|
|
5236
|
+
});
|
|
5237
|
+
return {
|
|
5238
|
+
page: browserPage,
|
|
5239
|
+
cleanupPage: () => {
|
|
5240
|
+
browserInstance.close({ silent: true }).catch((err) => {
|
|
5241
|
+
if (!err.message.includes("Target closed")) {
|
|
5242
|
+
Log.error({ indent, logLevel }, "Was not able to close puppeteer page", err);
|
|
5243
|
+
}
|
|
5244
|
+
});
|
|
5245
|
+
return Promise.resolve();
|
|
5728
5246
|
}
|
|
5729
|
-
}
|
|
5730
|
-
return Math.min(freemem(), maxMemory);
|
|
5247
|
+
};
|
|
5731
5248
|
};
|
|
5732
5249
|
|
|
5733
|
-
// src/
|
|
5734
|
-
import {
|
|
5735
|
-
|
|
5736
|
-
var getConcurrencyFromNProc = () => {
|
|
5737
|
-
try {
|
|
5738
|
-
return parseInt(execSync2("nproc", { stdio: "pipe" }).toString().trim(), 10);
|
|
5739
|
-
} catch {
|
|
5740
|
-
return null;
|
|
5741
|
-
}
|
|
5742
|
-
};
|
|
5743
|
-
var getCpuCount = () => {
|
|
5744
|
-
const node = cpus().length;
|
|
5745
|
-
const nproc = getConcurrencyFromNProc();
|
|
5746
|
-
if (nproc === null) {
|
|
5747
|
-
return node;
|
|
5748
|
-
}
|
|
5749
|
-
return Math.min(nproc, node);
|
|
5750
|
-
};
|
|
5250
|
+
// src/options/offthreadvideo-threads.tsx
|
|
5251
|
+
import { jsx as jsx2, jsxs as jsxs2, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
5252
|
+
var DEFAULT_RENDER_FRAMES_OFFTHREAD_VIDEO_THREADS = 2;
|
|
5751
5253
|
|
|
5752
|
-
// src/
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
const freeMemory = getAvailableMemory(logLevel);
|
|
5757
|
-
const cpus2 = getCpuCount();
|
|
5758
|
-
const maxRecommendedBasedOnCpus = cpus2 * 2 / 3;
|
|
5759
|
-
const maxRecommendedBasedOnMemory = (freeMemory - RESERVED_MEMORY) / MEMORY_USAGE_PER_THREAD;
|
|
5760
|
-
const maxRecommended = Math.min(maxRecommendedBasedOnCpus, maxRecommendedBasedOnMemory);
|
|
5761
|
-
return Math.max(1, Math.round(maxRecommended));
|
|
5762
|
-
};
|
|
5254
|
+
// src/prepare-server.ts
|
|
5255
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
5256
|
+
import path18 from "node:path";
|
|
5257
|
+
import { NoReactInternals as NoReactInternals7 } from "remotion/no-react";
|
|
5763
5258
|
|
|
5764
|
-
// src/
|
|
5765
|
-
import
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
"angle",
|
|
5769
|
-
"egl",
|
|
5770
|
-
"swiftshader",
|
|
5771
|
-
"vulkan",
|
|
5772
|
-
"angle-egl"
|
|
5773
|
-
];
|
|
5774
|
-
var DEFAULT_OPENGL_RENDERER = null;
|
|
5775
|
-
var validateOpenGlRenderer = (option) => {
|
|
5776
|
-
if (option === null) {
|
|
5777
|
-
return null;
|
|
5778
|
-
}
|
|
5779
|
-
if (!validOpenGlRenderers.includes(option)) {
|
|
5780
|
-
throw new TypeError(`${option} is not a valid GL backend. Accepted values: ${validOpenGlRenderers.join(", ")}`);
|
|
5781
|
-
}
|
|
5782
|
-
return option;
|
|
5783
|
-
};
|
|
5259
|
+
// src/assets/download-and-map-assets-to-file.ts
|
|
5260
|
+
import fs10 from "node:fs";
|
|
5261
|
+
import path11, { extname as extname2 } from "node:path";
|
|
5262
|
+
import { random } from "remotion/no-react";
|
|
5784
5263
|
|
|
5785
|
-
// src/
|
|
5786
|
-
var
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
if (renderer === "vulkan") {
|
|
5790
|
-
return [...enableAlways, "Vulkan", "UseSkiaRenderer"];
|
|
5264
|
+
// src/compress-assets.ts
|
|
5265
|
+
var compressAsset = (previousRenderAssets, newRenderAsset) => {
|
|
5266
|
+
if (newRenderAsset.src.length < 400) {
|
|
5267
|
+
return newRenderAsset;
|
|
5791
5268
|
}
|
|
5792
|
-
|
|
5793
|
-
|
|
5269
|
+
const assetWithSameSrc = previousRenderAssets.find((a) => a.src === newRenderAsset.src);
|
|
5270
|
+
if (!assetWithSameSrc) {
|
|
5271
|
+
return newRenderAsset;
|
|
5794
5272
|
}
|
|
5795
|
-
return
|
|
5273
|
+
return {
|
|
5274
|
+
...newRenderAsset,
|
|
5275
|
+
src: `same-as-${assetWithSameSrc.id}-${assetWithSameSrc.frame}`
|
|
5276
|
+
};
|
|
5796
5277
|
};
|
|
5797
|
-
var
|
|
5798
|
-
|
|
5799
|
-
validateOpenGlRenderer(renderer);
|
|
5800
|
-
if (renderer === "swangle") {
|
|
5801
|
-
return ["--use-gl=angle", "--use-angle=swiftshader"];
|
|
5802
|
-
}
|
|
5803
|
-
if (renderer === "angle-egl") {
|
|
5804
|
-
return ["--use-gl=angle", "--use-angle=gl-egl"];
|
|
5805
|
-
}
|
|
5806
|
-
if (renderer === "vulkan") {
|
|
5807
|
-
return [
|
|
5808
|
-
"--use-angle=vulkan",
|
|
5809
|
-
"--use-vulkan=native",
|
|
5810
|
-
"--disable-vulkan-fallback-to-gl-for-testing",
|
|
5811
|
-
"--disable-vulkan-surface",
|
|
5812
|
-
"--ignore-gpu-blocklist",
|
|
5813
|
-
"--enable-gpu"
|
|
5814
|
-
];
|
|
5815
|
-
}
|
|
5816
|
-
if (renderer === null) {
|
|
5817
|
-
return [];
|
|
5818
|
-
}
|
|
5819
|
-
return [`--use-gl=${renderer}`];
|
|
5820
|
-
};
|
|
5821
|
-
var internalOpenBrowser = async ({
|
|
5822
|
-
browser,
|
|
5823
|
-
browserExecutable,
|
|
5824
|
-
chromiumOptions,
|
|
5825
|
-
forceDeviceScaleFactor,
|
|
5826
|
-
indent,
|
|
5827
|
-
viewport,
|
|
5828
|
-
logLevel,
|
|
5829
|
-
onBrowserDownload,
|
|
5830
|
-
chromeMode
|
|
5831
|
-
}) => {
|
|
5832
|
-
if (browser === "firefox") {
|
|
5833
|
-
throw new TypeError("Firefox supported is not yet turned on. Stay tuned for the future.");
|
|
5834
|
-
}
|
|
5835
|
-
await internalEnsureBrowser({
|
|
5836
|
-
browserExecutable,
|
|
5837
|
-
logLevel,
|
|
5838
|
-
indent,
|
|
5839
|
-
onBrowserDownload,
|
|
5840
|
-
chromeMode
|
|
5841
|
-
});
|
|
5842
|
-
const executablePath = getLocalBrowserExecutable({
|
|
5843
|
-
preferredBrowserExecutable: browserExecutable,
|
|
5844
|
-
logLevel,
|
|
5845
|
-
indent,
|
|
5846
|
-
chromeMode
|
|
5847
|
-
});
|
|
5848
|
-
const customGlRenderer = getOpenGlRenderer(chromiumOptions.gl ?? null);
|
|
5849
|
-
const enableMultiProcessOnLinux = chromiumOptions.enableMultiProcessOnLinux ?? true;
|
|
5850
|
-
Log.verbose({ indent, logLevel, tag: "openBrowser()" }, `Opening browser: gl = ${chromiumOptions.gl}, executable = ${executablePath}, enableMultiProcessOnLinux = ${enableMultiProcessOnLinux}`);
|
|
5851
|
-
if (chromiumOptions.userAgent) {
|
|
5852
|
-
Log.verbose({ indent, logLevel: "verbose", tag: "openBrowser()" }, `Using custom user agent: ${chromiumOptions.userAgent}`);
|
|
5853
|
-
}
|
|
5854
|
-
const userDataDir = await fs9.promises.mkdtemp(path9.join(os3.tmpdir(), "puppeteer_dev_chrome_profile-"));
|
|
5855
|
-
const browserInstance = await launchChrome({
|
|
5856
|
-
executablePath,
|
|
5857
|
-
logLevel,
|
|
5858
|
-
indent,
|
|
5859
|
-
userDataDir,
|
|
5860
|
-
args: [
|
|
5861
|
-
"about:blank",
|
|
5862
|
-
"--allow-pre-commit-input",
|
|
5863
|
-
"--disable-background-networking",
|
|
5864
|
-
`--enable-features=${featuresToEnable(chromiumOptions.gl).join(",")}`,
|
|
5865
|
-
"--disable-background-timer-throttling",
|
|
5866
|
-
"--disable-backgrounding-occluded-windows",
|
|
5867
|
-
"--disable-breakpad",
|
|
5868
|
-
"--disable-client-side-phishing-detection",
|
|
5869
|
-
"--disable-component-extensions-with-background-pages",
|
|
5870
|
-
"--disable-default-apps",
|
|
5871
|
-
"--disable-dev-shm-usage",
|
|
5872
|
-
"--no-proxy-server",
|
|
5873
|
-
"--proxy-server='direct://'",
|
|
5874
|
-
"--proxy-bypass-list=*",
|
|
5875
|
-
"--force-gpu-mem-available-mb=4096",
|
|
5876
|
-
"--disable-hang-monitor",
|
|
5877
|
-
"--disable-extensions",
|
|
5878
|
-
"--allow-chrome-scheme-url",
|
|
5879
|
-
"--disable-ipc-flooding-protection",
|
|
5880
|
-
"--disable-popup-blocking",
|
|
5881
|
-
"--disable-prompt-on-repost",
|
|
5882
|
-
"--disable-renderer-backgrounding",
|
|
5883
|
-
"--disable-sync",
|
|
5884
|
-
"--force-color-profile=srgb",
|
|
5885
|
-
"--metrics-recording-only",
|
|
5886
|
-
"--mute-audio",
|
|
5887
|
-
"--no-first-run",
|
|
5888
|
-
`--video-threads=${getIdealVideoThreadsFlag(logLevel)}`,
|
|
5889
|
-
"--enable-automation",
|
|
5890
|
-
"--password-store=basic",
|
|
5891
|
-
"--use-mock-keychain",
|
|
5892
|
-
"--enable-blink-features=IdleDetection",
|
|
5893
|
-
"--export-tagged-pdf",
|
|
5894
|
-
"--intensive-wake-up-throttling-policy=0",
|
|
5895
|
-
chromiumOptions.headless ?? true ? chromeMode === "chrome-for-testing" ? "--headless=new" : "--headless=old" : null,
|
|
5896
|
-
"--no-sandbox",
|
|
5897
|
-
"--disable-setuid-sandbox",
|
|
5898
|
-
...customGlRenderer,
|
|
5899
|
-
"--disable-background-media-suspend",
|
|
5900
|
-
process.platform === "linux" && chromiumOptions.gl !== "vulkan" && !enableMultiProcessOnLinux ? "--single-process" : null,
|
|
5901
|
-
"--allow-running-insecure-content",
|
|
5902
|
-
"--disable-component-update",
|
|
5903
|
-
"--disable-domain-reliability",
|
|
5904
|
-
"--disable-features=AudioServiceOutOfProcess,IsolateOrigins,site-per-process,Translate,BackForwardCache,AvoidUnnecessaryBeforeUnloadCheckSync,IntensiveWakeUpThrottling",
|
|
5905
|
-
"--disable-print-preview",
|
|
5906
|
-
"--disable-site-isolation-trials",
|
|
5907
|
-
"--disk-cache-size=268435456",
|
|
5908
|
-
"--hide-scrollbars",
|
|
5909
|
-
"--no-default-browser-check",
|
|
5910
|
-
"--no-pings",
|
|
5911
|
-
"--font-render-hinting=none",
|
|
5912
|
-
"--no-zygote",
|
|
5913
|
-
"--ignore-gpu-blocklist",
|
|
5914
|
-
"--enable-unsafe-webgpu",
|
|
5915
|
-
typeof forceDeviceScaleFactor === "undefined" ? null : `--force-device-scale-factor=${forceDeviceScaleFactor}`,
|
|
5916
|
-
chromiumOptions.ignoreCertificateErrors ? "--ignore-certificate-errors" : null,
|
|
5917
|
-
...chromiumOptions?.disableWebSecurity ? ["--disable-web-security"] : [],
|
|
5918
|
-
chromiumOptions?.userAgent ? `--user-agent="${chromiumOptions.userAgent}"` : null,
|
|
5919
|
-
"--remote-debugging-port=0",
|
|
5920
|
-
`--user-data-dir=${userDataDir}`
|
|
5921
|
-
].filter(Boolean),
|
|
5922
|
-
defaultViewport: viewport ?? {
|
|
5923
|
-
height: 720,
|
|
5924
|
-
width: 1280,
|
|
5925
|
-
deviceScaleFactor: 1
|
|
5926
|
-
}
|
|
5927
|
-
});
|
|
5928
|
-
const pages = await browserInstance.pages();
|
|
5929
|
-
await pages[0]?.close();
|
|
5930
|
-
return browserInstance;
|
|
5931
|
-
};
|
|
5932
|
-
var openBrowser = (browser, options) => {
|
|
5933
|
-
const { browserExecutable, chromiumOptions, forceDeviceScaleFactor } = options ?? {};
|
|
5934
|
-
const indent = false;
|
|
5935
|
-
const logLevel = options?.logLevel ?? (options?.shouldDumpIo ? "verbose" : "info");
|
|
5936
|
-
return internalOpenBrowser({
|
|
5937
|
-
browser,
|
|
5938
|
-
browserExecutable: browserExecutable ?? null,
|
|
5939
|
-
chromiumOptions: chromiumOptions ?? {},
|
|
5940
|
-
forceDeviceScaleFactor,
|
|
5941
|
-
indent,
|
|
5942
|
-
viewport: null,
|
|
5943
|
-
logLevel,
|
|
5944
|
-
onBrowserDownload: defaultBrowserDownloadProgress({
|
|
5945
|
-
indent,
|
|
5946
|
-
logLevel,
|
|
5947
|
-
api: "openBrowser()"
|
|
5948
|
-
}),
|
|
5949
|
-
chromeMode: options?.chromeMode ?? "headless-shell"
|
|
5950
|
-
});
|
|
5951
|
-
};
|
|
5952
|
-
|
|
5953
|
-
// src/get-browser-instance.ts
|
|
5954
|
-
var getPageAndCleanupFn = async ({
|
|
5955
|
-
passedInInstance,
|
|
5956
|
-
browserExecutable,
|
|
5957
|
-
chromiumOptions,
|
|
5958
|
-
forceDeviceScaleFactor,
|
|
5959
|
-
indent,
|
|
5960
|
-
logLevel,
|
|
5961
|
-
onBrowserDownload,
|
|
5962
|
-
chromeMode,
|
|
5963
|
-
pageIndex,
|
|
5964
|
-
onBrowserLog
|
|
5965
|
-
}) => {
|
|
5966
|
-
if (passedInInstance) {
|
|
5967
|
-
const page = await passedInInstance.newPage({
|
|
5968
|
-
context: () => null,
|
|
5969
|
-
logLevel,
|
|
5970
|
-
indent,
|
|
5971
|
-
pageIndex,
|
|
5972
|
-
onBrowserLog
|
|
5973
|
-
});
|
|
5974
|
-
return {
|
|
5975
|
-
page,
|
|
5976
|
-
cleanupPage: () => {
|
|
5977
|
-
page.close().catch((err) => {
|
|
5978
|
-
if (!err.message.includes("Target closed")) {
|
|
5979
|
-
Log.error({ indent, logLevel }, "Was not able to close puppeteer page", err);
|
|
5980
|
-
}
|
|
5981
|
-
});
|
|
5982
|
-
return Promise.resolve();
|
|
5983
|
-
}
|
|
5984
|
-
};
|
|
5985
|
-
}
|
|
5986
|
-
const browserInstance = await internalOpenBrowser({
|
|
5987
|
-
browser: DEFAULT_BROWSER,
|
|
5988
|
-
browserExecutable,
|
|
5989
|
-
chromiumOptions,
|
|
5990
|
-
forceDeviceScaleFactor,
|
|
5991
|
-
indent,
|
|
5992
|
-
viewport: null,
|
|
5993
|
-
logLevel,
|
|
5994
|
-
onBrowserDownload,
|
|
5995
|
-
chromeMode
|
|
5996
|
-
});
|
|
5997
|
-
const browserPage = await browserInstance.newPage({
|
|
5998
|
-
context: () => null,
|
|
5999
|
-
logLevel,
|
|
6000
|
-
indent,
|
|
6001
|
-
pageIndex,
|
|
6002
|
-
onBrowserLog
|
|
6003
|
-
});
|
|
6004
|
-
return {
|
|
6005
|
-
page: browserPage,
|
|
6006
|
-
cleanupPage: () => {
|
|
6007
|
-
browserInstance.close({ silent: true }).catch((err) => {
|
|
6008
|
-
if (!err.message.includes("Target closed")) {
|
|
6009
|
-
Log.error({ indent, logLevel }, "Was not able to close puppeteer page", err);
|
|
6010
|
-
}
|
|
6011
|
-
});
|
|
6012
|
-
return Promise.resolve();
|
|
6013
|
-
}
|
|
6014
|
-
};
|
|
6015
|
-
};
|
|
6016
|
-
|
|
6017
|
-
// src/options/offthreadvideo-threads.tsx
|
|
6018
|
-
import { jsx as jsx2, jsxs as jsxs2, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
6019
|
-
var DEFAULT_RENDER_FRAMES_OFFTHREAD_VIDEO_THREADS = 2;
|
|
6020
|
-
|
|
6021
|
-
// src/prepare-server.ts
|
|
6022
|
-
import { existsSync as existsSync4 } from "node:fs";
|
|
6023
|
-
import path18 from "node:path";
|
|
6024
|
-
import { NoReactInternals as NoReactInternals7 } from "remotion/no-react";
|
|
6025
|
-
|
|
6026
|
-
// src/assets/download-and-map-assets-to-file.ts
|
|
6027
|
-
import fs10 from "node:fs";
|
|
6028
|
-
import path11, { extname as extname2 } from "node:path";
|
|
6029
|
-
import { random } from "remotion/no-react";
|
|
6030
|
-
|
|
6031
|
-
// src/compress-assets.ts
|
|
6032
|
-
var compressAsset = (previousRenderAssets, newRenderAsset) => {
|
|
6033
|
-
if (newRenderAsset.src.length < 400) {
|
|
6034
|
-
return newRenderAsset;
|
|
6035
|
-
}
|
|
6036
|
-
const assetWithSameSrc = previousRenderAssets.find((a) => a.src === newRenderAsset.src);
|
|
6037
|
-
if (!assetWithSameSrc) {
|
|
6038
|
-
return newRenderAsset;
|
|
6039
|
-
}
|
|
6040
|
-
return {
|
|
6041
|
-
...newRenderAsset,
|
|
6042
|
-
src: `same-as-${assetWithSameSrc.id}-${assetWithSameSrc.frame}`
|
|
6043
|
-
};
|
|
6044
|
-
};
|
|
6045
|
-
var isAssetCompressed = (src) => {
|
|
6046
|
-
return src.startsWith("same-as");
|
|
5278
|
+
var isAssetCompressed = (src) => {
|
|
5279
|
+
return src.startsWith("same-as");
|
|
6047
5280
|
};
|
|
6048
5281
|
|
|
6049
5282
|
// src/mime-types.ts
|
|
@@ -16738,7 +15971,7 @@ var seekToFrame = async ({
|
|
|
16738
15971
|
};
|
|
16739
15972
|
|
|
16740
15973
|
// src/set-props-and-env.ts
|
|
16741
|
-
import { VERSION as
|
|
15974
|
+
import { VERSION as VERSION2 } from "remotion/version";
|
|
16742
15975
|
|
|
16743
15976
|
// src/goto-page-or-throw.ts
|
|
16744
15977
|
var gotoPageOrThrow = async (page, urlToVisit, actualTimeout) => {
|
|
@@ -16927,7 +16160,7 @@ var innerSetPropsAndEnv = async ({
|
|
|
16927
16160
|
throw new Error([
|
|
16928
16161
|
`Incompatible site: When visiting ${urlToVisit}, a bundle was found, but one that is not compatible with this version of Remotion. Found version: ${siteVersion} - Required version: ${requiredVersion}. To resolve this error:`,
|
|
16929
16162
|
"When using server-side rendering:",
|
|
16930
|
-
` ▸ Use 'bundle()' with '@remotion/bundler' of version ${
|
|
16163
|
+
` ▸ Use 'bundle()' with '@remotion/bundler' of version ${VERSION2} to create a compatible bundle.`,
|
|
16931
16164
|
"When using the Remotion Lambda:",
|
|
16932
16165
|
" ▸ Use `npx remotion lambda sites create` to redeploy the site with the latest version.",
|
|
16933
16166
|
" ℹ Use --site-name with the same name as before to overwrite your site.",
|
|
@@ -16935,13 +16168,13 @@ var innerSetPropsAndEnv = async ({
|
|
|
16935
16168
|
].join(`
|
|
16936
16169
|
`));
|
|
16937
16170
|
}
|
|
16938
|
-
if (remotionVersion !==
|
|
16171
|
+
if (remotionVersion !== VERSION2 && true) {
|
|
16939
16172
|
if (remotionVersion) {
|
|
16940
16173
|
Log.warn({
|
|
16941
16174
|
indent,
|
|
16942
16175
|
logLevel
|
|
16943
16176
|
}, [
|
|
16944
|
-
`The site was bundled with version ${remotionVersion} of @remotion/bundler, while @remotion/renderer is on version ${
|
|
16177
|
+
`The site was bundled with version ${remotionVersion} of @remotion/bundler, while @remotion/renderer is on version ${VERSION2}. You may not have the newest bugfixes and features.`,
|
|
16945
16178
|
`To resolve this warning:`,
|
|
16946
16179
|
"▸ Use `npx remotion lambda sites create` to redeploy the site with the latest version.",
|
|
16947
16180
|
" ℹ Use --site-name with the same name as before to overwrite your site.",
|
|
@@ -16952,7 +16185,7 @@ var innerSetPropsAndEnv = async ({
|
|
|
16952
16185
|
Log.warn({
|
|
16953
16186
|
indent,
|
|
16954
16187
|
logLevel
|
|
16955
|
-
}, `The site was bundled with an old version of Remotion, while @remotion/renderer is on version ${
|
|
16188
|
+
}, `The site was bundled with an old version of Remotion, while @remotion/renderer is on version ${VERSION2}. You may not have the newest bugfixes and features. Re-bundle the site to fix this issue.`);
|
|
16956
16189
|
}
|
|
16957
16190
|
}
|
|
16958
16191
|
};
|
|
@@ -17065,6 +16298,14 @@ var printUsefulErrorMessage = (err, logLevel, indent) => {
|
|
|
17065
16298
|
Log.info({ indent, logLevel }, "\uD83D\uDCA1 On Lambda, one reason this could happen is that Chrome is rejecting an asset to be loaded when it is running low on disk space.");
|
|
17066
16299
|
Log.info({ indent, logLevel }, "Try increasing the disk size of your Lambda function.");
|
|
17067
16300
|
}
|
|
16301
|
+
if (err.message.includes("Invalid value specified for cpu")) {
|
|
16302
|
+
Log.info({ indent, logLevel });
|
|
16303
|
+
Log.info({ indent, logLevel }, "\uD83D\uDCA1 This error indicates that your GCP account does have a limit. Try setting `--maxInstances=5` / `maxInstances: 5` when deploying this service.");
|
|
16304
|
+
Log.info({
|
|
16305
|
+
indent,
|
|
16306
|
+
logLevel
|
|
16307
|
+
});
|
|
16308
|
+
}
|
|
17068
16309
|
};
|
|
17069
16310
|
|
|
17070
16311
|
// src/wrap-with-error-handling.ts
|
|
@@ -17311,332 +16552,810 @@ var resolveConcurrency = (userPreference) => {
|
|
|
17311
16552
|
} else {
|
|
17312
16553
|
rounded = Math.floor(userPreference);
|
|
17313
16554
|
}
|
|
17314
|
-
if (rounded > maxCpus) {
|
|
17315
|
-
throw new Error(`Maximum for --concurrency is ${maxCpus} (number of cores on this system)`);
|
|
16555
|
+
if (rounded > maxCpus) {
|
|
16556
|
+
throw new Error(`Maximum for --concurrency is ${maxCpus} (number of cores on this system)`);
|
|
16557
|
+
}
|
|
16558
|
+
if (rounded < min) {
|
|
16559
|
+
throw new Error(`Minimum for concurrency is ${min}.`);
|
|
16560
|
+
}
|
|
16561
|
+
return rounded;
|
|
16562
|
+
};
|
|
16563
|
+
|
|
16564
|
+
// src/get-duration-from-frame-range.ts
|
|
16565
|
+
var getFramesToRender = (frameRange, everyNthFrame) => {
|
|
16566
|
+
if (everyNthFrame === 0) {
|
|
16567
|
+
throw new Error("everyNthFrame cannot be 0");
|
|
16568
|
+
}
|
|
16569
|
+
return new Array(frameRange[1] - frameRange[0] + 1).fill(true).map((_, index) => {
|
|
16570
|
+
return index + frameRange[0];
|
|
16571
|
+
}).filter((index) => {
|
|
16572
|
+
return index % everyNthFrame === 0;
|
|
16573
|
+
});
|
|
16574
|
+
};
|
|
16575
|
+
|
|
16576
|
+
// src/get-extension-from-codec.ts
|
|
16577
|
+
var getFileExtensionFromCodec = (codec, audioCodec) => {
|
|
16578
|
+
if (!validCodecs.includes(codec)) {
|
|
16579
|
+
throw new Error(`Codec must be one of the following: ${validCodecs.join(", ")}, but got ${codec}`);
|
|
16580
|
+
}
|
|
16581
|
+
const map2 = defaultFileExtensionMap[codec];
|
|
16582
|
+
if (audioCodec === null) {
|
|
16583
|
+
return map2.default;
|
|
16584
|
+
}
|
|
16585
|
+
const typedAudioCodec = audioCodec;
|
|
16586
|
+
if (!(typedAudioCodec in map2.forAudioCodec)) {
|
|
16587
|
+
throw new Error(`Audio codec ${typedAudioCodec} is not supported for codec ${codec}`);
|
|
16588
|
+
}
|
|
16589
|
+
return map2.forAudioCodec[audioCodec].default;
|
|
16590
|
+
};
|
|
16591
|
+
var makeFileExtensionMap = () => {
|
|
16592
|
+
const map2 = {};
|
|
16593
|
+
Object.keys(defaultFileExtensionMap).forEach((_codec) => {
|
|
16594
|
+
const codec = _codec;
|
|
16595
|
+
const fileExtMap = defaultFileExtensionMap[codec];
|
|
16596
|
+
const audioCodecs = Object.keys(fileExtMap.forAudioCodec);
|
|
16597
|
+
const possibleExtensionsForAudioCodec = audioCodecs.map((audioCodec) => fileExtMap.forAudioCodec[audioCodec].possible);
|
|
16598
|
+
const allPossibleExtensions = [
|
|
16599
|
+
fileExtMap.default,
|
|
16600
|
+
...possibleExtensionsForAudioCodec.flat(1)
|
|
16601
|
+
];
|
|
16602
|
+
for (const extension of allPossibleExtensions) {
|
|
16603
|
+
if (!map2[extension]) {
|
|
16604
|
+
map2[extension] = [];
|
|
16605
|
+
}
|
|
16606
|
+
if (!map2[extension].includes(codec)) {
|
|
16607
|
+
map2[extension].push(codec);
|
|
16608
|
+
}
|
|
16609
|
+
}
|
|
16610
|
+
});
|
|
16611
|
+
return map2;
|
|
16612
|
+
};
|
|
16613
|
+
var defaultCodecsForFileExtension = {
|
|
16614
|
+
"3gp": "aac",
|
|
16615
|
+
aac: "aac",
|
|
16616
|
+
gif: "gif",
|
|
16617
|
+
hevc: "h265",
|
|
16618
|
+
m4a: "aac",
|
|
16619
|
+
m4b: "aac",
|
|
16620
|
+
mkv: "h264-mkv",
|
|
16621
|
+
mov: "prores",
|
|
16622
|
+
mp3: "mp3",
|
|
16623
|
+
mp4: "h264",
|
|
16624
|
+
mpeg: "aac",
|
|
16625
|
+
mpg: "aac",
|
|
16626
|
+
mxf: "prores",
|
|
16627
|
+
wav: "wav",
|
|
16628
|
+
webm: "vp8",
|
|
16629
|
+
ts: "h264-ts"
|
|
16630
|
+
};
|
|
16631
|
+
|
|
16632
|
+
// src/path-normalize.ts
|
|
16633
|
+
var SLASH = 47;
|
|
16634
|
+
var DOT = 46;
|
|
16635
|
+
var assertPath = (path19) => {
|
|
16636
|
+
const t = typeof path19;
|
|
16637
|
+
if (t !== "string") {
|
|
16638
|
+
throw new TypeError(`Expected a string, got a ${t}`);
|
|
16639
|
+
}
|
|
16640
|
+
};
|
|
16641
|
+
var posixNormalize = (path19, allowAboveRoot) => {
|
|
16642
|
+
let res = "";
|
|
16643
|
+
let lastSegmentLength = 0;
|
|
16644
|
+
let lastSlash = -1;
|
|
16645
|
+
let dots = 0;
|
|
16646
|
+
let code;
|
|
16647
|
+
for (let i = 0;i <= path19.length; ++i) {
|
|
16648
|
+
if (i < path19.length) {
|
|
16649
|
+
code = path19.charCodeAt(i);
|
|
16650
|
+
} else if (code === SLASH) {
|
|
16651
|
+
break;
|
|
16652
|
+
} else {
|
|
16653
|
+
code = SLASH;
|
|
16654
|
+
}
|
|
16655
|
+
if (code === SLASH) {
|
|
16656
|
+
if (lastSlash === i - 1 || dots === 1) {
|
|
16657
|
+
} else if (lastSlash !== i - 1 && dots === 2) {
|
|
16658
|
+
if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== DOT || res.charCodeAt(res.length - 2) !== DOT) {
|
|
16659
|
+
if (res.length > 2) {
|
|
16660
|
+
const lastSlashIndex = res.lastIndexOf("/");
|
|
16661
|
+
if (lastSlashIndex !== res.length - 1) {
|
|
16662
|
+
if (lastSlashIndex === -1) {
|
|
16663
|
+
res = "";
|
|
16664
|
+
lastSegmentLength = 0;
|
|
16665
|
+
} else {
|
|
16666
|
+
res = res.slice(0, lastSlashIndex);
|
|
16667
|
+
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
|
|
16668
|
+
}
|
|
16669
|
+
lastSlash = i;
|
|
16670
|
+
dots = 0;
|
|
16671
|
+
continue;
|
|
16672
|
+
}
|
|
16673
|
+
} else if (res.length === 2 || res.length === 1) {
|
|
16674
|
+
res = "";
|
|
16675
|
+
lastSegmentLength = 0;
|
|
16676
|
+
lastSlash = i;
|
|
16677
|
+
dots = 0;
|
|
16678
|
+
continue;
|
|
16679
|
+
}
|
|
16680
|
+
}
|
|
16681
|
+
if (allowAboveRoot) {
|
|
16682
|
+
if (res.length > 0) {
|
|
16683
|
+
res += "/..";
|
|
16684
|
+
} else {
|
|
16685
|
+
res = "..";
|
|
16686
|
+
}
|
|
16687
|
+
lastSegmentLength = 2;
|
|
16688
|
+
}
|
|
16689
|
+
} else {
|
|
16690
|
+
if (res.length > 0) {
|
|
16691
|
+
res += "/" + path19.slice(lastSlash + 1, i);
|
|
16692
|
+
} else {
|
|
16693
|
+
res = path19.slice(lastSlash + 1, i);
|
|
16694
|
+
}
|
|
16695
|
+
lastSegmentLength = i - lastSlash - 1;
|
|
16696
|
+
}
|
|
16697
|
+
lastSlash = i;
|
|
16698
|
+
dots = 0;
|
|
16699
|
+
} else if (code === DOT && dots !== -1) {
|
|
16700
|
+
++dots;
|
|
16701
|
+
} else {
|
|
16702
|
+
dots = -1;
|
|
16703
|
+
}
|
|
16704
|
+
}
|
|
16705
|
+
return res;
|
|
16706
|
+
};
|
|
16707
|
+
var decode = (s) => {
|
|
16708
|
+
try {
|
|
16709
|
+
return decodeURIComponent(s);
|
|
16710
|
+
} catch {
|
|
16711
|
+
return s;
|
|
16712
|
+
}
|
|
16713
|
+
};
|
|
16714
|
+
var pathNormalize = (p) => {
|
|
16715
|
+
assertPath(p);
|
|
16716
|
+
let path19 = p;
|
|
16717
|
+
if (path19.length === 0) {
|
|
16718
|
+
return ".";
|
|
16719
|
+
}
|
|
16720
|
+
const isAbsolute = path19.charCodeAt(0) === SLASH;
|
|
16721
|
+
const trailingSeparator = path19.charCodeAt(path19.length - 1) === SLASH;
|
|
16722
|
+
path19 = decode(path19);
|
|
16723
|
+
path19 = posixNormalize(path19, !isAbsolute);
|
|
16724
|
+
if (path19.length === 0 && !isAbsolute) {
|
|
16725
|
+
path19 = ".";
|
|
16726
|
+
}
|
|
16727
|
+
if (path19.length > 0 && trailingSeparator) {
|
|
16728
|
+
path19 += "/";
|
|
16729
|
+
}
|
|
16730
|
+
if (isAbsolute) {
|
|
16731
|
+
return "/" + path19;
|
|
16732
|
+
}
|
|
16733
|
+
return path19;
|
|
16734
|
+
};
|
|
16735
|
+
|
|
16736
|
+
// src/get-extension-of-filename.ts
|
|
16737
|
+
var getExtensionOfFilename = (filename) => {
|
|
16738
|
+
if (filename === null) {
|
|
16739
|
+
return null;
|
|
16740
|
+
}
|
|
16741
|
+
const filenameArr = pathNormalize(filename).split(".");
|
|
16742
|
+
const hasExtension = filenameArr.length >= 2;
|
|
16743
|
+
const filenameArrLength = filenameArr.length;
|
|
16744
|
+
const extension = hasExtension ? filenameArr[filenameArrLength - 1] : null;
|
|
16745
|
+
return extension;
|
|
16746
|
+
};
|
|
16747
|
+
|
|
16748
|
+
// src/get-frame-to-render.ts
|
|
16749
|
+
var getRealFrameRange = (durationInFrames, frameRange) => {
|
|
16750
|
+
if (frameRange === null) {
|
|
16751
|
+
return [0, durationInFrames - 1];
|
|
16752
|
+
}
|
|
16753
|
+
if (typeof frameRange === "number") {
|
|
16754
|
+
if (frameRange < 0 || frameRange >= durationInFrames) {
|
|
16755
|
+
throw new Error(`Frame number is out of range, must be between 0 and ${durationInFrames - 1} but got ${frameRange}`);
|
|
16756
|
+
}
|
|
16757
|
+
return [frameRange, frameRange];
|
|
16758
|
+
}
|
|
16759
|
+
if (frameRange[1] >= durationInFrames || frameRange[0] < 0) {
|
|
16760
|
+
throw new Error(`The "durationInFrames" of the <Composition /> was evaluated to be ${durationInFrames}, but frame range ${frameRange.join("-")} is not inbetween 0-${durationInFrames - 1}`);
|
|
16761
|
+
}
|
|
16762
|
+
return frameRange;
|
|
16763
|
+
};
|
|
16764
|
+
|
|
16765
|
+
// src/image-format.ts
|
|
16766
|
+
var validVideoImageFormats = ["png", "jpeg", "none"];
|
|
16767
|
+
var validStillImageFormats = ["png", "jpeg", "pdf", "webp"];
|
|
16768
|
+
var DEFAULT_VIDEO_IMAGE_FORMAT = "jpeg";
|
|
16769
|
+
var DEFAULT_STILL_IMAGE_FORMAT = "png";
|
|
16770
|
+
var validateSelectedPixelFormatAndImageFormatCombination = (pixelFormat, videoImageFormat) => {
|
|
16771
|
+
if (videoImageFormat === "none") {
|
|
16772
|
+
return "none";
|
|
16773
|
+
}
|
|
16774
|
+
if (typeof pixelFormat === "undefined") {
|
|
16775
|
+
return "valid";
|
|
16776
|
+
}
|
|
16777
|
+
if (!validVideoImageFormats.includes(videoImageFormat)) {
|
|
16778
|
+
throw new TypeError(`Value ${videoImageFormat} is not valid as an image format.`);
|
|
16779
|
+
}
|
|
16780
|
+
if (pixelFormat !== "yuva420p" && pixelFormat !== "yuva444p10le") {
|
|
16781
|
+
return "valid";
|
|
16782
|
+
}
|
|
16783
|
+
if (videoImageFormat !== "png") {
|
|
16784
|
+
throw new TypeError(`Pixel format was set to '${pixelFormat}' but the image format is not PNG. To render transparent videos, you need to set PNG as the image format.`);
|
|
16785
|
+
}
|
|
16786
|
+
return "valid";
|
|
16787
|
+
};
|
|
16788
|
+
var validateStillImageFormat = (imageFormat) => {
|
|
16789
|
+
if (!validStillImageFormats.includes(imageFormat)) {
|
|
16790
|
+
throw new TypeError(String(`Image format should be one of: ${validStillImageFormats.map((v) => `"${v}"`).join(", ")}`));
|
|
16791
|
+
}
|
|
16792
|
+
};
|
|
16793
|
+
|
|
16794
|
+
// src/jpeg-quality.ts
|
|
16795
|
+
var DEFAULT_JPEG_QUALITY = 80;
|
|
16796
|
+
var validateJpegQuality = (q) => {
|
|
16797
|
+
if (typeof q !== "undefined" && typeof q !== "number") {
|
|
16798
|
+
throw new Error(`JPEG Quality option must be a number or undefined. Got ${typeof q} (${JSON.stringify(q)})`);
|
|
16799
|
+
}
|
|
16800
|
+
if (typeof q === "undefined") {
|
|
16801
|
+
return;
|
|
16802
|
+
}
|
|
16803
|
+
if (!Number.isFinite(q)) {
|
|
16804
|
+
throw new RangeError(`JPEG Quality must be a finite number, but is ${q}`);
|
|
16805
|
+
}
|
|
16806
|
+
if (Number.isNaN(q)) {
|
|
16807
|
+
throw new RangeError(`JPEG Quality is NaN, but must be a real number`);
|
|
16808
|
+
}
|
|
16809
|
+
if (q > 100 || q < 0) {
|
|
16810
|
+
throw new RangeError("JPEG Quality option must be between 0 and 100.");
|
|
16811
|
+
}
|
|
16812
|
+
};
|
|
16813
|
+
|
|
16814
|
+
// src/perf.ts
|
|
16815
|
+
var exports_perf = {};
|
|
16816
|
+
__export(exports_perf, {
|
|
16817
|
+
stopPerfMeasure: () => stopPerfMeasure,
|
|
16818
|
+
startPerfMeasure: () => startPerfMeasure,
|
|
16819
|
+
getPerf: () => getPerf
|
|
16820
|
+
});
|
|
16821
|
+
var perf = {
|
|
16822
|
+
"activate-target": [],
|
|
16823
|
+
capture: [],
|
|
16824
|
+
save: [],
|
|
16825
|
+
"extract-frame": [],
|
|
16826
|
+
piping: []
|
|
16827
|
+
};
|
|
16828
|
+
var map2 = {};
|
|
16829
|
+
var startPerfMeasure = (marker) => {
|
|
16830
|
+
const id = Math.random();
|
|
16831
|
+
map2[id] = {
|
|
16832
|
+
id,
|
|
16833
|
+
marker,
|
|
16834
|
+
start: Date.now()
|
|
16835
|
+
};
|
|
16836
|
+
return id;
|
|
16837
|
+
};
|
|
16838
|
+
var stopPerfMeasure = (id) => {
|
|
16839
|
+
const now = Date.now();
|
|
16840
|
+
const diff = now - map2[id].start;
|
|
16841
|
+
perf[map2[id].marker].push(diff);
|
|
16842
|
+
delete map2[id];
|
|
16843
|
+
};
|
|
16844
|
+
var getPerf = () => {
|
|
16845
|
+
return [
|
|
16846
|
+
"Render performance:",
|
|
16847
|
+
...Object.keys(perf).filter((p) => perf[p].length).map((p) => {
|
|
16848
|
+
return ` ${p} => ${Math.round(perf[p].reduce((a, b) => a + b, 0) / perf[p].length)}ms (n = ${perf[p].length})`;
|
|
16849
|
+
})
|
|
16850
|
+
];
|
|
16851
|
+
};
|
|
16852
|
+
|
|
16853
|
+
// src/pixel-format.ts
|
|
16854
|
+
var validPixelFormats = [
|
|
16855
|
+
"yuv420p",
|
|
16856
|
+
"yuva420p",
|
|
16857
|
+
"yuv422p",
|
|
16858
|
+
"yuv444p",
|
|
16859
|
+
"yuv420p10le",
|
|
16860
|
+
"yuv422p10le",
|
|
16861
|
+
"yuv444p10le",
|
|
16862
|
+
"yuva444p10le"
|
|
16863
|
+
];
|
|
16864
|
+
var DEFAULT_PIXEL_FORMAT = "yuv420p";
|
|
16865
|
+
var validPixelFormatsForCodec = (codec) => {
|
|
16866
|
+
if (codec === "vp8" || codec === "vp9") {
|
|
16867
|
+
return validPixelFormats;
|
|
16868
|
+
}
|
|
16869
|
+
return validPixelFormats.filter((format) => format !== "yuva420p");
|
|
16870
|
+
};
|
|
16871
|
+
var validateSelectedPixelFormatAndCodecCombination = (pixelFormat, codec) => {
|
|
16872
|
+
if (typeof pixelFormat === "undefined") {
|
|
16873
|
+
return pixelFormat;
|
|
16874
|
+
}
|
|
16875
|
+
if (!validPixelFormats.includes(pixelFormat)) {
|
|
16876
|
+
throw new TypeError(`Value ${pixelFormat} is not valid as a pixel format.`);
|
|
16877
|
+
}
|
|
16878
|
+
if (pixelFormat !== "yuva420p") {
|
|
16879
|
+
return;
|
|
17316
16880
|
}
|
|
17317
|
-
|
|
17318
|
-
|
|
16881
|
+
const validFormats = validPixelFormatsForCodec(codec);
|
|
16882
|
+
if (!validFormats.includes(pixelFormat)) {
|
|
16883
|
+
throw new TypeError(`Pixel format was set to 'yuva420p' but codec ${codec} does not support it. Valid pixel formats for codec ${codec} are: ${validFormats.join(", ")}.`);
|
|
17319
16884
|
}
|
|
17320
|
-
return rounded;
|
|
17321
16885
|
};
|
|
17322
16886
|
|
|
17323
|
-
// src/
|
|
17324
|
-
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
}
|
|
17328
|
-
return new Array(frameRange[1] - frameRange[0] + 1).fill(true).map((_, index) => {
|
|
17329
|
-
return index + frameRange[0];
|
|
17330
|
-
}).filter((index) => {
|
|
17331
|
-
return index % everyNthFrame === 0;
|
|
17332
|
-
});
|
|
17333
|
-
};
|
|
16887
|
+
// src/render-frames.ts
|
|
16888
|
+
import fs14 from "node:fs";
|
|
16889
|
+
import path20 from "node:path";
|
|
16890
|
+
import { NoReactInternals as NoReactInternals12 } from "remotion/no-react";
|
|
17334
16891
|
|
|
17335
|
-
// src/
|
|
17336
|
-
var
|
|
17337
|
-
|
|
17338
|
-
|
|
17339
|
-
|
|
17340
|
-
|
|
17341
|
-
|
|
16892
|
+
// src/cycle-browser-tabs.ts
|
|
16893
|
+
var cycleBrowserTabs = ({
|
|
16894
|
+
puppeteerInstance,
|
|
16895
|
+
concurrency,
|
|
16896
|
+
logLevel,
|
|
16897
|
+
indent
|
|
16898
|
+
}) => {
|
|
16899
|
+
if (concurrency <= 1) {
|
|
16900
|
+
return {
|
|
16901
|
+
stopCycling: () => {
|
|
16902
|
+
return;
|
|
16903
|
+
}
|
|
16904
|
+
};
|
|
17342
16905
|
}
|
|
17343
|
-
|
|
17344
|
-
|
|
17345
|
-
let
|
|
17346
|
-
|
|
17347
|
-
|
|
17348
|
-
|
|
17349
|
-
|
|
17350
|
-
|
|
17351
|
-
if (i < path19.length) {
|
|
17352
|
-
code = path19.charCodeAt(i);
|
|
17353
|
-
} else if (code === SLASH) {
|
|
17354
|
-
break;
|
|
17355
|
-
} else {
|
|
17356
|
-
code = SLASH;
|
|
17357
|
-
}
|
|
17358
|
-
if (code === SLASH) {
|
|
17359
|
-
if (lastSlash === i - 1 || dots === 1) {
|
|
17360
|
-
} else if (lastSlash !== i - 1 && dots === 2) {
|
|
17361
|
-
if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== DOT || res.charCodeAt(res.length - 2) !== DOT) {
|
|
17362
|
-
if (res.length > 2) {
|
|
17363
|
-
const lastSlashIndex = res.lastIndexOf("/");
|
|
17364
|
-
if (lastSlashIndex !== res.length - 1) {
|
|
17365
|
-
if (lastSlashIndex === -1) {
|
|
17366
|
-
res = "";
|
|
17367
|
-
lastSegmentLength = 0;
|
|
17368
|
-
} else {
|
|
17369
|
-
res = res.slice(0, lastSlashIndex);
|
|
17370
|
-
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
|
|
17371
|
-
}
|
|
17372
|
-
lastSlash = i;
|
|
17373
|
-
dots = 0;
|
|
17374
|
-
continue;
|
|
17375
|
-
}
|
|
17376
|
-
} else if (res.length === 2 || res.length === 1) {
|
|
17377
|
-
res = "";
|
|
17378
|
-
lastSegmentLength = 0;
|
|
17379
|
-
lastSlash = i;
|
|
17380
|
-
dots = 0;
|
|
17381
|
-
continue;
|
|
17382
|
-
}
|
|
16906
|
+
let interval = null;
|
|
16907
|
+
let i = 0;
|
|
16908
|
+
let stopped = false;
|
|
16909
|
+
const set = () => {
|
|
16910
|
+
interval = setTimeout(() => {
|
|
16911
|
+
puppeteerInstance.getBrowser().pages().then((pages) => {
|
|
16912
|
+
if (pages.length === 0) {
|
|
16913
|
+
return;
|
|
17383
16914
|
}
|
|
17384
|
-
|
|
17385
|
-
|
|
17386
|
-
|
|
17387
|
-
|
|
17388
|
-
res = "..";
|
|
17389
|
-
}
|
|
17390
|
-
lastSegmentLength = 2;
|
|
16915
|
+
const currentPage = pages[i % pages.length];
|
|
16916
|
+
i++;
|
|
16917
|
+
if (!currentPage?.closed && !stopped && currentPage?.url() !== "about:blank") {
|
|
16918
|
+
return currentPage.bringToFront();
|
|
17391
16919
|
}
|
|
17392
|
-
}
|
|
17393
|
-
if (
|
|
17394
|
-
|
|
17395
|
-
} else {
|
|
17396
|
-
res = path19.slice(lastSlash + 1, i);
|
|
16920
|
+
}).catch((err) => Log.error({ indent, logLevel }, err)).finally(() => {
|
|
16921
|
+
if (!stopped) {
|
|
16922
|
+
set();
|
|
17397
16923
|
}
|
|
17398
|
-
|
|
16924
|
+
});
|
|
16925
|
+
}, 200);
|
|
16926
|
+
};
|
|
16927
|
+
set();
|
|
16928
|
+
return {
|
|
16929
|
+
stopCycling: () => {
|
|
16930
|
+
if (!interval) {
|
|
16931
|
+
return;
|
|
17399
16932
|
}
|
|
17400
|
-
|
|
17401
|
-
|
|
17402
|
-
} else if (code === DOT && dots !== -1) {
|
|
17403
|
-
++dots;
|
|
17404
|
-
} else {
|
|
17405
|
-
dots = -1;
|
|
16933
|
+
stopped = true;
|
|
16934
|
+
return clearTimeout(interval);
|
|
17406
16935
|
}
|
|
17407
|
-
}
|
|
17408
|
-
return res;
|
|
16936
|
+
};
|
|
17409
16937
|
};
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
|
|
17415
|
-
|
|
16938
|
+
|
|
16939
|
+
// src/combine-audio.ts
|
|
16940
|
+
import { rmSync as rmSync2, writeFileSync } from "fs";
|
|
16941
|
+
import { join as join3 } from "path";
|
|
16942
|
+
import { VERSION as VERSION3 } from "remotion/version";
|
|
16943
|
+
|
|
16944
|
+
// src/options/separate-audio.tsx
|
|
16945
|
+
var DEFAULT = null;
|
|
16946
|
+
var cliFlag = "separate-audio-to";
|
|
16947
|
+
var separateAudioOption = {
|
|
16948
|
+
cliFlag,
|
|
16949
|
+
description: () => `If set, the audio will not be included in the main output but rendered as a separate file at the location you pass. It is recommended to use an absolute path. If a relative path is passed, it is relative to the Remotion Root.`,
|
|
16950
|
+
docLink: "https://remotion.dev/docs/renderer/render-media",
|
|
16951
|
+
getValue: ({ commandLine }) => {
|
|
16952
|
+
if (commandLine[cliFlag]) {
|
|
16953
|
+
return {
|
|
16954
|
+
source: "cli",
|
|
16955
|
+
value: commandLine[cliFlag]
|
|
16956
|
+
};
|
|
16957
|
+
}
|
|
16958
|
+
return {
|
|
16959
|
+
source: "default",
|
|
16960
|
+
value: DEFAULT
|
|
16961
|
+
};
|
|
16962
|
+
},
|
|
16963
|
+
name: "Separate audio to",
|
|
16964
|
+
setConfig: () => {
|
|
16965
|
+
throw new Error("Not implemented");
|
|
16966
|
+
},
|
|
16967
|
+
ssrName: "separateAudioTo",
|
|
16968
|
+
type: "string"
|
|
17416
16969
|
};
|
|
17417
|
-
|
|
17418
|
-
|
|
17419
|
-
|
|
17420
|
-
|
|
17421
|
-
|
|
16970
|
+
|
|
16971
|
+
// src/options/audio-codec.tsx
|
|
16972
|
+
var validAudioCodecs = ["pcm-16", "aac", "mp3", "opus"];
|
|
16973
|
+
var supportedAudioCodecs = {
|
|
16974
|
+
h264: ["aac", "pcm-16", "mp3"],
|
|
16975
|
+
"h264-mkv": ["pcm-16", "mp3"],
|
|
16976
|
+
"h264-ts": ["pcm-16", "aac"],
|
|
16977
|
+
aac: ["aac", "pcm-16"],
|
|
16978
|
+
avi: [],
|
|
16979
|
+
gif: [],
|
|
16980
|
+
h265: ["aac", "pcm-16"],
|
|
16981
|
+
mp3: ["mp3", "pcm-16"],
|
|
16982
|
+
prores: ["aac", "pcm-16"],
|
|
16983
|
+
vp8: ["opus", "pcm-16"],
|
|
16984
|
+
vp9: ["opus", "pcm-16"],
|
|
16985
|
+
wav: ["pcm-16"]
|
|
16986
|
+
};
|
|
16987
|
+
var _satisfies = supportedAudioCodecs;
|
|
16988
|
+
if (_satisfies) {
|
|
16989
|
+
}
|
|
16990
|
+
var mapAudioCodecToFfmpegAudioCodecName = (audioCodec) => {
|
|
16991
|
+
if (audioCodec === "aac") {
|
|
16992
|
+
return "libfdk_aac";
|
|
17422
16993
|
}
|
|
17423
|
-
|
|
17424
|
-
|
|
17425
|
-
path19 = decode(path19);
|
|
17426
|
-
path19 = posixNormalize(path19, !isAbsolute);
|
|
17427
|
-
if (path19.length === 0 && !isAbsolute) {
|
|
17428
|
-
path19 = ".";
|
|
16994
|
+
if (audioCodec === "mp3") {
|
|
16995
|
+
return "libmp3lame";
|
|
17429
16996
|
}
|
|
17430
|
-
if (
|
|
17431
|
-
|
|
16997
|
+
if (audioCodec === "opus") {
|
|
16998
|
+
return "libopus";
|
|
17432
16999
|
}
|
|
17433
|
-
if (
|
|
17434
|
-
return "
|
|
17000
|
+
if (audioCodec === "pcm-16") {
|
|
17001
|
+
return "pcm_s16le";
|
|
17002
|
+
}
|
|
17003
|
+
throw new Error("unknown audio codec: " + audioCodec);
|
|
17004
|
+
};
|
|
17005
|
+
var cliFlag2 = "audio-codec";
|
|
17006
|
+
var ssrName = "audioCodec";
|
|
17007
|
+
var defaultAudioCodecs = {
|
|
17008
|
+
"h264-mkv": {
|
|
17009
|
+
lossless: "pcm-16",
|
|
17010
|
+
compressed: "pcm-16"
|
|
17011
|
+
},
|
|
17012
|
+
"h264-ts": {
|
|
17013
|
+
lossless: "pcm-16",
|
|
17014
|
+
compressed: "aac"
|
|
17015
|
+
},
|
|
17016
|
+
aac: {
|
|
17017
|
+
lossless: "pcm-16",
|
|
17018
|
+
compressed: "aac"
|
|
17019
|
+
},
|
|
17020
|
+
gif: {
|
|
17021
|
+
lossless: null,
|
|
17022
|
+
compressed: null
|
|
17023
|
+
},
|
|
17024
|
+
h264: {
|
|
17025
|
+
lossless: "pcm-16",
|
|
17026
|
+
compressed: "aac"
|
|
17027
|
+
},
|
|
17028
|
+
h265: {
|
|
17029
|
+
lossless: "pcm-16",
|
|
17030
|
+
compressed: "aac"
|
|
17031
|
+
},
|
|
17032
|
+
mp3: {
|
|
17033
|
+
lossless: "pcm-16",
|
|
17034
|
+
compressed: "mp3"
|
|
17035
|
+
},
|
|
17036
|
+
prores: {
|
|
17037
|
+
lossless: "pcm-16",
|
|
17038
|
+
compressed: "pcm-16"
|
|
17039
|
+
},
|
|
17040
|
+
vp8: {
|
|
17041
|
+
lossless: "pcm-16",
|
|
17042
|
+
compressed: "opus"
|
|
17043
|
+
},
|
|
17044
|
+
vp9: {
|
|
17045
|
+
lossless: "pcm-16",
|
|
17046
|
+
compressed: "opus"
|
|
17047
|
+
},
|
|
17048
|
+
wav: {
|
|
17049
|
+
lossless: "pcm-16",
|
|
17050
|
+
compressed: "pcm-16"
|
|
17435
17051
|
}
|
|
17436
|
-
return path19;
|
|
17437
17052
|
};
|
|
17438
|
-
|
|
17439
|
-
|
|
17440
|
-
|
|
17441
|
-
|
|
17442
|
-
|
|
17443
|
-
}
|
|
17444
|
-
const filenameArr = pathNormalize(filename).split(".");
|
|
17445
|
-
const hasExtension = filenameArr.length >= 2;
|
|
17446
|
-
const filenameArrLength = filenameArr.length;
|
|
17447
|
-
const extension = hasExtension ? filenameArr[filenameArrLength - 1] : null;
|
|
17448
|
-
return extension;
|
|
17053
|
+
var extensionMap = {
|
|
17054
|
+
aac: "aac",
|
|
17055
|
+
mp3: "mp3",
|
|
17056
|
+
opus: "opus",
|
|
17057
|
+
"pcm-16": "wav"
|
|
17449
17058
|
};
|
|
17450
|
-
|
|
17451
|
-
|
|
17452
|
-
|
|
17453
|
-
if (frameRange === null) {
|
|
17454
|
-
return [0, durationInFrames - 1];
|
|
17455
|
-
}
|
|
17456
|
-
if (typeof frameRange === "number") {
|
|
17457
|
-
if (frameRange < 0 || frameRange >= durationInFrames) {
|
|
17458
|
-
throw new Error(`Frame number is out of range, must be between 0 and ${durationInFrames - 1} but got ${frameRange}`);
|
|
17459
|
-
}
|
|
17460
|
-
return [frameRange, frameRange];
|
|
17461
|
-
}
|
|
17462
|
-
if (frameRange[1] >= durationInFrames || frameRange[0] < 0) {
|
|
17463
|
-
throw new Error(`The "durationInFrames" of the <Composition /> was evaluated to be ${durationInFrames}, but frame range ${frameRange.join("-")} is not inbetween 0-${durationInFrames - 1}`);
|
|
17059
|
+
var getExtensionFromAudioCodec = (audioCodec) => {
|
|
17060
|
+
if (extensionMap[audioCodec]) {
|
|
17061
|
+
return extensionMap[audioCodec];
|
|
17464
17062
|
}
|
|
17465
|
-
|
|
17063
|
+
throw new Error(`Unsupported audio codec: ${audioCodec}`);
|
|
17466
17064
|
};
|
|
17467
|
-
|
|
17468
|
-
|
|
17469
|
-
|
|
17470
|
-
|
|
17471
|
-
|
|
17472
|
-
|
|
17473
|
-
|
|
17474
|
-
if (
|
|
17475
|
-
|
|
17476
|
-
|
|
17477
|
-
|
|
17478
|
-
|
|
17065
|
+
var resolveAudioCodec = ({
|
|
17066
|
+
codec,
|
|
17067
|
+
setting,
|
|
17068
|
+
preferLossless,
|
|
17069
|
+
separateAudioTo
|
|
17070
|
+
}) => {
|
|
17071
|
+
let derivedFromSeparateAudioToExtension = null;
|
|
17072
|
+
if (separateAudioTo) {
|
|
17073
|
+
const extension = separateAudioTo.split(".").pop();
|
|
17074
|
+
for (const [key, value] of Object.entries(extensionMap)) {
|
|
17075
|
+
if (value === extension) {
|
|
17076
|
+
derivedFromSeparateAudioToExtension = key;
|
|
17077
|
+
if (!supportedAudioCodecs[codec].includes(derivedFromSeparateAudioToExtension) && derivedFromSeparateAudioToExtension) {
|
|
17078
|
+
throw new Error(`The codec is ${codec} but the audio codec derived from --${separateAudioOption.cliFlag} is ${derivedFromSeparateAudioToExtension}. The only supported codecs are: ${supportedAudioCodecs[codec].join(", ")}`);
|
|
17079
|
+
}
|
|
17080
|
+
}
|
|
17081
|
+
}
|
|
17479
17082
|
}
|
|
17480
|
-
if (
|
|
17481
|
-
|
|
17083
|
+
if (preferLossless) {
|
|
17084
|
+
const selected = getDefaultAudioCodec({ codec, preferLossless });
|
|
17085
|
+
if (derivedFromSeparateAudioToExtension && selected !== derivedFromSeparateAudioToExtension) {
|
|
17086
|
+
throw new Error(`The audio codec derived from --${separateAudioOption.cliFlag} is ${derivedFromSeparateAudioToExtension}, but does not match the audio codec derived from the "Prefer lossless" option (${selected}). Remove any conflicting options.`);
|
|
17087
|
+
}
|
|
17088
|
+
return selected;
|
|
17482
17089
|
}
|
|
17483
|
-
if (
|
|
17484
|
-
|
|
17090
|
+
if (setting === null) {
|
|
17091
|
+
if (derivedFromSeparateAudioToExtension) {
|
|
17092
|
+
return derivedFromSeparateAudioToExtension;
|
|
17093
|
+
}
|
|
17094
|
+
return getDefaultAudioCodec({ codec, preferLossless });
|
|
17485
17095
|
}
|
|
17486
|
-
if (
|
|
17487
|
-
throw new
|
|
17096
|
+
if (derivedFromSeparateAudioToExtension !== setting && derivedFromSeparateAudioToExtension) {
|
|
17097
|
+
throw new Error(`The audio codec derived from --${separateAudioOption.cliFlag} is ${derivedFromSeparateAudioToExtension}, but does not match the audio codec derived from your ${audioCodecOption.name} setting (${setting}). Remove any conflicting options.`);
|
|
17488
17098
|
}
|
|
17489
|
-
return
|
|
17099
|
+
return setting;
|
|
17490
17100
|
};
|
|
17491
|
-
var
|
|
17492
|
-
|
|
17493
|
-
|
|
17494
|
-
|
|
17101
|
+
var getDefaultAudioCodec = ({
|
|
17102
|
+
codec,
|
|
17103
|
+
preferLossless
|
|
17104
|
+
}) => {
|
|
17105
|
+
return defaultAudioCodecs[codec][preferLossless ? "lossless" : "compressed"];
|
|
17106
|
+
};
|
|
17107
|
+
var _audioCodec = null;
|
|
17108
|
+
var audioCodecOption = {
|
|
17109
|
+
cliFlag: cliFlag2,
|
|
17110
|
+
setConfig: (audioCodec) => {
|
|
17111
|
+
if (audioCodec === null) {
|
|
17112
|
+
_audioCodec = null;
|
|
17113
|
+
return;
|
|
17114
|
+
}
|
|
17115
|
+
if (!validAudioCodecs.includes(audioCodec)) {
|
|
17116
|
+
throw new Error(`Audio codec must be one of the following: ${validAudioCodecs.join(", ")}, but got ${audioCodec}`);
|
|
17117
|
+
}
|
|
17118
|
+
_audioCodec = audioCodec;
|
|
17119
|
+
},
|
|
17120
|
+
getValue: ({ commandLine }) => {
|
|
17121
|
+
if (commandLine[cliFlag2]) {
|
|
17122
|
+
const codec = commandLine[cliFlag2];
|
|
17123
|
+
if (!validAudioCodecs.includes(commandLine[cliFlag2])) {
|
|
17124
|
+
throw new Error(`Audio codec must be one of the following: ${validAudioCodecs.join(", ")}, but got ${codec}`);
|
|
17125
|
+
}
|
|
17126
|
+
return {
|
|
17127
|
+
source: "cli",
|
|
17128
|
+
value: commandLine[cliFlag2]
|
|
17129
|
+
};
|
|
17130
|
+
}
|
|
17131
|
+
if (_audioCodec !== null) {
|
|
17132
|
+
return {
|
|
17133
|
+
source: "config",
|
|
17134
|
+
value: _audioCodec
|
|
17135
|
+
};
|
|
17136
|
+
}
|
|
17137
|
+
return {
|
|
17138
|
+
source: "default",
|
|
17139
|
+
value: null
|
|
17140
|
+
};
|
|
17141
|
+
},
|
|
17142
|
+
description: () => `Set the format of the audio that is embedded in the video. Not all codec and audio codec combinations are supported and certain combinations require a certain file extension and container format. See the table in the docs to see possible combinations.`,
|
|
17143
|
+
docLink: "https://www.remotion.dev/docs/encoding/#audio-codec",
|
|
17144
|
+
name: "Audio Codec",
|
|
17145
|
+
ssrName,
|
|
17146
|
+
type: "aac"
|
|
17495
17147
|
};
|
|
17496
17148
|
|
|
17497
|
-
// src/
|
|
17498
|
-
var
|
|
17499
|
-
|
|
17500
|
-
if (
|
|
17501
|
-
|
|
17502
|
-
}
|
|
17503
|
-
if (typeof q === "undefined") {
|
|
17504
|
-
return;
|
|
17505
|
-
}
|
|
17506
|
-
if (!Number.isFinite(q)) {
|
|
17507
|
-
throw new RangeError(`JPEG Quality must be a finite number, but is ${q}`);
|
|
17508
|
-
}
|
|
17509
|
-
if (Number.isNaN(q)) {
|
|
17510
|
-
throw new RangeError(`JPEG Quality is NaN, but must be a real number`);
|
|
17149
|
+
// src/parse-ffmpeg-progress.ts
|
|
17150
|
+
var parseFfmpegProgress = (input, fps) => {
|
|
17151
|
+
const match = input.match(/frame=(\s+)?([0-9]+)\s/);
|
|
17152
|
+
if (match) {
|
|
17153
|
+
return Number(match[2]);
|
|
17511
17154
|
}
|
|
17512
|
-
|
|
17513
|
-
|
|
17155
|
+
const match2 = input.match(/time=(\d+):(\d+):(\d+).(\d+)\s/);
|
|
17156
|
+
if (match2) {
|
|
17157
|
+
const [, hours, minutes, seconds, hundreds] = match2;
|
|
17158
|
+
return Number(hundreds) / 100 * fps + Number(seconds) * fps + Number(minutes) * fps * 60 + Number(hours) * fps * 60 * 60;
|
|
17514
17159
|
}
|
|
17515
17160
|
};
|
|
17516
17161
|
|
|
17517
|
-
// src/
|
|
17518
|
-
var
|
|
17519
|
-
__export(exports_perf, {
|
|
17520
|
-
stopPerfMeasure: () => stopPerfMeasure,
|
|
17521
|
-
startPerfMeasure: () => startPerfMeasure,
|
|
17522
|
-
getPerf: () => getPerf
|
|
17523
|
-
});
|
|
17524
|
-
var perf = {
|
|
17525
|
-
"activate-target": [],
|
|
17526
|
-
capture: [],
|
|
17527
|
-
save: [],
|
|
17528
|
-
"extract-frame": [],
|
|
17529
|
-
piping: []
|
|
17530
|
-
};
|
|
17531
|
-
var map2 = {};
|
|
17532
|
-
var startPerfMeasure = (marker) => {
|
|
17533
|
-
const id = Math.random();
|
|
17534
|
-
map2[id] = {
|
|
17535
|
-
id,
|
|
17536
|
-
marker,
|
|
17537
|
-
start: Date.now()
|
|
17538
|
-
};
|
|
17539
|
-
return id;
|
|
17540
|
-
};
|
|
17541
|
-
var stopPerfMeasure = (id) => {
|
|
17542
|
-
const now = Date.now();
|
|
17543
|
-
const diff = now - map2[id].start;
|
|
17544
|
-
perf[map2[id].marker].push(diff);
|
|
17545
|
-
delete map2[id];
|
|
17546
|
-
};
|
|
17547
|
-
var getPerf = () => {
|
|
17548
|
-
return [
|
|
17549
|
-
"Render performance:",
|
|
17550
|
-
...Object.keys(perf).filter((p) => perf[p].length).map((p) => {
|
|
17551
|
-
return ` ${p} => ${Math.round(perf[p].reduce((a, b) => a + b, 0) / perf[p].length)}ms (n = ${perf[p].length})`;
|
|
17552
|
-
})
|
|
17553
|
-
];
|
|
17554
|
-
};
|
|
17162
|
+
// src/sample-rate.ts
|
|
17163
|
+
var DEFAULT_SAMPLE_RATE = 48000;
|
|
17555
17164
|
|
|
17556
|
-
// src/
|
|
17557
|
-
var
|
|
17558
|
-
|
|
17559
|
-
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
|
|
17570
|
-
|
|
17165
|
+
// src/combine-audio.ts
|
|
17166
|
+
var durationOf1Frame = 1024 / DEFAULT_SAMPLE_RATE * 1e6;
|
|
17167
|
+
var getClosestAlignedTime = (targetTime) => {
|
|
17168
|
+
const decimalFramesToTargetTime = targetTime * 1e6 / durationOf1Frame;
|
|
17169
|
+
const nearestFrameIndexForTargetTime = Math.round(decimalFramesToTargetTime);
|
|
17170
|
+
return nearestFrameIndexForTargetTime * durationOf1Frame / 1e6;
|
|
17171
|
+
};
|
|
17172
|
+
var encodeAudio = async ({
|
|
17173
|
+
files,
|
|
17174
|
+
resolvedAudioCodec,
|
|
17175
|
+
audioBitrate,
|
|
17176
|
+
filelistDir,
|
|
17177
|
+
output,
|
|
17178
|
+
indent,
|
|
17179
|
+
logLevel,
|
|
17180
|
+
addRemotionMetadata,
|
|
17181
|
+
fps,
|
|
17182
|
+
binariesDirectory,
|
|
17183
|
+
cancelSignal,
|
|
17184
|
+
onProgress
|
|
17185
|
+
}) => {
|
|
17186
|
+
const fileList = files.map((p) => `file '${p}'`).join(`
|
|
17187
|
+
`);
|
|
17188
|
+
const fileListTxt = join3(filelistDir, "audio-files.txt");
|
|
17189
|
+
writeFileSync(fileListTxt, fileList);
|
|
17190
|
+
const startCombining = Date.now();
|
|
17191
|
+
const command = [
|
|
17192
|
+
"-hide_banner",
|
|
17193
|
+
"-f",
|
|
17194
|
+
"concat",
|
|
17195
|
+
"-safe",
|
|
17196
|
+
"0",
|
|
17197
|
+
"-i",
|
|
17198
|
+
fileListTxt,
|
|
17199
|
+
"-c:a",
|
|
17200
|
+
mapAudioCodecToFfmpegAudioCodecName(resolvedAudioCodec),
|
|
17201
|
+
resolvedAudioCodec === "aac" ? "-cutoff" : null,
|
|
17202
|
+
resolvedAudioCodec === "aac" ? "18000" : null,
|
|
17203
|
+
"-b:a",
|
|
17204
|
+
audioBitrate ? audioBitrate : "320k",
|
|
17205
|
+
"-vn",
|
|
17206
|
+
addRemotionMetadata ? `-metadata` : null,
|
|
17207
|
+
addRemotionMetadata ? `comment=Made with Remotion ${VERSION3}` : null,
|
|
17208
|
+
"-y",
|
|
17209
|
+
output
|
|
17210
|
+
];
|
|
17211
|
+
Log.verbose({ indent, logLevel }, `Combining audio with re-encoding, command: ${command.join(" ")}`);
|
|
17212
|
+
try {
|
|
17213
|
+
const task = callFf({
|
|
17214
|
+
args: command,
|
|
17215
|
+
bin: "ffmpeg",
|
|
17216
|
+
indent,
|
|
17217
|
+
logLevel,
|
|
17218
|
+
binariesDirectory,
|
|
17219
|
+
cancelSignal
|
|
17220
|
+
});
|
|
17221
|
+
task.stderr?.on("data", (data) => {
|
|
17222
|
+
const utf8 = data.toString("utf8");
|
|
17223
|
+
const parsed = parseFfmpegProgress(utf8, fps);
|
|
17224
|
+
if (parsed === undefined) {
|
|
17225
|
+
Log.verbose({ indent, logLevel }, utf8);
|
|
17226
|
+
} else {
|
|
17227
|
+
onProgress(parsed);
|
|
17228
|
+
Log.verbose({ indent, logLevel }, `Encoded ${parsed} audio frames`);
|
|
17229
|
+
}
|
|
17230
|
+
});
|
|
17231
|
+
await task;
|
|
17232
|
+
Log.verbose({ indent, logLevel }, `Encoded audio in ${Date.now() - startCombining}ms`);
|
|
17233
|
+
return output;
|
|
17234
|
+
} catch (e) {
|
|
17235
|
+
rmSync2(fileListTxt, { recursive: true });
|
|
17236
|
+
throw e;
|
|
17571
17237
|
}
|
|
17572
|
-
return validPixelFormats.filter((format) => format !== "yuva420p");
|
|
17573
17238
|
};
|
|
17574
|
-
var
|
|
17575
|
-
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
17579
|
-
|
|
17580
|
-
|
|
17581
|
-
|
|
17582
|
-
|
|
17583
|
-
|
|
17584
|
-
|
|
17585
|
-
|
|
17586
|
-
|
|
17239
|
+
var combineAudioSeamlessly = async ({
|
|
17240
|
+
files,
|
|
17241
|
+
filelistDir,
|
|
17242
|
+
indent,
|
|
17243
|
+
logLevel,
|
|
17244
|
+
output,
|
|
17245
|
+
chunkDurationInSeconds,
|
|
17246
|
+
addRemotionMetadata,
|
|
17247
|
+
fps,
|
|
17248
|
+
binariesDirectory,
|
|
17249
|
+
cancelSignal,
|
|
17250
|
+
onProgress
|
|
17251
|
+
}) => {
|
|
17252
|
+
const startConcatenating = Date.now();
|
|
17253
|
+
const fileList = files.map((p, i) => {
|
|
17254
|
+
const isLast = i === files.length - 1;
|
|
17255
|
+
const targetStart = i * chunkDurationInSeconds;
|
|
17256
|
+
const endStart = (i + 1) * chunkDurationInSeconds;
|
|
17257
|
+
const startTime = getClosestAlignedTime(targetStart) * 1e6;
|
|
17258
|
+
const endTime = getClosestAlignedTime(endStart) * 1e6;
|
|
17259
|
+
const realDuration = endTime - startTime;
|
|
17260
|
+
let inpoint = 0;
|
|
17261
|
+
if (i > 0) {
|
|
17262
|
+
inpoint = durationOf1Frame * 4;
|
|
17263
|
+
}
|
|
17264
|
+
const outpoint = (i === 0 ? durationOf1Frame * 2 : inpoint) + realDuration - (isLast ? 0 : durationOf1Frame);
|
|
17265
|
+
return [`file '${p}'`, `inpoint ${inpoint}us`, `outpoint ${outpoint}us`].filter(truthy).join(`
|
|
17266
|
+
`);
|
|
17267
|
+
}).join(`
|
|
17268
|
+
`);
|
|
17269
|
+
const fileListTxt = join3(filelistDir, "audio-files.txt");
|
|
17270
|
+
writeFileSync(fileListTxt, fileList);
|
|
17271
|
+
const command = [
|
|
17272
|
+
"-hide_banner",
|
|
17273
|
+
"-f",
|
|
17274
|
+
"concat",
|
|
17275
|
+
"-safe",
|
|
17276
|
+
"0",
|
|
17277
|
+
"-i",
|
|
17278
|
+
fileListTxt,
|
|
17279
|
+
"-c:a",
|
|
17280
|
+
"copy",
|
|
17281
|
+
"-vn",
|
|
17282
|
+
addRemotionMetadata ? `-metadata` : null,
|
|
17283
|
+
addRemotionMetadata ? `comment=Made with Remotion ${VERSION3}` : null,
|
|
17284
|
+
"-y",
|
|
17285
|
+
output
|
|
17286
|
+
];
|
|
17287
|
+
Log.verbose({ indent, logLevel }, `Combining AAC audio seamlessly, command: ${command.join(" ")}`);
|
|
17288
|
+
try {
|
|
17289
|
+
const task = callFf({
|
|
17290
|
+
args: command,
|
|
17291
|
+
bin: "ffmpeg",
|
|
17292
|
+
indent,
|
|
17293
|
+
logLevel,
|
|
17294
|
+
binariesDirectory,
|
|
17295
|
+
cancelSignal
|
|
17296
|
+
});
|
|
17297
|
+
task.stderr?.on("data", (data) => {
|
|
17298
|
+
const utf8 = data.toString("utf8");
|
|
17299
|
+
const parsed = parseFfmpegProgress(utf8, fps);
|
|
17300
|
+
if (parsed !== undefined) {
|
|
17301
|
+
onProgress(parsed);
|
|
17302
|
+
Log.verbose({ indent, logLevel }, `Encoded ${parsed} audio frames`);
|
|
17303
|
+
}
|
|
17304
|
+
});
|
|
17305
|
+
await task;
|
|
17306
|
+
Log.verbose({ indent, logLevel }, `Combined audio seamlessly in ${Date.now() - startConcatenating}ms`);
|
|
17307
|
+
return output;
|
|
17308
|
+
} catch (e) {
|
|
17309
|
+
rmSync2(fileListTxt, { recursive: true });
|
|
17310
|
+
Log.error({ indent, logLevel }, e);
|
|
17311
|
+
throw e;
|
|
17587
17312
|
}
|
|
17588
17313
|
};
|
|
17589
|
-
|
|
17590
|
-
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
|
|
17594
|
-
|
|
17595
|
-
// src/cycle-browser-tabs.ts
|
|
17596
|
-
var cycleBrowserTabs = ({
|
|
17597
|
-
puppeteerInstance,
|
|
17598
|
-
concurrency,
|
|
17314
|
+
var createCombinedAudio = ({
|
|
17315
|
+
seamless,
|
|
17316
|
+
filelistDir,
|
|
17317
|
+
files,
|
|
17318
|
+
indent,
|
|
17599
17319
|
logLevel,
|
|
17600
|
-
|
|
17320
|
+
audioBitrate,
|
|
17321
|
+
resolvedAudioCodec,
|
|
17322
|
+
output,
|
|
17323
|
+
chunkDurationInSeconds,
|
|
17324
|
+
addRemotionMetadata,
|
|
17325
|
+
binariesDirectory,
|
|
17326
|
+
fps,
|
|
17327
|
+
cancelSignal,
|
|
17328
|
+
onProgress
|
|
17601
17329
|
}) => {
|
|
17602
|
-
if (
|
|
17603
|
-
return {
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17330
|
+
if (seamless) {
|
|
17331
|
+
return combineAudioSeamlessly({
|
|
17332
|
+
filelistDir,
|
|
17333
|
+
files,
|
|
17334
|
+
indent,
|
|
17335
|
+
logLevel,
|
|
17336
|
+
output,
|
|
17337
|
+
chunkDurationInSeconds,
|
|
17338
|
+
addRemotionMetadata,
|
|
17339
|
+
binariesDirectory,
|
|
17340
|
+
fps,
|
|
17341
|
+
cancelSignal,
|
|
17342
|
+
onProgress
|
|
17343
|
+
});
|
|
17608
17344
|
}
|
|
17609
|
-
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
17616
|
-
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
}).catch((err) => Log.error({ indent, logLevel }, err)).finally(() => {
|
|
17624
|
-
if (!stopped) {
|
|
17625
|
-
set();
|
|
17626
|
-
}
|
|
17627
|
-
});
|
|
17628
|
-
}, 200);
|
|
17629
|
-
};
|
|
17630
|
-
set();
|
|
17631
|
-
return {
|
|
17632
|
-
stopCycling: () => {
|
|
17633
|
-
if (!interval) {
|
|
17634
|
-
return;
|
|
17635
|
-
}
|
|
17636
|
-
stopped = true;
|
|
17637
|
-
return clearTimeout(interval);
|
|
17638
|
-
}
|
|
17639
|
-
};
|
|
17345
|
+
return encodeAudio({
|
|
17346
|
+
filelistDir,
|
|
17347
|
+
files,
|
|
17348
|
+
resolvedAudioCodec,
|
|
17349
|
+
audioBitrate,
|
|
17350
|
+
output,
|
|
17351
|
+
indent,
|
|
17352
|
+
logLevel,
|
|
17353
|
+
addRemotionMetadata,
|
|
17354
|
+
binariesDirectory,
|
|
17355
|
+
fps,
|
|
17356
|
+
cancelSignal,
|
|
17357
|
+
onProgress
|
|
17358
|
+
});
|
|
17640
17359
|
};
|
|
17641
17360
|
|
|
17642
17361
|
// src/get-extra-frames-to-capture.ts
|
|
@@ -19604,14 +19323,20 @@ var validateEvenDimensionsWithCodec = ({
|
|
|
19604
19323
|
indent,
|
|
19605
19324
|
logLevel
|
|
19606
19325
|
}) => {
|
|
19326
|
+
let actualWidth = width * scale;
|
|
19327
|
+
let actualHeight = height * scale;
|
|
19607
19328
|
if (wantsImageSequence) {
|
|
19608
|
-
return
|
|
19329
|
+
return {
|
|
19330
|
+
actualWidth,
|
|
19331
|
+
actualHeight
|
|
19332
|
+
};
|
|
19609
19333
|
}
|
|
19610
19334
|
if (codec !== "h264-mkv" && codec !== "h264" && codec !== "h265" && codec !== "h264-ts") {
|
|
19611
|
-
return
|
|
19335
|
+
return {
|
|
19336
|
+
actualWidth,
|
|
19337
|
+
actualHeight
|
|
19338
|
+
};
|
|
19612
19339
|
}
|
|
19613
|
-
let actualWidth = width * scale;
|
|
19614
|
-
let actualHeight = height * scale;
|
|
19615
19340
|
if (actualWidth % 1 !== 0 && (actualWidth % 1 < 0.005 || actualWidth % 1 > 0.005)) {
|
|
19616
19341
|
Log.verbose({ indent, logLevel }, `Rounding width to an even number from ${actualWidth} to ${Math.round(actualWidth)}`);
|
|
19617
19342
|
actualWidth = Math.round(actualWidth);
|
|
@@ -19637,6 +19362,10 @@ var validateEvenDimensionsWithCodec = ({
|
|
|
19637
19362
|
].join(" ");
|
|
19638
19363
|
throw new Error(message);
|
|
19639
19364
|
}
|
|
19365
|
+
return {
|
|
19366
|
+
actualWidth,
|
|
19367
|
+
actualHeight
|
|
19368
|
+
};
|
|
19640
19369
|
};
|
|
19641
19370
|
|
|
19642
19371
|
// src/prespawn-ffmpeg.ts
|
|
@@ -19783,9 +19512,20 @@ var validateSelectedCodecAndProResCombination = ({
|
|
|
19783
19512
|
};
|
|
19784
19513
|
|
|
19785
19514
|
// src/stitch-frames-to-video.ts
|
|
19786
|
-
import { cpSync as cpSync2, promises as promises3, rmSync as
|
|
19515
|
+
import { cpSync as cpSync2, promises as promises3, rmSync as rmSync3 } from "node:fs";
|
|
19787
19516
|
import path24 from "node:path";
|
|
19788
19517
|
|
|
19518
|
+
// src/convert-number-of-gif-loops-to-ffmpeg.ts
|
|
19519
|
+
var convertNumberOfGifLoopsToFfmpegSyntax = (loops) => {
|
|
19520
|
+
if (loops === null) {
|
|
19521
|
+
return "0";
|
|
19522
|
+
}
|
|
19523
|
+
if (loops === 0) {
|
|
19524
|
+
return "-1";
|
|
19525
|
+
}
|
|
19526
|
+
return String(loops);
|
|
19527
|
+
};
|
|
19528
|
+
|
|
19789
19529
|
// src/create-audio.ts
|
|
19790
19530
|
import path23 from "path";
|
|
19791
19531
|
|
|
@@ -19880,7 +19620,6 @@ var calculateAssetPositions = (frames) => {
|
|
|
19880
19620
|
trimLeft: asset.mediaFrame,
|
|
19881
19621
|
volume: [],
|
|
19882
19622
|
playbackRate: asset.playbackRate,
|
|
19883
|
-
allowAmplificationDuringRender: asset.allowAmplificationDuringRender,
|
|
19884
19623
|
toneFrequency: asset.toneFrequency,
|
|
19885
19624
|
audioStartFrame: asset.audioStartFrame
|
|
19886
19625
|
});
|
|
@@ -20282,28 +20021,25 @@ var ffmpegBuildVolumeExpression = ({
|
|
|
20282
20021
|
var ffmpegVolumeExpression = ({
|
|
20283
20022
|
volume,
|
|
20284
20023
|
fps,
|
|
20285
|
-
trimLeft
|
|
20286
|
-
allowAmplificationDuringRender
|
|
20024
|
+
trimLeft
|
|
20287
20025
|
}) => {
|
|
20288
|
-
const maxVolume = allowAmplificationDuringRender ? Infinity : 1;
|
|
20289
20026
|
if (typeof volume === "number") {
|
|
20290
20027
|
return {
|
|
20291
20028
|
eval: "once",
|
|
20292
|
-
value: String(
|
|
20029
|
+
value: String(volume)
|
|
20293
20030
|
};
|
|
20294
20031
|
}
|
|
20295
20032
|
if ([...new Set(volume)].length === 1) {
|
|
20296
20033
|
return ffmpegVolumeExpression({
|
|
20297
20034
|
volume: volume[0],
|
|
20298
20035
|
fps,
|
|
20299
|
-
trimLeft
|
|
20300
|
-
allowAmplificationDuringRender
|
|
20036
|
+
trimLeft
|
|
20301
20037
|
});
|
|
20302
20038
|
}
|
|
20303
20039
|
const paddedVolume = [...volume, volume[volume.length - 1]];
|
|
20304
20040
|
const volumeMap = {};
|
|
20305
20041
|
paddedVolume.forEach((baseVolume, frame) => {
|
|
20306
|
-
const actualVolume = roundVolumeToAvoidStackOverflow(
|
|
20042
|
+
const actualVolume = roundVolumeToAvoidStackOverflow(baseVolume);
|
|
20307
20043
|
if (!volumeMap[actualVolume]) {
|
|
20308
20044
|
volumeMap[actualVolume] = [];
|
|
20309
20045
|
}
|
|
@@ -20445,8 +20181,7 @@ var stringifyFfmpegFilter = ({
|
|
|
20445
20181
|
const volumeFilter = ffmpegVolumeExpression({
|
|
20446
20182
|
volume,
|
|
20447
20183
|
fps,
|
|
20448
|
-
trimLeft: actualTrimLeft
|
|
20449
|
-
allowAmplificationDuringRender: asset.allowAmplificationDuringRender
|
|
20184
|
+
trimLeft: actualTrimLeft
|
|
20450
20185
|
});
|
|
20451
20186
|
const padAtEnd = chunkLengthInSeconds - audibleDuration - startInVideoSeconds;
|
|
20452
20187
|
const padStart = startInVideoSeconds + presentationTimeOffsetInSeconds;
|
|
@@ -20649,6 +20384,25 @@ var createAudio = async ({
|
|
|
20649
20384
|
return outName;
|
|
20650
20385
|
};
|
|
20651
20386
|
|
|
20387
|
+
// src/make-metadata-args.ts
|
|
20388
|
+
import { VERSION as VERSION4 } from "remotion/version";
|
|
20389
|
+
var makeMetadataArgs = (metadata) => {
|
|
20390
|
+
const defaultComment = `Made with Remotion ${VERSION4}`;
|
|
20391
|
+
const newMetadata = {
|
|
20392
|
+
comment: defaultComment
|
|
20393
|
+
};
|
|
20394
|
+
Object.keys(metadata).forEach((key) => {
|
|
20395
|
+
const lowercaseKey = key.toLowerCase();
|
|
20396
|
+
if (lowercaseKey === "comment") {
|
|
20397
|
+
newMetadata[lowercaseKey] = `${defaultComment}; ${metadata[key]}`;
|
|
20398
|
+
} else {
|
|
20399
|
+
newMetadata[lowercaseKey] = metadata[key];
|
|
20400
|
+
}
|
|
20401
|
+
});
|
|
20402
|
+
const metadataArgs = Object.entries(newMetadata).map(([key, value]) => ["-metadata", `${key}=${value}`]);
|
|
20403
|
+
return metadataArgs.flat(1);
|
|
20404
|
+
};
|
|
20405
|
+
|
|
20652
20406
|
// src/render-has-audio.ts
|
|
20653
20407
|
var getShouldRenderAudio = ({
|
|
20654
20408
|
codec,
|
|
@@ -20929,7 +20683,7 @@ var innerStitchFramesToVideo = async ({
|
|
|
20929
20683
|
}
|
|
20930
20684
|
const finalDestination = path24.resolve(remotionRoot, separateAudioTo);
|
|
20931
20685
|
cpSync2(audio, finalDestination);
|
|
20932
|
-
|
|
20686
|
+
rmSync3(audio);
|
|
20933
20687
|
}
|
|
20934
20688
|
return new Promise((resolve2, reject) => {
|
|
20935
20689
|
task.once("close", (code, signal) => {
|
|
@@ -21315,7 +21069,7 @@ var internalRenderMediaRaw = ({
|
|
|
21315
21069
|
if (onCtrlCExit && workingDir) {
|
|
21316
21070
|
onCtrlCExit(`Delete ${workingDir}`, () => deleteDirectory(workingDir));
|
|
21317
21071
|
}
|
|
21318
|
-
validateEvenDimensionsWithCodec({
|
|
21072
|
+
const { actualWidth, actualHeight } = validateEvenDimensionsWithCodec({
|
|
21319
21073
|
codec,
|
|
21320
21074
|
height: composition.height,
|
|
21321
21075
|
scale,
|
|
@@ -21351,8 +21105,8 @@ var internalRenderMediaRaw = ({
|
|
|
21351
21105
|
const createPrestitcherIfNecessary = () => {
|
|
21352
21106
|
if (preEncodedFileLocation) {
|
|
21353
21107
|
preStitcher = prespawnFfmpeg({
|
|
21354
|
-
width:
|
|
21355
|
-
height:
|
|
21108
|
+
width: actualWidth,
|
|
21109
|
+
height: actualHeight,
|
|
21356
21110
|
fps,
|
|
21357
21111
|
outputLocation: preEncodedFileLocation,
|
|
21358
21112
|
pixelFormat,
|
|
@@ -21511,8 +21265,8 @@ var internalRenderMediaRaw = ({
|
|
|
21511
21265
|
}
|
|
21512
21266
|
const stitchStart = Date.now();
|
|
21513
21267
|
return internalStitchFramesToVideo({
|
|
21514
|
-
width:
|
|
21515
|
-
height:
|
|
21268
|
+
width: actualWidth,
|
|
21269
|
+
height: actualHeight,
|
|
21516
21270
|
fps,
|
|
21517
21271
|
outputLocation: absoluteOutputLocation,
|
|
21518
21272
|
preEncodedFileLocation,
|
|
@@ -21668,7 +21422,8 @@ var renderMedia = ({
|
|
|
21668
21422
|
metadata,
|
|
21669
21423
|
hardwareAcceleration,
|
|
21670
21424
|
chromeMode,
|
|
21671
|
-
offthreadVideoThreads
|
|
21425
|
+
offthreadVideoThreads,
|
|
21426
|
+
compositionStart
|
|
21672
21427
|
}) => {
|
|
21673
21428
|
const indent = false;
|
|
21674
21429
|
const logLevel = verbose || dumpBrowserLogs ? "verbose" : passedLogLevel ?? "info";
|
|
@@ -21749,7 +21504,7 @@ var renderMedia = ({
|
|
|
21749
21504
|
}),
|
|
21750
21505
|
onArtifact: onArtifact ?? null,
|
|
21751
21506
|
metadata: metadata ?? null,
|
|
21752
|
-
compositionStart: 0,
|
|
21507
|
+
compositionStart: compositionStart ?? 0,
|
|
21753
21508
|
hardwareAcceleration: hardwareAcceleration ?? "disable",
|
|
21754
21509
|
chromeMode: chromeMode ?? "headless-shell"
|
|
21755
21510
|
});
|
|
@@ -22388,6 +22143,312 @@ var getMaxConcurrency = () => {
|
|
|
22388
22143
|
return getCpuCount();
|
|
22389
22144
|
};
|
|
22390
22145
|
var getMinConcurrency = () => 1;
|
|
22146
|
+
|
|
22147
|
+
// src/combine-chunks.ts
|
|
22148
|
+
import { rmSync as rmSync5 } from "node:fs";
|
|
22149
|
+
import { join as join5 } from "node:path";
|
|
22150
|
+
|
|
22151
|
+
// src/can-concat-seamlessly.ts
|
|
22152
|
+
var canConcatAudioSeamlessly = (audioCodec, chunkDurationInFrames) => {
|
|
22153
|
+
if (chunkDurationInFrames <= 4) {
|
|
22154
|
+
return false;
|
|
22155
|
+
}
|
|
22156
|
+
return audioCodec === "aac";
|
|
22157
|
+
};
|
|
22158
|
+
var canConcatVideoSeamlessly = (codec) => {
|
|
22159
|
+
return codec === "h264";
|
|
22160
|
+
};
|
|
22161
|
+
|
|
22162
|
+
// src/combine-video-streams.ts
|
|
22163
|
+
import { rmSync as rmSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
22164
|
+
import { join as join4 } from "path";
|
|
22165
|
+
import { VERSION as VERSION5 } from "remotion/version";
|
|
22166
|
+
var combineVideoStreams = async ({
|
|
22167
|
+
fps,
|
|
22168
|
+
codec,
|
|
22169
|
+
filelistDir,
|
|
22170
|
+
numberOfGifLoops,
|
|
22171
|
+
output,
|
|
22172
|
+
indent,
|
|
22173
|
+
logLevel,
|
|
22174
|
+
onProgress,
|
|
22175
|
+
files,
|
|
22176
|
+
addRemotionMetadata,
|
|
22177
|
+
binariesDirectory,
|
|
22178
|
+
cancelSignal
|
|
22179
|
+
}) => {
|
|
22180
|
+
const fileList = files.map((p) => `file '${p}'`).join(`
|
|
22181
|
+
`);
|
|
22182
|
+
const fileListTxt = join4(filelistDir, "video-files.txt");
|
|
22183
|
+
writeFileSync2(fileListTxt, fileList);
|
|
22184
|
+
const encoder = codec === "gif" ? "gif" : "copy";
|
|
22185
|
+
const command = [
|
|
22186
|
+
"-hide_banner",
|
|
22187
|
+
"-r",
|
|
22188
|
+
String(fps),
|
|
22189
|
+
"-f",
|
|
22190
|
+
"concat",
|
|
22191
|
+
"-safe",
|
|
22192
|
+
"0",
|
|
22193
|
+
"-i",
|
|
22194
|
+
fileListTxt,
|
|
22195
|
+
numberOfGifLoops === null ? null : "-loop",
|
|
22196
|
+
numberOfGifLoops === null ? null : convertNumberOfGifLoopsToFfmpegSyntax(numberOfGifLoops),
|
|
22197
|
+
codec === "gif" ? "-filter_complex" : null,
|
|
22198
|
+
codec === "gif" ? "split[v],palettegen,[v]paletteuse" : null,
|
|
22199
|
+
"-an",
|
|
22200
|
+
"-c:v",
|
|
22201
|
+
encoder,
|
|
22202
|
+
codec === "h265" ? "-tag:v" : null,
|
|
22203
|
+
codec === "h265" ? "hvc1" : null,
|
|
22204
|
+
addRemotionMetadata ? `-metadata` : null,
|
|
22205
|
+
addRemotionMetadata ? `comment=Made with Remotion ${VERSION5}` : null,
|
|
22206
|
+
"-y",
|
|
22207
|
+
output
|
|
22208
|
+
].filter(truthy);
|
|
22209
|
+
const doesReencode = encoder !== "copy";
|
|
22210
|
+
const startTime = Date.now();
|
|
22211
|
+
Log.verbose({ indent, logLevel }, `Combining video ${doesReencode ? "with reencoding" : "without reencoding"}, command: ${command.join(" ")}`);
|
|
22212
|
+
try {
|
|
22213
|
+
const task = callFf({
|
|
22214
|
+
args: command,
|
|
22215
|
+
bin: "ffmpeg",
|
|
22216
|
+
indent,
|
|
22217
|
+
logLevel,
|
|
22218
|
+
binariesDirectory,
|
|
22219
|
+
cancelSignal
|
|
22220
|
+
});
|
|
22221
|
+
task.stderr?.on("data", (data) => {
|
|
22222
|
+
const parsed = parseFfmpegProgress(data.toString("utf8"), fps);
|
|
22223
|
+
if (parsed === undefined) {
|
|
22224
|
+
Log.verbose({ indent, logLevel }, data.toString("utf8"));
|
|
22225
|
+
} else {
|
|
22226
|
+
Log.verbose({ indent, logLevel }, `Encoded ${parsed} video frames`);
|
|
22227
|
+
onProgress(parsed);
|
|
22228
|
+
}
|
|
22229
|
+
});
|
|
22230
|
+
await task;
|
|
22231
|
+
Log.verbose({ indent, logLevel }, `Finished combining video in ${Date.now() - startTime}ms`);
|
|
22232
|
+
return output;
|
|
22233
|
+
} catch (e) {
|
|
22234
|
+
rmSync4(fileListTxt, { recursive: true });
|
|
22235
|
+
throw e;
|
|
22236
|
+
}
|
|
22237
|
+
};
|
|
22238
|
+
|
|
22239
|
+
// src/combine-video-streams-seamlessly.ts
|
|
22240
|
+
var combineVideoStreamsSeamlessly = ({ files }) => {
|
|
22241
|
+
const fileList = `concat:${files.join("|")}`;
|
|
22242
|
+
return fileList;
|
|
22243
|
+
};
|
|
22244
|
+
|
|
22245
|
+
// src/mux-video-and-audio.ts
|
|
22246
|
+
var muxVideoAndAudio = async ({
|
|
22247
|
+
videoOutput,
|
|
22248
|
+
audioOutput,
|
|
22249
|
+
output,
|
|
22250
|
+
indent,
|
|
22251
|
+
logLevel,
|
|
22252
|
+
onProgress,
|
|
22253
|
+
binariesDirectory,
|
|
22254
|
+
fps,
|
|
22255
|
+
cancelSignal,
|
|
22256
|
+
addFaststart,
|
|
22257
|
+
metadata
|
|
22258
|
+
}) => {
|
|
22259
|
+
const startTime = Date.now();
|
|
22260
|
+
Log.verbose({ indent, logLevel }, "Muxing video and audio together");
|
|
22261
|
+
const command = [
|
|
22262
|
+
"-hide_banner",
|
|
22263
|
+
videoOutput ? "-i" : null,
|
|
22264
|
+
videoOutput,
|
|
22265
|
+
audioOutput ? "-i" : null,
|
|
22266
|
+
audioOutput,
|
|
22267
|
+
videoOutput ? "-c:v" : null,
|
|
22268
|
+
videoOutput ? "copy" : null,
|
|
22269
|
+
audioOutput ? "-c:a" : null,
|
|
22270
|
+
audioOutput ? "copy" : null,
|
|
22271
|
+
addFaststart ? "-movflags" : null,
|
|
22272
|
+
addFaststart ? "faststart" : null,
|
|
22273
|
+
...makeMetadataArgs(metadata ?? {}),
|
|
22274
|
+
"-y",
|
|
22275
|
+
output
|
|
22276
|
+
].filter(truthy);
|
|
22277
|
+
Log.verbose({ indent, logLevel }, "Combining command: ", command);
|
|
22278
|
+
const task = callFf({
|
|
22279
|
+
bin: "ffmpeg",
|
|
22280
|
+
args: command,
|
|
22281
|
+
indent,
|
|
22282
|
+
logLevel,
|
|
22283
|
+
binariesDirectory,
|
|
22284
|
+
cancelSignal
|
|
22285
|
+
});
|
|
22286
|
+
task.stderr?.on("data", (data) => {
|
|
22287
|
+
const utf8 = data.toString("utf8");
|
|
22288
|
+
const parsed = parseFfmpegProgress(utf8, fps);
|
|
22289
|
+
if (parsed === undefined) {
|
|
22290
|
+
if (!utf8.includes("Estimating duration from bitrate, this may be inaccurate")) {
|
|
22291
|
+
Log.verbose({ indent, logLevel }, utf8);
|
|
22292
|
+
}
|
|
22293
|
+
} else {
|
|
22294
|
+
Log.verbose({ indent, logLevel }, `Combined ${parsed} frames`);
|
|
22295
|
+
onProgress(parsed);
|
|
22296
|
+
}
|
|
22297
|
+
});
|
|
22298
|
+
await task;
|
|
22299
|
+
Log.verbose({ indent, logLevel }, `Muxing done in ${Date.now() - startTime}ms`);
|
|
22300
|
+
};
|
|
22301
|
+
|
|
22302
|
+
// src/combine-chunks.ts
|
|
22303
|
+
var codecSupportsFastStart = {
|
|
22304
|
+
"h264-mkv": false,
|
|
22305
|
+
"h264-ts": false,
|
|
22306
|
+
h264: true,
|
|
22307
|
+
h265: true,
|
|
22308
|
+
aac: false,
|
|
22309
|
+
gif: false,
|
|
22310
|
+
mp3: false,
|
|
22311
|
+
prores: false,
|
|
22312
|
+
vp8: false,
|
|
22313
|
+
vp9: false,
|
|
22314
|
+
wav: false
|
|
22315
|
+
};
|
|
22316
|
+
var REMOTION_FILELIST_TOKEN = "remotion-filelist";
|
|
22317
|
+
var internalCombineChunks = async ({
|
|
22318
|
+
outputLocation: output,
|
|
22319
|
+
onProgress,
|
|
22320
|
+
codec,
|
|
22321
|
+
fps,
|
|
22322
|
+
numberOfGifLoops,
|
|
22323
|
+
audioBitrate,
|
|
22324
|
+
indent,
|
|
22325
|
+
logLevel,
|
|
22326
|
+
binariesDirectory,
|
|
22327
|
+
cancelSignal,
|
|
22328
|
+
metadata,
|
|
22329
|
+
audioFiles,
|
|
22330
|
+
videoFiles,
|
|
22331
|
+
framesPerChunk,
|
|
22332
|
+
audioCodec,
|
|
22333
|
+
preferLossless,
|
|
22334
|
+
everyNthFrame,
|
|
22335
|
+
frameRange,
|
|
22336
|
+
compositionDurationInFrames
|
|
22337
|
+
}) => {
|
|
22338
|
+
const filelistDir = tmpDir(REMOTION_FILELIST_TOKEN);
|
|
22339
|
+
const shouldCreateVideo = !isAudioCodec(codec);
|
|
22340
|
+
const resolvedAudioCodec = resolveAudioCodec({
|
|
22341
|
+
setting: audioCodec,
|
|
22342
|
+
codec,
|
|
22343
|
+
preferLossless,
|
|
22344
|
+
separateAudioTo: null
|
|
22345
|
+
});
|
|
22346
|
+
const shouldCreateAudio = resolvedAudioCodec !== null && audioFiles.length > 0;
|
|
22347
|
+
const seamlessVideo = canConcatVideoSeamlessly(codec);
|
|
22348
|
+
const seamlessAudio = canConcatAudioSeamlessly(resolvedAudioCodec, framesPerChunk);
|
|
22349
|
+
const realFrameRange = getRealFrameRange(compositionDurationInFrames, frameRange);
|
|
22350
|
+
const numberOfFrames = getFramesToRender(realFrameRange, everyNthFrame).length;
|
|
22351
|
+
const videoOutput = shouldCreateVideo ? join5(filelistDir, `video.${getFileExtensionFromCodec(codec, resolvedAudioCodec)}`) : null;
|
|
22352
|
+
const audioOutput = shouldCreateAudio ? join5(filelistDir, `audio.${getExtensionFromAudioCodec(resolvedAudioCodec)}`) : null;
|
|
22353
|
+
const chunkDurationInSeconds = framesPerChunk / fps;
|
|
22354
|
+
let concatenatedAudio = 0;
|
|
22355
|
+
let concatenatedVideo = 0;
|
|
22356
|
+
let muxing = 0;
|
|
22357
|
+
const updateProgress = () => {
|
|
22358
|
+
const totalFrames = (shouldCreateAudio ? numberOfFrames : 0) + (shouldCreateVideo ? numberOfFrames : 0) + numberOfFrames;
|
|
22359
|
+
const actualProgress = concatenatedAudio + concatenatedVideo + muxing;
|
|
22360
|
+
onProgress({
|
|
22361
|
+
frames: actualProgress / totalFrames * numberOfFrames,
|
|
22362
|
+
totalProgress: actualProgress / totalFrames
|
|
22363
|
+
});
|
|
22364
|
+
};
|
|
22365
|
+
Log.verbose({ indent, logLevel }, `Combining chunks, audio = ${shouldCreateAudio === false ? "no" : seamlessAudio ? "seamlessly" : "normally"}, video = ${shouldCreateVideo === false ? "no" : seamlessVideo ? "seamlessly" : "normally"}`);
|
|
22366
|
+
await Promise.all([
|
|
22367
|
+
shouldCreateAudio && audioOutput ? createCombinedAudio({
|
|
22368
|
+
audioBitrate,
|
|
22369
|
+
filelistDir,
|
|
22370
|
+
files: audioFiles,
|
|
22371
|
+
indent,
|
|
22372
|
+
logLevel,
|
|
22373
|
+
output: audioOutput,
|
|
22374
|
+
resolvedAudioCodec,
|
|
22375
|
+
seamless: seamlessAudio,
|
|
22376
|
+
chunkDurationInSeconds,
|
|
22377
|
+
addRemotionMetadata: !shouldCreateVideo,
|
|
22378
|
+
binariesDirectory,
|
|
22379
|
+
fps,
|
|
22380
|
+
cancelSignal,
|
|
22381
|
+
onProgress: (frames) => {
|
|
22382
|
+
concatenatedAudio = frames;
|
|
22383
|
+
updateProgress();
|
|
22384
|
+
}
|
|
22385
|
+
}) : null,
|
|
22386
|
+
shouldCreateVideo && !seamlessVideo && videoOutput ? combineVideoStreams({
|
|
22387
|
+
codec,
|
|
22388
|
+
filelistDir,
|
|
22389
|
+
fps,
|
|
22390
|
+
indent,
|
|
22391
|
+
logLevel,
|
|
22392
|
+
numberOfGifLoops,
|
|
22393
|
+
output: videoOutput,
|
|
22394
|
+
files: videoFiles,
|
|
22395
|
+
addRemotionMetadata: !shouldCreateAudio,
|
|
22396
|
+
binariesDirectory,
|
|
22397
|
+
cancelSignal,
|
|
22398
|
+
onProgress: (frames) => {
|
|
22399
|
+
concatenatedVideo = frames;
|
|
22400
|
+
updateProgress();
|
|
22401
|
+
}
|
|
22402
|
+
}) : null
|
|
22403
|
+
].filter(truthy));
|
|
22404
|
+
try {
|
|
22405
|
+
await muxVideoAndAudio({
|
|
22406
|
+
audioOutput,
|
|
22407
|
+
indent,
|
|
22408
|
+
logLevel,
|
|
22409
|
+
onProgress: (frames) => {
|
|
22410
|
+
muxing = frames;
|
|
22411
|
+
updateProgress();
|
|
22412
|
+
},
|
|
22413
|
+
output,
|
|
22414
|
+
videoOutput: seamlessVideo ? combineVideoStreamsSeamlessly({ files: videoFiles }) : videoOutput,
|
|
22415
|
+
binariesDirectory,
|
|
22416
|
+
fps,
|
|
22417
|
+
cancelSignal,
|
|
22418
|
+
addFaststart: codecSupportsFastStart[codec],
|
|
22419
|
+
metadata
|
|
22420
|
+
});
|
|
22421
|
+
onProgress({ totalProgress: 1, frames: numberOfFrames });
|
|
22422
|
+
rmSync5(filelistDir, { recursive: true });
|
|
22423
|
+
} catch (err) {
|
|
22424
|
+
rmSync5(filelistDir, { recursive: true });
|
|
22425
|
+
throw err;
|
|
22426
|
+
}
|
|
22427
|
+
};
|
|
22428
|
+
var combineChunks = (options) => {
|
|
22429
|
+
return internalCombineChunks({
|
|
22430
|
+
audioBitrate: options.audioBitrate ?? null,
|
|
22431
|
+
numberOfGifLoops: options.numberOfGifLoops ?? null,
|
|
22432
|
+
indent: false,
|
|
22433
|
+
logLevel: options.logLevel ?? "info",
|
|
22434
|
+
binariesDirectory: options.binariesDirectory ?? null,
|
|
22435
|
+
cancelSignal: options.cancelSignal,
|
|
22436
|
+
metadata: options.metadata ?? null,
|
|
22437
|
+
audioCodec: options.audioCodec ?? null,
|
|
22438
|
+
preferLossless: options.preferLossless,
|
|
22439
|
+
audioFiles: options.audioFiles,
|
|
22440
|
+
codec: options.codec,
|
|
22441
|
+
fps: options.fps,
|
|
22442
|
+
framesPerChunk: options.framesPerChunk,
|
|
22443
|
+
outputLocation: options.outputLocation,
|
|
22444
|
+
onProgress: options.onProgress ?? (() => {
|
|
22445
|
+
}),
|
|
22446
|
+
videoFiles: options.videoFiles,
|
|
22447
|
+
everyNthFrame: options.everyNthFrame ?? 1,
|
|
22448
|
+
frameRange: options.frameRange ?? null,
|
|
22449
|
+
compositionDurationInFrames: options.compositionDurationInFrames
|
|
22450
|
+
});
|
|
22451
|
+
};
|
|
22391
22452
|
// src/extract-audio.ts
|
|
22392
22453
|
var extractAudio = async (options) => {
|
|
22393
22454
|
const compositor = startLongRunningCompositor({
|
|
@@ -22532,7 +22593,6 @@ var RenderInternals = {
|
|
|
22532
22593
|
convertToPositiveFrameIndex,
|
|
22533
22594
|
findRemotionRoot,
|
|
22534
22595
|
validateBitrate,
|
|
22535
|
-
combineChunks,
|
|
22536
22596
|
getMinConcurrency,
|
|
22537
22597
|
getMaxConcurrency,
|
|
22538
22598
|
getDefaultAudioCodec,
|
|
@@ -22573,7 +22633,10 @@ var RenderInternals = {
|
|
|
22573
22633
|
toMegabytes,
|
|
22574
22634
|
internalEnsureBrowser,
|
|
22575
22635
|
printUsefulErrorMessage,
|
|
22576
|
-
DEFAULT_RENDER_FRAMES_OFFTHREAD_VIDEO_THREADS
|
|
22636
|
+
DEFAULT_RENDER_FRAMES_OFFTHREAD_VIDEO_THREADS,
|
|
22637
|
+
canConcatVideoSeamlessly,
|
|
22638
|
+
canConcatAudioSeamlessly,
|
|
22639
|
+
internalCombineChunks
|
|
22577
22640
|
};
|
|
22578
22641
|
checkRuntimeVersion("info", false);
|
|
22579
22642
|
export {
|
|
@@ -22591,6 +22654,7 @@ export {
|
|
|
22591
22654
|
getCompositions,
|
|
22592
22655
|
extractAudio,
|
|
22593
22656
|
ensureBrowser,
|
|
22657
|
+
combineChunks,
|
|
22594
22658
|
RenderInternals,
|
|
22595
22659
|
ErrorWithStackFrame
|
|
22596
22660
|
};
|