134 lines
5.2 KiB
JavaScript
134 lines
5.2 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.mergeAudioTrack = void 0;
|
|
const node_path_1 = __importDefault(require("node:path"));
|
|
const call_ffmpeg_1 = require("./call-ffmpeg");
|
|
const chunk_1 = require("./chunk");
|
|
const create_ffmpeg_complex_filter_1 = require("./create-ffmpeg-complex-filter");
|
|
const create_ffmpeg_merge_filter_1 = require("./create-ffmpeg-merge-filter");
|
|
const create_silent_audio_1 = require("./create-silent-audio");
|
|
const delete_directory_1 = require("./delete-directory");
|
|
const logger_1 = require("./logger");
|
|
const p_limit_1 = require("./p-limit");
|
|
const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
|
|
const tmp_dir_1 = require("./tmp-dir");
|
|
const truthy_1 = require("./truthy");
|
|
const mergeAudioTrackUnlimited = async ({ outName, files, downloadMap, remotionRoot, indent, logLevel, binariesDirectory, cancelSignal, onProgress, fps, chunkLengthInSeconds, }) => {
|
|
var _a;
|
|
if (files.length === 0) {
|
|
await (0, create_silent_audio_1.createSilentAudio)({
|
|
outName,
|
|
chunkLengthInSeconds,
|
|
indent,
|
|
logLevel,
|
|
binariesDirectory,
|
|
cancelSignal,
|
|
});
|
|
onProgress(1);
|
|
return;
|
|
}
|
|
// Previously a bug: We cannot optimize for files.length === 1 because we need to pad the audio
|
|
// In FFMPEG, the total number of left and right tracks that can be merged at one time is limited to 64
|
|
if (files.length >= 32) {
|
|
const chunked = (0, chunk_1.chunk)(files, 10);
|
|
const tempPath = (0, tmp_dir_1.tmpDir)('remotion-large-audio-mixing');
|
|
try {
|
|
const partialProgress = new Array(chunked.length).fill(0);
|
|
let finalProgress = 0;
|
|
const callProgress = () => {
|
|
const totalProgress = partialProgress.reduce((a, b) => a + b, 0) / chunked.length;
|
|
const combinedProgress = totalProgress * 0.8 + finalProgress * 0.2;
|
|
onProgress(combinedProgress);
|
|
};
|
|
const chunkNames = await Promise.all(chunked.map(async (chunkFiles, i) => {
|
|
const chunkOutname = node_path_1.default.join(tempPath, `chunk-${i}.wav`);
|
|
await (0, exports.mergeAudioTrack)({
|
|
files: chunkFiles,
|
|
chunkLengthInSeconds,
|
|
outName: chunkOutname,
|
|
downloadMap,
|
|
remotionRoot,
|
|
indent,
|
|
logLevel,
|
|
binariesDirectory,
|
|
cancelSignal,
|
|
onProgress: (progress) => {
|
|
partialProgress[i] = progress;
|
|
callProgress();
|
|
},
|
|
fps,
|
|
});
|
|
return chunkOutname;
|
|
}));
|
|
await (0, exports.mergeAudioTrack)({
|
|
files: chunkNames.map((c) => ({
|
|
filter: {
|
|
pad_end: null,
|
|
pad_start: null,
|
|
},
|
|
outName: c,
|
|
})),
|
|
outName,
|
|
downloadMap,
|
|
remotionRoot,
|
|
indent,
|
|
logLevel,
|
|
binariesDirectory,
|
|
cancelSignal,
|
|
onProgress: (progress) => {
|
|
finalProgress = progress;
|
|
callProgress();
|
|
},
|
|
fps,
|
|
chunkLengthInSeconds,
|
|
});
|
|
return;
|
|
}
|
|
finally {
|
|
(0, delete_directory_1.deleteDirectory)(tempPath);
|
|
}
|
|
}
|
|
const { complexFilterFlag: mergeFilter, cleanup, complexFilter, } = await (0, create_ffmpeg_complex_filter_1.createFfmpegComplexFilter)({
|
|
filters: files,
|
|
downloadMap,
|
|
});
|
|
const args = [
|
|
['-hide_banner'],
|
|
...files.map((f) => ['-i', f.outName]),
|
|
mergeFilter,
|
|
['-c:a', 'pcm_s16le'],
|
|
['-map', `[${create_ffmpeg_merge_filter_1.OUTPUT_FILTER_NAME}]`],
|
|
['-y', outName],
|
|
]
|
|
.filter(truthy_1.truthy)
|
|
.flat(2);
|
|
logger_1.Log.verbose({ indent, logLevel }, `Merging audio tracks`, 'Command:', `ffmpeg ${args.join(' ')}`, 'Complex filter script:', complexFilter);
|
|
const task = (0, call_ffmpeg_1.callFf)({
|
|
bin: 'ffmpeg',
|
|
args,
|
|
indent,
|
|
logLevel,
|
|
binariesDirectory,
|
|
cancelSignal,
|
|
});
|
|
(_a = task.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
const utf8 = data.toString('utf8');
|
|
const parsed = (0, parse_ffmpeg_progress_1.parseFfmpegProgress)(utf8, fps);
|
|
if (parsed !== undefined) {
|
|
onProgress(parsed / (chunkLengthInSeconds * fps));
|
|
}
|
|
});
|
|
await task;
|
|
onProgress(1);
|
|
cleanup();
|
|
};
|
|
// Must be at least 3 because recursively called twice in mergeAudioTrack
|
|
const limit = (0, p_limit_1.pLimit)(3);
|
|
const mergeAudioTrack = (options) => {
|
|
return limit(mergeAudioTrackUnlimited, options);
|
|
};
|
|
exports.mergeAudioTrack = mergeAudioTrack;
|