UNPKG

@remotion/renderer

Version:

Render Remotion videos using Node.js or Bun

134 lines (133 loc) 5.28 kB
"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;