@remotion/renderer 4.0.516 → 4.0.518
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/inline-audio-mixing.d.ts +6 -1
- package/dist/assets/inline-audio-mixing.js +42 -39
- package/dist/combine-chunks.js +0 -15
- package/dist/create-audio.js +22 -8
- package/dist/esm/index.mjs +295 -99
- package/dist/ffmpeg-args.js +1 -0
- package/dist/finalize-fast-start.d.ts +12 -0
- package/dist/finalize-fast-start.js +70 -0
- package/dist/get-codec-name.d.ts +3 -1
- package/dist/get-codec-name.js +11 -2
- package/dist/get-fast-start-muxer.d.ts +2 -0
- package/dist/get-fast-start-muxer.js +11 -0
- package/dist/merge-inline-audio-tracks.d.ts +21 -0
- package/dist/merge-inline-audio-tracks.js +74 -0
- package/dist/mux-video-and-audio.d.ts +1 -2
- package/dist/mux-video-and-audio.js +9 -3
- package/dist/prespawn-ffmpeg.d.ts +2 -0
- package/dist/prespawn-ffmpeg.js +1 -0
- package/dist/probe-encoder.d.ts +3 -1
- package/dist/probe-encoder.js +10 -1
- package/dist/render-media.js +2 -0
- package/dist/stitch-frames-to-video.d.ts +2 -0
- package/dist/stitch-frames-to-video.js +51 -30
- package/package.json +13 -13
package/dist/esm/index.mjs
CHANGED
|
@@ -17206,11 +17206,14 @@ var correctFloatingPointError = (value) => {
|
|
|
17206
17206
|
var BIT_DEPTH = 16;
|
|
17207
17207
|
var BYTES_PER_SAMPLE = BIT_DEPTH / 8;
|
|
17208
17208
|
var NUMBER_OF_CHANNELS = 2;
|
|
17209
|
+
var WAV_HEADER_SIZE = 44;
|
|
17209
17210
|
var makeInlineAudioMixing = (dir, sampleRate) => {
|
|
17210
17211
|
const folderToAdd = makeAndReturn(dir, "remotion-inline-audio-mixing");
|
|
17211
17212
|
const openFiles = {};
|
|
17212
17213
|
const writtenHeaders = {};
|
|
17213
17214
|
const toneFrequencies = {};
|
|
17215
|
+
const startTimesInSamples = {};
|
|
17216
|
+
const writtenDataSizes = {};
|
|
17214
17217
|
const cleanup = () => {
|
|
17215
17218
|
for (const fileName of Object.keys(openFiles)) {
|
|
17216
17219
|
try {
|
|
@@ -17221,42 +17224,39 @@ var makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
17221
17224
|
deleteDirectory(folderToAdd);
|
|
17222
17225
|
};
|
|
17223
17226
|
const getListOfAssets = () => {
|
|
17224
|
-
return Object.keys(
|
|
17227
|
+
return Object.keys(writtenHeaders).map((outName) => ({
|
|
17228
|
+
outName,
|
|
17229
|
+
startInSamples: startTimesInSamples[outName],
|
|
17230
|
+
durationInSamples: writtenDataSizes[outName] / (NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE)
|
|
17231
|
+
})).sort((a, b) => a.startInSamples - b.startInSamples);
|
|
17225
17232
|
};
|
|
17226
17233
|
const getFilePath = (asset) => {
|
|
17227
17234
|
return path15.join(folderToAdd, `${asset.id}.wav`);
|
|
17228
17235
|
};
|
|
17229
|
-
const ensureAsset = ({
|
|
17230
|
-
asset,
|
|
17231
|
-
fps,
|
|
17232
|
-
totalNumberOfFrames,
|
|
17233
|
-
trimLeftOffset,
|
|
17234
|
-
trimRightOffset
|
|
17235
|
-
}) => {
|
|
17236
|
+
const ensureAsset = (asset) => {
|
|
17236
17237
|
const filePath = getFilePath(asset);
|
|
17237
|
-
if (
|
|
17238
|
+
if (openFiles[filePath] === undefined) {
|
|
17238
17239
|
openFiles[filePath] = fs15.openSync(filePath, "w");
|
|
17239
17240
|
}
|
|
17240
17241
|
if (writtenHeaders[filePath]) {
|
|
17241
17242
|
return;
|
|
17242
17243
|
}
|
|
17243
17244
|
writtenHeaders[filePath] = true;
|
|
17244
|
-
|
|
17245
|
-
const expectedSize = 40 + expectedDataSize;
|
|
17245
|
+
writtenDataSizes[filePath] = 0;
|
|
17246
17246
|
const fd = openFiles[filePath];
|
|
17247
17247
|
writeSync(fd, new Uint8Array([82, 73, 70, 70]), 0, 4, 0);
|
|
17248
|
-
writeSync(fd,
|
|
17248
|
+
writeSync(fd, numberTo32BiIntLittleEndian(36), 0, 4, 4);
|
|
17249
17249
|
writeSync(fd, new Uint8Array([87, 65, 86, 69]), 0, 4, 8);
|
|
17250
17250
|
writeSync(fd, new Uint8Array([102, 109, 116, 32]), 0, 4, 12);
|
|
17251
17251
|
writeSync(fd, new Uint8Array([BIT_DEPTH, 0, 0, 0]), 0, 4, 16);
|
|
17252
17252
|
writeSync(fd, new Uint8Array([1, 0]), 0, 2, 20);
|
|
17253
17253
|
writeSync(fd, new Uint8Array([NUMBER_OF_CHANNELS, 0]), 0, 2, 22);
|
|
17254
|
-
writeSync(fd,
|
|
17255
|
-
writeSync(fd,
|
|
17256
|
-
writeSync(fd,
|
|
17254
|
+
writeSync(fd, numberTo32BiIntLittleEndian(sampleRate), 0, 4, 24);
|
|
17255
|
+
writeSync(fd, numberTo32BiIntLittleEndian(sampleRate * NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE), 0, 4, 28);
|
|
17256
|
+
writeSync(fd, numberTo16BitLittleEndian(NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE), 0, 2, 32);
|
|
17257
17257
|
writeSync(fd, numberTo16BitLittleEndian(BIT_DEPTH), 0, 2, 34);
|
|
17258
17258
|
writeSync(fd, new Uint8Array([100, 97, 116, 97]), 0, 4, 36);
|
|
17259
|
-
writeSync(fd,
|
|
17259
|
+
writeSync(fd, numberTo32BiIntLittleEndian(0), 0, 4, 40);
|
|
17260
17260
|
};
|
|
17261
17261
|
const finish = async ({
|
|
17262
17262
|
binariesDirectory,
|
|
@@ -17265,7 +17265,14 @@ var makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
17265
17265
|
cancelSignal,
|
|
17266
17266
|
sampleRate: finishSampleRate
|
|
17267
17267
|
}) => {
|
|
17268
|
-
for (const fileName of Object.keys(
|
|
17268
|
+
for (const fileName of Object.keys(writtenHeaders)) {
|
|
17269
|
+
const fd = openFiles[fileName];
|
|
17270
|
+
const dataSize = Math.max(0, fs15.fstatSync(fd).size - WAV_HEADER_SIZE);
|
|
17271
|
+
writtenDataSizes[fileName] = dataSize;
|
|
17272
|
+
writeSync(fd, numberTo32BiIntLittleEndian(36 + dataSize), 0, 4, 4);
|
|
17273
|
+
writeSync(fd, numberTo32BiIntLittleEndian(dataSize), 0, 4, 40);
|
|
17274
|
+
fs15.closeSync(fd);
|
|
17275
|
+
delete openFiles[fileName];
|
|
17269
17276
|
const frequency = toneFrequencies[fileName];
|
|
17270
17277
|
if (frequency === 1) {
|
|
17271
17278
|
continue;
|
|
@@ -17281,9 +17288,6 @@ var makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
17281
17288
|
cancelSignal,
|
|
17282
17289
|
sampleRate: finishSampleRate
|
|
17283
17290
|
});
|
|
17284
|
-
try {
|
|
17285
|
-
fs15.closeSync(openFiles[fileName]);
|
|
17286
|
-
} catch {}
|
|
17287
17291
|
fs15.renameSync(tmpFile, fileName);
|
|
17288
17292
|
}
|
|
17289
17293
|
};
|
|
@@ -17295,19 +17299,20 @@ var makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
17295
17299
|
trimLeftOffset,
|
|
17296
17300
|
trimRightOffset
|
|
17297
17301
|
}) => {
|
|
17298
|
-
ensureAsset(
|
|
17299
|
-
asset,
|
|
17300
|
-
fps,
|
|
17301
|
-
totalNumberOfFrames,
|
|
17302
|
-
trimLeftOffset,
|
|
17303
|
-
trimRightOffset
|
|
17304
|
-
});
|
|
17302
|
+
ensureAsset(asset);
|
|
17305
17303
|
const filePath = getFilePath(asset);
|
|
17306
17304
|
if (toneFrequencies[filePath] !== undefined && toneFrequencies[filePath] !== asset.toneFrequency) {
|
|
17307
17305
|
throw new Error(`toneFrequency must be the same across the entire audio, got ${asset.toneFrequency}, but before it was ${toneFrequencies[filePath]}`);
|
|
17308
17306
|
}
|
|
17309
17307
|
const fileDescriptor = openFiles[filePath];
|
|
17310
17308
|
toneFrequencies[filePath] = asset.toneFrequency;
|
|
17309
|
+
const assetStartInVideo = asset.startInVideo ?? firstFrame;
|
|
17310
|
+
const firstFrameForAsset = Math.max(assetStartInVideo, firstFrame);
|
|
17311
|
+
const startInSamples = Math.max(0, Math.floor(correctFloatingPointError(((firstFrameForAsset - firstFrame) / fps - trimLeftOffset) * sampleRate)));
|
|
17312
|
+
if (startTimesInSamples[filePath] !== undefined && startTimesInSamples[filePath] !== startInSamples) {
|
|
17313
|
+
throw new Error(`The start time for inline audio asset ${asset.id} changed from ${startTimesInSamples[filePath]} to ${startInSamples} samples`);
|
|
17314
|
+
}
|
|
17315
|
+
startTimesInSamples[filePath] = startInSamples;
|
|
17311
17316
|
let arr = new Int16Array(asset.audio);
|
|
17312
17317
|
const isFirst = asset.frame === firstFrame;
|
|
17313
17318
|
const isLast = asset.frame === totalNumberOfFrames + firstFrame - 1;
|
|
@@ -17319,9 +17324,10 @@ var makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
17319
17324
|
if (isLast) {
|
|
17320
17325
|
arr = arr.slice(0, arr.length + Math.ceil(correctFloatingPointError(samplesToShaveFromEnd)) * NUMBER_OF_CHANNELS);
|
|
17321
17326
|
}
|
|
17322
|
-
const
|
|
17323
|
-
const position = Math.floor(correctFloatingPointError(
|
|
17324
|
-
writeSync(fileDescriptor, arr, 0, arr.byteLength,
|
|
17327
|
+
const positionInRenderInSeconds = (asset.frame - firstFrame) / fps - (isFirst ? 0 : trimLeftOffset);
|
|
17328
|
+
const position = (Math.floor(correctFloatingPointError(positionInRenderInSeconds * sampleRate)) - startInSamples) * NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE;
|
|
17329
|
+
writeSync(fileDescriptor, arr, 0, arr.byteLength, WAV_HEADER_SIZE + position);
|
|
17330
|
+
writtenDataSizes[filePath] = Math.max(writtenDataSizes[filePath], position + arr.byteLength);
|
|
17325
17331
|
};
|
|
17326
17332
|
return {
|
|
17327
17333
|
cleanup,
|
|
@@ -21564,7 +21570,7 @@ var renderFrames = (options2) => {
|
|
|
21564
21570
|
// src/render-media.ts
|
|
21565
21571
|
import fs19 from "node:fs";
|
|
21566
21572
|
import os10 from "node:os";
|
|
21567
|
-
import
|
|
21573
|
+
import path30 from "node:path";
|
|
21568
21574
|
import { LicensingInternals } from "@remotion/licensing";
|
|
21569
21575
|
import { NoReactInternals as NoReactInternals17 } from "remotion/no-react";
|
|
21570
21576
|
|
|
@@ -21844,7 +21850,8 @@ var getCodecName = ({
|
|
|
21844
21850
|
crf,
|
|
21845
21851
|
hardwareAcceleration,
|
|
21846
21852
|
logLevel,
|
|
21847
|
-
indent
|
|
21853
|
+
indent,
|
|
21854
|
+
onLog
|
|
21848
21855
|
}) => {
|
|
21849
21856
|
const preferredHwAcceleration = hardwareAcceleration === "required" || hardwareAcceleration === "if-possible";
|
|
21850
21857
|
const unsupportedQualityOption = hasSpecifiedUnsupportedHardwareQualifySettings({
|
|
@@ -21857,8 +21864,17 @@ var getCodecName = ({
|
|
|
21857
21864
|
}
|
|
21858
21865
|
const warnAboutDisabledHardwareAcceleration = () => {
|
|
21859
21866
|
if (hardwareAcceleration === "if-possible" && unsupportedQualityOption) {
|
|
21867
|
+
const message = `Hardware accelerated encoding disabled - "${unsupportedQualityOption}" option is not supported with hardware acceleration`;
|
|
21868
|
+
if (onLog !== null) {
|
|
21869
|
+
onLog({
|
|
21870
|
+
logLevel: "warn",
|
|
21871
|
+
previewString: message,
|
|
21872
|
+
tag: ""
|
|
21873
|
+
});
|
|
21874
|
+
return;
|
|
21875
|
+
}
|
|
21860
21876
|
Log.warn({ indent, logLevel }, `${indent ? "" : `
|
|
21861
|
-
`}
|
|
21877
|
+
`}${message}`);
|
|
21862
21878
|
}
|
|
21863
21879
|
};
|
|
21864
21880
|
if (codec === "prores") {
|
|
@@ -21990,7 +22006,8 @@ var generateFfmpegArgs = ({
|
|
|
21990
22006
|
crf,
|
|
21991
22007
|
hardwareAcceleration,
|
|
21992
22008
|
indent,
|
|
21993
|
-
logLevel
|
|
22009
|
+
logLevel,
|
|
22010
|
+
onLog: null
|
|
21994
22011
|
});
|
|
21995
22012
|
if (encoderSettings === null) {
|
|
21996
22013
|
throw new TypeError(`encoderSettings is null: ${JSON.stringify(codec)} (hwaccel = ${hardwareAcceleration})`);
|
|
@@ -22105,7 +22122,8 @@ var resolveHardwareAcceleration = ({
|
|
|
22105
22122
|
logLevel,
|
|
22106
22123
|
crf,
|
|
22107
22124
|
encodingMaxRate,
|
|
22108
|
-
encodingBufferSize
|
|
22125
|
+
encodingBufferSize,
|
|
22126
|
+
onLog
|
|
22109
22127
|
}) => {
|
|
22110
22128
|
if (hardwareAcceleration === "disable") {
|
|
22111
22129
|
return "disable";
|
|
@@ -22117,12 +22135,20 @@ var resolveHardwareAcceleration = ({
|
|
|
22117
22135
|
encodingMaxRate,
|
|
22118
22136
|
encodingBufferSize,
|
|
22119
22137
|
logLevel,
|
|
22120
|
-
indent
|
|
22138
|
+
indent,
|
|
22139
|
+
onLog
|
|
22121
22140
|
});
|
|
22122
22141
|
if (preferred === null) {
|
|
22123
22142
|
return hardwareAcceleration;
|
|
22124
22143
|
}
|
|
22125
22144
|
if (!preferred.hardwareAccelerated) {
|
|
22145
|
+
if (hardwareAcceleration === "if-possible" && hasSpecifiedUnsupportedHardwareQualifySettings({
|
|
22146
|
+
crf,
|
|
22147
|
+
encodingMaxRate,
|
|
22148
|
+
encodingBufferSize
|
|
22149
|
+
})) {
|
|
22150
|
+
return "disable";
|
|
22151
|
+
}
|
|
22126
22152
|
return hardwareAcceleration;
|
|
22127
22153
|
}
|
|
22128
22154
|
const encoderAvailable = probeEncoderAvailability({
|
|
@@ -22209,7 +22235,8 @@ var prespawnFfmpeg = (options2) => {
|
|
|
22209
22235
|
logLevel: options2.logLevel,
|
|
22210
22236
|
crf: options2.crf,
|
|
22211
22237
|
encodingMaxRate: options2.encodingMaxRate,
|
|
22212
|
-
encodingBufferSize: options2.encodingBufferSize
|
|
22238
|
+
encodingBufferSize: options2.encodingBufferSize,
|
|
22239
|
+
onLog: options2.onLog
|
|
22213
22240
|
});
|
|
22214
22241
|
const ffmpegArgs = [
|
|
22215
22242
|
["-r", options2.fps],
|
|
@@ -22342,8 +22369,8 @@ var validateSelectedCodecAndProResCombination = ({
|
|
|
22342
22369
|
};
|
|
22343
22370
|
|
|
22344
22371
|
// src/stitch-frames-to-video.ts
|
|
22345
|
-
import { cpSync as cpSync2, promises as
|
|
22346
|
-
import
|
|
22372
|
+
import { cpSync as cpSync2, promises as promises5, rmSync as rmSync4 } from "node:fs";
|
|
22373
|
+
import path29 from "node:path";
|
|
22347
22374
|
|
|
22348
22375
|
// src/convert-number-of-gif-loops-to-ffmpeg.ts
|
|
22349
22376
|
var convertNumberOfGifLoopsToFfmpegSyntax = (loops) => {
|
|
@@ -22357,7 +22384,7 @@ var convertNumberOfGifLoopsToFfmpegSyntax = (loops) => {
|
|
|
22357
22384
|
};
|
|
22358
22385
|
|
|
22359
22386
|
// src/create-audio.ts
|
|
22360
|
-
import
|
|
22387
|
+
import path27 from "path";
|
|
22361
22388
|
|
|
22362
22389
|
// src/resolve-asset-src.ts
|
|
22363
22390
|
import url from "node:url";
|
|
@@ -22831,6 +22858,83 @@ var mergeAudioTrack = (options2) => {
|
|
|
22831
22858
|
return limit2(mergeAudioTrackUnlimited, options2);
|
|
22832
22859
|
};
|
|
22833
22860
|
|
|
22861
|
+
// src/merge-inline-audio-tracks.ts
|
|
22862
|
+
import path26 from "node:path";
|
|
22863
|
+
var MAX_INLINE_AUDIO_INPUTS = 10;
|
|
22864
|
+
var inlineAudioTrackToPreprocessedAudioTrack = ({
|
|
22865
|
+
track,
|
|
22866
|
+
relativeToInSamples,
|
|
22867
|
+
padToDurationInSamples
|
|
22868
|
+
}) => {
|
|
22869
|
+
const delayInSamples = Math.max(0, track.startInSamples - relativeToInSamples);
|
|
22870
|
+
const padAtEndInSamples = padToDurationInSamples === null ? 0 : Math.max(0, padToDurationInSamples - delayInSamples - track.durationInSamples);
|
|
22871
|
+
return {
|
|
22872
|
+
outName: track.outName,
|
|
22873
|
+
filter: {
|
|
22874
|
+
pad_start: delayInSamples === 0 ? null : `adelay=${new Array(3).fill(`${delayInSamples}S`).join("|")}`,
|
|
22875
|
+
pad_end: padAtEndInSamples === 0 ? null : `apad=pad_len=${padAtEndInSamples}`
|
|
22876
|
+
}
|
|
22877
|
+
};
|
|
22878
|
+
};
|
|
22879
|
+
var mergeInlineAudioTracks = async ({
|
|
22880
|
+
tracks,
|
|
22881
|
+
downloadMap,
|
|
22882
|
+
remotionRoot,
|
|
22883
|
+
indent,
|
|
22884
|
+
logLevel,
|
|
22885
|
+
binariesDirectory,
|
|
22886
|
+
cancelSignal,
|
|
22887
|
+
fps,
|
|
22888
|
+
chunkLengthInSeconds,
|
|
22889
|
+
sampleRate
|
|
22890
|
+
}) => {
|
|
22891
|
+
let currentTracks = tracks.sort((a, b) => a.startInSamples - b.startInSamples);
|
|
22892
|
+
let level = 0;
|
|
22893
|
+
while (currentTracks.length > 1) {
|
|
22894
|
+
const groups = chunk2(currentTracks, MAX_INLINE_AUDIO_INPUTS);
|
|
22895
|
+
currentTracks = await Promise.all(groups.map(async (group, index) => {
|
|
22896
|
+
if (group.length === 1) {
|
|
22897
|
+
return group[0];
|
|
22898
|
+
}
|
|
22899
|
+
const [{ startInSamples }] = group;
|
|
22900
|
+
const durationInSamples = Math.max(...group.map((track) => {
|
|
22901
|
+
return track.startInSamples - startInSamples + track.durationInSamples;
|
|
22902
|
+
}));
|
|
22903
|
+
const outName = path26.join(downloadMap.audioMixing, `inline-${level}-${index}.wav`);
|
|
22904
|
+
await mergeAudioTrack({
|
|
22905
|
+
files: group.map((track) => inlineAudioTrackToPreprocessedAudioTrack({
|
|
22906
|
+
track,
|
|
22907
|
+
relativeToInSamples: startInSamples,
|
|
22908
|
+
padToDurationInSamples: null
|
|
22909
|
+
})),
|
|
22910
|
+
outName,
|
|
22911
|
+
downloadMap,
|
|
22912
|
+
remotionRoot,
|
|
22913
|
+
indent,
|
|
22914
|
+
logLevel,
|
|
22915
|
+
binariesDirectory,
|
|
22916
|
+
cancelSignal,
|
|
22917
|
+
onProgress: () => {
|
|
22918
|
+
return;
|
|
22919
|
+
},
|
|
22920
|
+
fps,
|
|
22921
|
+
chunkLengthInSeconds,
|
|
22922
|
+
sampleRate
|
|
22923
|
+
});
|
|
22924
|
+
for (const track of group) {
|
|
22925
|
+
deleteDirectory(track.outName);
|
|
22926
|
+
}
|
|
22927
|
+
return {
|
|
22928
|
+
outName,
|
|
22929
|
+
startInSamples,
|
|
22930
|
+
durationInSamples
|
|
22931
|
+
};
|
|
22932
|
+
}));
|
|
22933
|
+
level++;
|
|
22934
|
+
}
|
|
22935
|
+
return currentTracks[0] ?? null;
|
|
22936
|
+
};
|
|
22937
|
+
|
|
22834
22938
|
// src/assets/calculate-atempo.ts
|
|
22835
22939
|
var calculateATempo = (playbackRate) => {
|
|
22836
22940
|
if (playbackRate === 1) {
|
|
@@ -23204,7 +23308,7 @@ var createAudio = async ({
|
|
|
23204
23308
|
onProgress(totalProgress);
|
|
23205
23309
|
};
|
|
23206
23310
|
const audioTracks = await Promise.all(assetPositions.map(async (asset, index) => {
|
|
23207
|
-
const filterFile =
|
|
23311
|
+
const filterFile = path27.join(downloadMap.audioMixing, `${index}.wav`);
|
|
23208
23312
|
const result = await preprocessAudioTrack({
|
|
23209
23313
|
outName: filterFile,
|
|
23210
23314
|
asset,
|
|
@@ -23237,20 +23341,31 @@ var createAudio = async ({
|
|
|
23237
23341
|
sampleRate
|
|
23238
23342
|
});
|
|
23239
23343
|
const inlinedAudio = downloadMap.inlineAudioMixing.getListOfAssets();
|
|
23344
|
+
const mergedInlineAudio = await mergeInlineAudioTracks({
|
|
23345
|
+
tracks: inlinedAudio,
|
|
23346
|
+
downloadMap,
|
|
23347
|
+
remotionRoot,
|
|
23348
|
+
indent,
|
|
23349
|
+
logLevel,
|
|
23350
|
+
binariesDirectory,
|
|
23351
|
+
cancelSignal,
|
|
23352
|
+
fps,
|
|
23353
|
+
chunkLengthInSeconds,
|
|
23354
|
+
sampleRate
|
|
23355
|
+
});
|
|
23240
23356
|
const preprocessed = [
|
|
23241
23357
|
...audioTracks.filter(truthy),
|
|
23242
|
-
...
|
|
23243
|
-
|
|
23244
|
-
|
|
23245
|
-
|
|
23246
|
-
|
|
23247
|
-
|
|
23248
|
-
|
|
23249
|
-
}))
|
|
23358
|
+
...mergedInlineAudio ? [
|
|
23359
|
+
inlineAudioTrackToPreprocessedAudioTrack({
|
|
23360
|
+
track: mergedInlineAudio,
|
|
23361
|
+
relativeToInSamples: 0,
|
|
23362
|
+
padToDurationInSamples: Math.round(chunkLengthInSeconds * sampleRate)
|
|
23363
|
+
})
|
|
23364
|
+
] : []
|
|
23250
23365
|
];
|
|
23251
|
-
const merged =
|
|
23366
|
+
const merged = path27.join(downloadMap.audioPreprocessing, "merged.wav");
|
|
23252
23367
|
const extension = getExtensionFromAudioCodec(audioCodec);
|
|
23253
|
-
const outName =
|
|
23368
|
+
const outName = path27.join(downloadMap.audioPreprocessing, `audio.${extension}`);
|
|
23254
23369
|
await mergeAudioTrack({
|
|
23255
23370
|
files: preprocessed,
|
|
23256
23371
|
outName: merged,
|
|
@@ -23292,6 +23407,85 @@ var createAudio = async ({
|
|
|
23292
23407
|
return outName;
|
|
23293
23408
|
};
|
|
23294
23409
|
|
|
23410
|
+
// src/finalize-fast-start.ts
|
|
23411
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
23412
|
+
import { promises as promises4 } from "node:fs";
|
|
23413
|
+
import path28 from "node:path";
|
|
23414
|
+
var finalizeFastStart = async ({
|
|
23415
|
+
input,
|
|
23416
|
+
output,
|
|
23417
|
+
muxer,
|
|
23418
|
+
force,
|
|
23419
|
+
indent,
|
|
23420
|
+
logLevel,
|
|
23421
|
+
binariesDirectory,
|
|
23422
|
+
cancelSignal
|
|
23423
|
+
}) => {
|
|
23424
|
+
let fastStartFile = null;
|
|
23425
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
23426
|
+
const candidate = path28.join(path28.dirname(output), `${path28.basename(output)}.${randomUUID2()}.remotion-in-progress`);
|
|
23427
|
+
const task = callFf({
|
|
23428
|
+
bin: "ffmpeg",
|
|
23429
|
+
args: [
|
|
23430
|
+
"-hide_banner",
|
|
23431
|
+
"-i",
|
|
23432
|
+
input,
|
|
23433
|
+
"-c",
|
|
23434
|
+
"copy",
|
|
23435
|
+
"-movflags",
|
|
23436
|
+
"faststart",
|
|
23437
|
+
"-y",
|
|
23438
|
+
"-f",
|
|
23439
|
+
muxer,
|
|
23440
|
+
candidate
|
|
23441
|
+
],
|
|
23442
|
+
indent,
|
|
23443
|
+
logLevel,
|
|
23444
|
+
binariesDirectory,
|
|
23445
|
+
cancelSignal: cancelSignal ?? undefined
|
|
23446
|
+
});
|
|
23447
|
+
let stderr = "";
|
|
23448
|
+
task.stderr?.on("data", (data) => {
|
|
23449
|
+
stderr += data.toString();
|
|
23450
|
+
});
|
|
23451
|
+
try {
|
|
23452
|
+
await task;
|
|
23453
|
+
fastStartFile = candidate;
|
|
23454
|
+
break;
|
|
23455
|
+
} catch (error) {
|
|
23456
|
+
await promises4.rm(candidate, { force: true }).catch(() => {
|
|
23457
|
+
return;
|
|
23458
|
+
});
|
|
23459
|
+
const isReopenFailure = stderr.includes("Unable to re-open") && stderr.includes("output file for shifting data");
|
|
23460
|
+
if (!isReopenFailure || attempt === 2) {
|
|
23461
|
+
throw error;
|
|
23462
|
+
}
|
|
23463
|
+
Log.verbose({ indent, logLevel, tag: "stitchFramesToVideo()" }, `Retrying Fast Start finalization (attempt ${attempt + 2} of 3)`);
|
|
23464
|
+
}
|
|
23465
|
+
}
|
|
23466
|
+
if (fastStartFile === null) {
|
|
23467
|
+
throw new Error("Fast Start finalization did not produce an output file");
|
|
23468
|
+
}
|
|
23469
|
+
if (force) {
|
|
23470
|
+
await promises4.rename(fastStartFile, output);
|
|
23471
|
+
return;
|
|
23472
|
+
}
|
|
23473
|
+
try {
|
|
23474
|
+
await promises4.link(fastStartFile, output);
|
|
23475
|
+
} finally {
|
|
23476
|
+
await promises4.rm(fastStartFile, { force: true });
|
|
23477
|
+
}
|
|
23478
|
+
};
|
|
23479
|
+
|
|
23480
|
+
// src/get-fast-start-muxer.ts
|
|
23481
|
+
var getFastStartMuxer = (outputExtension) => {
|
|
23482
|
+
const normalizedExtension = outputExtension.toLowerCase();
|
|
23483
|
+
if (normalizedExtension === "mp4" || normalizedExtension === "mov") {
|
|
23484
|
+
return normalizedExtension;
|
|
23485
|
+
}
|
|
23486
|
+
return null;
|
|
23487
|
+
};
|
|
23488
|
+
|
|
23295
23489
|
// src/make-metadata-args.ts
|
|
23296
23490
|
import { VERSION as VERSION5 } from "remotion/version";
|
|
23297
23491
|
var makeMetadataArgs = (metadata) => {
|
|
@@ -23384,7 +23578,8 @@ var innerStitchFramesToVideo = async ({
|
|
|
23384
23578
|
separateAudioTo,
|
|
23385
23579
|
metadata,
|
|
23386
23580
|
hardwareAcceleration,
|
|
23387
|
-
sampleRate
|
|
23581
|
+
sampleRate,
|
|
23582
|
+
onLog
|
|
23388
23583
|
}, remotionRoot) => {
|
|
23389
23584
|
validateDimension(height, "height", "passed to `stitchFramesToVideo()`");
|
|
23390
23585
|
validateDimension(width, "width", "passed to `stitchFramesToVideo()`");
|
|
@@ -23430,7 +23625,10 @@ var innerStitchFramesToVideo = async ({
|
|
|
23430
23625
|
setting: audioCodecSetting,
|
|
23431
23626
|
separateAudioTo
|
|
23432
23627
|
});
|
|
23433
|
-
const tempFile = outputLocation ? null :
|
|
23628
|
+
const tempFile = outputLocation ? null : path29.join(assetsInfo.downloadMap.stitchFrames, `out.${getFileExtensionFromCodec(codec, resolvedAudioCodec)}`);
|
|
23629
|
+
const outputExtension = (getExtensionOfFilename(outputLocation) ?? getFileExtensionFromCodec(codec, resolvedAudioCodec)).toLowerCase();
|
|
23630
|
+
const fastStartMuxer = getFastStartMuxer(outputExtension);
|
|
23631
|
+
const fastStartIntermediate = fastStartMuxer === null ? null : path29.join(assetsInfo.downloadMap.stitchFrames, "fast-start-intermediate.remotion-in-progress");
|
|
23434
23632
|
Log.verbose({
|
|
23435
23633
|
indent,
|
|
23436
23634
|
logLevel,
|
|
@@ -23506,10 +23704,10 @@ var innerStitchFramesToVideo = async ({
|
|
|
23506
23704
|
}
|
|
23507
23705
|
cpSync2(audio, outputLocation ?? tempFile);
|
|
23508
23706
|
onProgress?.(Math.round(assetsInfo.chunkLengthInSeconds * fps));
|
|
23509
|
-
deleteDirectory(
|
|
23707
|
+
deleteDirectory(path29.dirname(audio));
|
|
23510
23708
|
const file = await new Promise((resolve2, reject) => {
|
|
23511
23709
|
if (tempFile) {
|
|
23512
|
-
|
|
23710
|
+
promises5.readFile(tempFile).then((f) => {
|
|
23513
23711
|
return resolve2(f);
|
|
23514
23712
|
}).catch((e) => reject(e));
|
|
23515
23713
|
} else {
|
|
@@ -23520,7 +23718,7 @@ var innerStitchFramesToVideo = async ({
|
|
|
23520
23718
|
assetsInfo.downloadMap.allowCleanup();
|
|
23521
23719
|
return Promise.resolve(file);
|
|
23522
23720
|
}
|
|
23523
|
-
const resolvedHardwareAcceleration = resolveHardwareAcceleration({
|
|
23721
|
+
const resolvedHardwareAcceleration = preEncodedFileLocation ? "disable" : resolveHardwareAcceleration({
|
|
23524
23722
|
codec,
|
|
23525
23723
|
hardwareAcceleration,
|
|
23526
23724
|
binariesDirectory,
|
|
@@ -23528,7 +23726,8 @@ var innerStitchFramesToVideo = async ({
|
|
|
23528
23726
|
logLevel,
|
|
23529
23727
|
crf,
|
|
23530
23728
|
encodingMaxRate: maxRate,
|
|
23531
|
-
encodingBufferSize: bufferSize
|
|
23729
|
+
encodingBufferSize: bufferSize,
|
|
23730
|
+
onLog
|
|
23532
23731
|
});
|
|
23533
23732
|
const ffmpegArgs = [
|
|
23534
23733
|
...preEncodedFileLocation ? [["-i", preEncodedFileLocation]] : [
|
|
@@ -23557,11 +23756,11 @@ var innerStitchFramesToVideo = async ({
|
|
|
23557
23756
|
indent,
|
|
23558
23757
|
logLevel
|
|
23559
23758
|
}),
|
|
23560
|
-
codec === "h264" ? ["-movflags", "faststart"] : null,
|
|
23561
23759
|
["-map_metadata", "-1"],
|
|
23562
23760
|
...makeMetadataArgs(metadata ?? {}),
|
|
23563
|
-
force ? "-y" : null,
|
|
23564
|
-
|
|
23761
|
+
force || fastStartIntermediate ? "-y" : null,
|
|
23762
|
+
fastStartIntermediate ? ["-f", fastStartMuxer] : null,
|
|
23763
|
+
fastStartIntermediate ?? outputLocation ?? tempFile
|
|
23565
23764
|
];
|
|
23566
23765
|
const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
|
|
23567
23766
|
const finalFfmpegString = ffmpegOverride ? ffmpegOverride({ type: "stitcher", args: ffmpegString }) : ffmpegString;
|
|
@@ -23606,29 +23805,37 @@ var innerStitchFramesToVideo = async ({
|
|
|
23606
23805
|
if (!audio) {
|
|
23607
23806
|
throw new Error(`\`separateAudioTo\` was set to ${JSON.stringify(separateAudioTo)}, but this render included no audio`);
|
|
23608
23807
|
}
|
|
23609
|
-
const finalDestination =
|
|
23808
|
+
const finalDestination = path29.resolve(remotionRoot, separateAudioTo);
|
|
23610
23809
|
cpSync2(audio, finalDestination);
|
|
23611
23810
|
rmSync4(audio);
|
|
23612
23811
|
}
|
|
23613
|
-
|
|
23812
|
+
await new Promise((resolve2, reject) => {
|
|
23614
23813
|
task.once("close", (code, signal) => {
|
|
23615
23814
|
if (code === 0) {
|
|
23616
|
-
|
|
23617
|
-
cleanDownloadMap(assetsInfo.downloadMap);
|
|
23618
|
-
return resolve2(null);
|
|
23619
|
-
}
|
|
23620
|
-
promises4.readFile(tempFile).then((f) => {
|
|
23621
|
-
resolve2(f);
|
|
23622
|
-
}).catch((e) => {
|
|
23623
|
-
reject(e);
|
|
23624
|
-
}).finally(() => {
|
|
23625
|
-
cleanDownloadMap(assetsInfo.downloadMap);
|
|
23626
|
-
});
|
|
23815
|
+
resolve2();
|
|
23627
23816
|
} else {
|
|
23628
23817
|
reject(new Error(`FFmpeg quit with code ${code} ${signal ? `(${signal})` : ""} The FFmpeg output was ${ffmpegStderr}`));
|
|
23629
23818
|
}
|
|
23630
23819
|
});
|
|
23631
23820
|
});
|
|
23821
|
+
if (fastStartIntermediate && fastStartMuxer) {
|
|
23822
|
+
const destination = outputLocation ?? tempFile;
|
|
23823
|
+
if (destination === null) {
|
|
23824
|
+
throw new Error("Expected a Fast Start output destination");
|
|
23825
|
+
}
|
|
23826
|
+
await finalizeFastStart({
|
|
23827
|
+
input: fastStartIntermediate,
|
|
23828
|
+
output: path29.resolve(remotionRoot, destination),
|
|
23829
|
+
muxer: fastStartMuxer,
|
|
23830
|
+
force,
|
|
23831
|
+
indent,
|
|
23832
|
+
logLevel,
|
|
23833
|
+
binariesDirectory,
|
|
23834
|
+
cancelSignal
|
|
23835
|
+
});
|
|
23836
|
+
}
|
|
23837
|
+
const result = tempFile === null ? null : await promises5.readFile(tempFile);
|
|
23838
|
+
cleanDownloadMap(assetsInfo.downloadMap);
|
|
23632
23839
|
assetsInfo.downloadMap.allowCleanup();
|
|
23633
23840
|
return result;
|
|
23634
23841
|
};
|
|
@@ -23711,7 +23918,8 @@ var stitchFramesToVideo = ({
|
|
|
23711
23918
|
metadata: metadata ?? null,
|
|
23712
23919
|
separateAudioTo: separateAudioTo ?? null,
|
|
23713
23920
|
hardwareAcceleration: hardwareAcceleration ?? "disable",
|
|
23714
|
-
sampleRate: sampleRate ?? 48000
|
|
23921
|
+
sampleRate: sampleRate ?? 48000,
|
|
23922
|
+
onLog: defaultOnLog
|
|
23715
23923
|
});
|
|
23716
23924
|
};
|
|
23717
23925
|
|
|
@@ -23975,7 +24183,7 @@ var internalRenderMediaRaw = ({
|
|
|
23975
24183
|
separateAudioTo
|
|
23976
24184
|
});
|
|
23977
24185
|
}
|
|
23978
|
-
const absoluteOutputLocation = outputLocation ?
|
|
24186
|
+
const absoluteOutputLocation = outputLocation ? path30.resolve(process.cwd(), outputLocation) : null;
|
|
23979
24187
|
validateScale(scale);
|
|
23980
24188
|
validateFfmpegOverride(ffmpegOverride);
|
|
23981
24189
|
validateEveryNthFrame(everyNthFrame);
|
|
@@ -24041,8 +24249,8 @@ var internalRenderMediaRaw = ({
|
|
|
24041
24249
|
}
|
|
24042
24250
|
const imageFormat = isAudioCodec(codec) ? "none" : provisionalImageFormat ?? compositionWithPossibleUnevenDimensions.defaultVideoImageFormat ?? DEFAULT_VIDEO_IMAGE_FORMAT;
|
|
24043
24251
|
validateSelectedPixelFormatAndImageFormatCombination(pixelFormat, imageFormat);
|
|
24044
|
-
const workingDir = fs19.mkdtempSync(
|
|
24045
|
-
const preEncodedFileLocation = parallelEncoding ?
|
|
24252
|
+
const workingDir = fs19.mkdtempSync(path30.join(os10.tmpdir(), "react-motion-render"));
|
|
24253
|
+
const preEncodedFileLocation = parallelEncoding ? path30.join(workingDir, "pre-encode." + getFileExtensionFromCodec(codec, audioCodec)) : null;
|
|
24046
24254
|
if (onCtrlCExit && workingDir) {
|
|
24047
24255
|
onCtrlCExit(`Delete ${workingDir}`, () => deleteDirectory(workingDir));
|
|
24048
24256
|
}
|
|
@@ -24115,7 +24323,8 @@ var internalRenderMediaRaw = ({
|
|
|
24115
24323
|
gopSize,
|
|
24116
24324
|
colorSpace,
|
|
24117
24325
|
binariesDirectory,
|
|
24118
|
-
hardwareAcceleration
|
|
24326
|
+
hardwareAcceleration,
|
|
24327
|
+
onLog
|
|
24119
24328
|
});
|
|
24120
24329
|
stitcherFfmpeg = preStitcher.task;
|
|
24121
24330
|
}
|
|
@@ -24319,6 +24528,7 @@ var internalRenderMediaRaw = ({
|
|
|
24319
24528
|
separateAudioTo,
|
|
24320
24529
|
metadata,
|
|
24321
24530
|
hardwareAcceleration,
|
|
24531
|
+
onLog,
|
|
24322
24532
|
sampleRate
|
|
24323
24533
|
});
|
|
24324
24534
|
}).then((buffer2) => {
|
|
@@ -24382,7 +24592,7 @@ var internalRenderMediaRaw = ({
|
|
|
24382
24592
|
reject(err);
|
|
24383
24593
|
}).finally(() => {
|
|
24384
24594
|
if (preEncodedFileLocation !== null && fs19.existsSync(preEncodedFileLocation)) {
|
|
24385
|
-
deleteDirectory(
|
|
24595
|
+
deleteDirectory(path30.dirname(preEncodedFileLocation));
|
|
24386
24596
|
}
|
|
24387
24597
|
if (workingDir && fs19.existsSync(workingDir)) {
|
|
24388
24598
|
deleteDirectory(workingDir);
|
|
@@ -24560,7 +24770,7 @@ var renderMedia = ({
|
|
|
24560
24770
|
|
|
24561
24771
|
// src/render-still.ts
|
|
24562
24772
|
import fs20, { statSync as statSync2 } from "node:fs";
|
|
24563
|
-
import
|
|
24773
|
+
import path31 from "node:path";
|
|
24564
24774
|
import { LicensingInternals as LicensingInternals2 } from "@remotion/licensing";
|
|
24565
24775
|
import { NoReactInternals as NoReactInternals18 } from "remotion/no-react";
|
|
24566
24776
|
var innerRenderStill = async ({
|
|
@@ -24611,7 +24821,7 @@ var innerRenderStill = async ({
|
|
|
24611
24821
|
});
|
|
24612
24822
|
validatePuppeteerTimeout(timeoutInMilliseconds);
|
|
24613
24823
|
validateScale(scale);
|
|
24614
|
-
output = typeof output === "string" ?
|
|
24824
|
+
output = typeof output === "string" ? path31.resolve(process.cwd(), output) : null;
|
|
24615
24825
|
validateJpegQuality(jpegQuality);
|
|
24616
24826
|
if (output) {
|
|
24617
24827
|
if (fs20.existsSync(output)) {
|
|
@@ -25393,12 +25603,13 @@ var muxVideoAndAudio = async ({
|
|
|
25393
25603
|
binariesDirectory,
|
|
25394
25604
|
fps,
|
|
25395
25605
|
cancelSignal,
|
|
25396
|
-
addFaststart,
|
|
25397
25606
|
metadata,
|
|
25398
25607
|
numberOfGifLoops
|
|
25399
25608
|
}) => {
|
|
25400
25609
|
const startTime = Date.now();
|
|
25401
25610
|
Log.verbose({ indent, logLevel }, "Muxing video and audio together");
|
|
25611
|
+
const outputExtension = getExtensionOfFilename(output);
|
|
25612
|
+
const fastStartMuxer = outputExtension ? getFastStartMuxer(outputExtension) : null;
|
|
25402
25613
|
const command = [
|
|
25403
25614
|
"-hide_banner",
|
|
25404
25615
|
videoOutput ? "-i" : null,
|
|
@@ -25413,8 +25624,8 @@ var muxVideoAndAudio = async ({
|
|
|
25413
25624
|
videoOutput ? String(fps) : null,
|
|
25414
25625
|
numberOfGifLoops === null ? null : "-loop",
|
|
25415
25626
|
numberOfGifLoops === null ? null : convertNumberOfGifLoopsToFfmpegSyntax(numberOfGifLoops),
|
|
25416
|
-
|
|
25417
|
-
|
|
25627
|
+
fastStartMuxer ? "-movflags" : null,
|
|
25628
|
+
fastStartMuxer ? "faststart" : null,
|
|
25418
25629
|
...makeMetadataArgs(metadata ?? {}),
|
|
25419
25630
|
"-y",
|
|
25420
25631
|
output
|
|
@@ -25445,20 +25656,6 @@ var muxVideoAndAudio = async ({
|
|
|
25445
25656
|
};
|
|
25446
25657
|
|
|
25447
25658
|
// src/combine-chunks.ts
|
|
25448
|
-
var codecSupportsFastStart = {
|
|
25449
|
-
"h264-mkv": false,
|
|
25450
|
-
"h264-ts": false,
|
|
25451
|
-
h264: true,
|
|
25452
|
-
h265: true,
|
|
25453
|
-
av1: true,
|
|
25454
|
-
aac: false,
|
|
25455
|
-
gif: false,
|
|
25456
|
-
mp3: false,
|
|
25457
|
-
prores: false,
|
|
25458
|
-
vp8: false,
|
|
25459
|
-
vp9: false,
|
|
25460
|
-
wav: false
|
|
25461
|
-
};
|
|
25462
25659
|
var REMOTION_FILELIST_TOKEN = "remotion-filelist";
|
|
25463
25660
|
var internalCombineChunks = async ({
|
|
25464
25661
|
outputLocation: output,
|
|
@@ -25564,7 +25761,6 @@ var internalCombineChunks = async ({
|
|
|
25564
25761
|
binariesDirectory,
|
|
25565
25762
|
fps,
|
|
25566
25763
|
cancelSignal,
|
|
25567
|
-
addFaststart: codecSupportsFastStart[codec],
|
|
25568
25764
|
metadata,
|
|
25569
25765
|
numberOfGifLoops
|
|
25570
25766
|
});
|