@remotion/renderer 4.0.122 → 4.0.123

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.
Files changed (60) hide show
  1. package/dist/assets/get-audio-channels.d.ts +10 -2
  2. package/dist/assets/get-audio-channels.js +12 -4
  3. package/dist/calculate-ffmpeg-filters.d.ts +2 -1
  4. package/dist/calculate-ffmpeg-filters.js +14 -3
  5. package/dist/call-ffmpeg.d.ts +6 -2
  6. package/dist/call-ffmpeg.js +12 -4
  7. package/dist/can-use-parallel-encoding.js +2 -2
  8. package/dist/client.d.ts +252 -26
  9. package/dist/client.js +3 -3
  10. package/dist/codec-supports-media.js +5 -0
  11. package/dist/codec.d.ts +1 -1
  12. package/dist/codec.js +1 -0
  13. package/dist/combine-audio.d.ts +1 -1
  14. package/dist/combine-audio.js +1 -1
  15. package/dist/combine-videos.d.ts +8 -3
  16. package/dist/combine-videos.js +85 -61
  17. package/dist/compress-audio.d.ts +5 -2
  18. package/dist/compress-audio.js +22 -3
  19. package/dist/create-audio.d.ts +1 -1
  20. package/dist/create-audio.js +25 -5
  21. package/dist/create-silent-audio.d.ts +3 -1
  22. package/dist/create-silent-audio.js +2 -1
  23. package/dist/crf.js +7 -7
  24. package/dist/ffmpeg-args.js +1 -0
  25. package/dist/file-extensions.d.ts +2 -2
  26. package/dist/file-extensions.js +7 -0
  27. package/dist/get-codec-name.js +3 -3
  28. package/dist/get-extension-from-codec.d.ts +3 -3
  29. package/dist/get-extension-from-codec.js +1 -0
  30. package/dist/guess-extension-for-media.d.ts +3 -1
  31. package/dist/guess-extension-for-media.js +2 -1
  32. package/dist/index.d.ts +49 -21
  33. package/dist/index.js +4 -4
  34. package/dist/merge-audio-track.d.ts +5 -1
  35. package/dist/merge-audio-track.js +40 -3
  36. package/dist/options/audio-codec.d.ts +55 -0
  37. package/dist/options/audio-codec.js +190 -0
  38. package/dist/options/enforce-audio.d.ts +4 -1
  39. package/dist/options/enforce-audio.js +3 -3
  40. package/dist/options/for-seamless-aac-concatenation.js +1 -1
  41. package/dist/options/gl.d.ts +3 -3
  42. package/dist/options/index.d.ts +84 -9
  43. package/dist/options/index.js +8 -0
  44. package/dist/options/options-map.d.ts +137 -6
  45. package/dist/options/options-map.js +13 -0
  46. package/dist/options/separate-audio.d.ts +18 -0
  47. package/dist/options/separate-audio.js +28 -0
  48. package/dist/options/video-codec.d.ts +1 -1
  49. package/dist/preprocess-audio-track.d.ts +4 -0
  50. package/dist/preprocess-audio-track.js +28 -2
  51. package/dist/prespawn-ffmpeg.js +1 -3
  52. package/dist/pure.d.ts +4 -3
  53. package/dist/render-media.d.ts +1 -4
  54. package/dist/render-media.js +10 -5
  55. package/dist/stitch-frames-to-video.d.ts +6 -4
  56. package/dist/stitch-frames-to-video.js +36 -98
  57. package/dist/stringify-ffmpeg-filter.js +9 -8
  58. package/dist/validate-output-filename.d.ts +4 -3
  59. package/dist/validate-output-filename.js +10 -4
  60. package/package.json +9 -9
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
1
3
  import execa from 'execa';
2
4
  import { HeadlessBrowser } from './browser/Browser';
3
5
  import { SymbolicateableError } from './error-handling/symbolicateable-error';
4
6
  import { mimeContentType, mimeLookup } from './mime-types';
5
7
  import * as perf from './perf';
6
8
  export type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
7
- export { AudioCodec } from './audio-codec';
8
9
  export { Browser } from './browser';
9
10
  export { BrowserExecutable } from './browser-executable';
10
11
  export { BrowserLog } from './browser-log';
@@ -42,6 +43,8 @@ export { stitchFramesToVideo, StitchFramesToVideoOptions, } from './stitch-frame
42
43
  export { SymbolicatedStackFrame } from './symbolicate-stacktrace';
43
44
  export { OnStartData, RenderFramesOutput } from './types';
44
45
  export { validateOutputFilename } from './validate-output-filename';
46
+ export type { AudioCodec };
47
+ import type { AudioCodec } from './options/audio-codec';
45
48
  export declare const RenderInternals: {
46
49
  ensureLocalBrowser: ({ indent, logLevel, preferredBrowserExecutable, }: {
47
50
  preferredBrowserExecutable: import("./browser-executable").BrowserExecutable;
@@ -67,10 +70,10 @@ export declare const RenderInternals: {
67
70
  width: number;
68
71
  height: number;
69
72
  scale: number;
70
- codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
73
+ codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
71
74
  wantsImageSequence: boolean;
72
75
  }) => void;
73
- getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">(codec: T, audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null) => import("./file-extensions").FileExtension;
76
+ getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif">(codec: T, audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null) => import("./file-extensions").FileExtension;
74
77
  tmpDir: (str: string) => string;
75
78
  deleteDirectory: (directory: string) => void;
76
79
  isServeUrl: (potentialUrl: string) => boolean;
@@ -127,7 +130,7 @@ export declare const RenderInternals: {
127
130
  };
128
131
  registerErrorSymbolicationLock: () => number;
129
132
  unlockErrorSymbolicationLock: (id: number) => void;
130
- canUseParallelEncoding: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => boolean;
133
+ canUseParallelEncoding: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif") => boolean;
131
134
  mimeContentType: typeof mimeContentType;
132
135
  mimeLookup: typeof mimeLookup;
133
136
  validateConcurrency: ({ setting, value, checkIfValidForCurrentMachine, }: {
@@ -138,14 +141,14 @@ export declare const RenderInternals: {
138
141
  validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
139
142
  DEFAULT_BROWSER: "chrome";
140
143
  validateFrameRange: (frameRange: import("./frame-range").FrameRange | null) => void;
141
- DEFAULT_OPENGL_RENDERER: "swangle" | "angle" | "egl" | "swiftshader" | "vulkan" | "angle-egl" | null;
142
- validateOpenGlRenderer: (option: unknown) => "swangle" | "angle" | "egl" | "swiftshader" | "vulkan" | "angle-egl" | null;
143
- validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "gif"];
144
+ DEFAULT_OPENGL_RENDERER: "angle" | "swangle" | "egl" | "swiftshader" | "vulkan" | "angle-egl" | null;
145
+ validateOpenGlRenderer: (option: unknown) => "angle" | "swangle" | "egl" | "swiftshader" | "vulkan" | "angle-egl" | null;
146
+ validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "h264-ts", "gif"];
144
147
  DEFAULT_PIXEL_FORMAT: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
145
148
  validateJpegQuality: (q: unknown) => void;
146
149
  DEFAULT_TIMEOUT: number;
147
- DEFAULT_CODEC: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
148
- isAudioCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif" | null | undefined) => boolean;
150
+ DEFAULT_CODEC: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
151
+ isAudioCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif" | null | undefined) => boolean;
149
152
  logLevels: readonly ["verbose", "info", "warn", "error"];
150
153
  isEqualOrBelowLogLevel: (currentLevel: "verbose" | "info" | "warn" | "error", level: "verbose" | "info" | "warn" | "error") => boolean;
151
154
  isValidLogLevel: (level: string) => boolean;
@@ -156,28 +159,31 @@ export declare const RenderInternals: {
156
159
  }) => number;
157
160
  findRemotionRoot: () => string;
158
161
  validateBitrate: (bitrate: unknown, name: string) => void;
159
- combineVideos: (options: {
162
+ combineVideos: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, resolvedAudioCodec, audioBitrate, indent, logLevel, chunkDurationInSeconds, binariesDirectory, cancelSignal, seamlessAudio, seamlessVideo, }: {
160
163
  files: string[];
161
164
  filelistDir: string;
162
165
  output: string;
163
166
  onProgress: (p: number) => void;
164
167
  numberOfFrames: number;
165
- codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
168
+ codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
166
169
  fps: number;
167
170
  numberOfGifLoops: number | null;
168
- audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null;
171
+ resolvedAudioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null;
169
172
  audioBitrate: string | null;
170
173
  indent: boolean;
171
174
  logLevel: "verbose" | "info" | "warn" | "error";
175
+ chunkDurationInSeconds: number;
172
176
  binariesDirectory: string | null;
177
+ cancelSignal: import("./make-cancel-signal").CancelSignal | undefined;
178
+ seamlessAudio: boolean;
179
+ seamlessVideo: boolean;
173
180
  }) => Promise<void>;
174
181
  getMinConcurrency: () => number;
175
182
  getMaxConcurrency: () => number;
176
183
  getDefaultAudioCodec: ({ codec, preferLossless, }: {
177
- codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
184
+ codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
178
185
  preferLossless: boolean;
179
186
  }) => "mp3" | "aac" | "pcm-16" | "opus" | null;
180
- validAudioCodecs: readonly ["pcm-16", "aac", "mp3", "opus"];
181
187
  defaultFileExtensionMap: {
182
188
  h264: {
183
189
  default: import("./file-extensions").FileExtension;
@@ -296,6 +302,19 @@ export declare const RenderInternals: {
296
302
  };
297
303
  };
298
304
  };
305
+ "h264-ts": {
306
+ default: import("./file-extensions").FileExtension;
307
+ forAudioCodec: {
308
+ aac: {
309
+ possible: import("./file-extensions").FileExtension[];
310
+ default: import("./file-extensions").FileExtension;
311
+ };
312
+ "pcm-16": {
313
+ possible: import("./file-extensions").FileExtension[];
314
+ default: import("./file-extensions").FileExtension;
315
+ };
316
+ };
317
+ };
299
318
  gif: {
300
319
  default: import("./file-extensions").FileExtension;
301
320
  forAudioCodec: {};
@@ -304,6 +323,7 @@ export declare const RenderInternals: {
304
323
  supportedAudioCodecs: {
305
324
  readonly h264: readonly ["aac", "pcm-16", "mp3"];
306
325
  readonly 'h264-mkv': readonly ["pcm-16", "mp3"];
326
+ readonly 'h264-ts': readonly ["pcm-16", "aac"];
307
327
  readonly aac: readonly ["aac", "pcm-16"];
308
328
  readonly gif: readonly [];
309
329
  readonly h265: readonly ["aac", "pcm-16"];
@@ -313,26 +333,27 @@ export declare const RenderInternals: {
313
333
  readonly vp9: readonly ["opus", "pcm-16"];
314
334
  readonly wav: readonly ["pcm-16"];
315
335
  };
316
- makeFileExtensionMap: () => Record<string, ("h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif")[]>;
317
- defaultCodecsForFileExtension: Record<import("./file-extensions").FileExtension, "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">;
336
+ makeFileExtensionMap: () => Record<string, ("h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif")[]>;
337
+ defaultCodecsForFileExtension: Record<import("./file-extensions").FileExtension, "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif">;
318
338
  getExecutablePath: ({ indent, logLevel, type, binariesDirectory, }: {
319
- type: "compositor" | "ffmpeg" | "ffprobe";
339
+ type: "ffmpeg" | "ffprobe" | "compositor";
320
340
  indent: boolean;
321
341
  logLevel: "verbose" | "info" | "warn" | "error";
322
342
  binariesDirectory: string | null;
323
343
  }) => string;
324
- callFf: ({ args, bin, indent, logLevel, options, binariesDirectory, }: {
344
+ callFf: ({ args, bin, indent, logLevel, options, binariesDirectory, cancelSignal, }: {
325
345
  bin: "ffmpeg" | "ffprobe";
326
346
  args: (string | null)[];
327
347
  indent: boolean;
328
348
  logLevel: "verbose" | "info" | "warn" | "error";
329
349
  binariesDirectory: string | null;
350
+ cancelSignal: import("./make-cancel-signal").CancelSignal | undefined;
330
351
  options?: execa.Options<string> | undefined;
331
352
  }) => execa.ExecaChildProcess<string>;
332
353
  validStillImageFormats: readonly ["png", "jpeg", "pdf", "webp"];
333
354
  validVideoImageFormats: readonly ["png", "jpeg", "none"];
334
- DEFAULT_STILL_IMAGE_FORMAT: "png" | "jpeg" | "pdf" | "webp";
335
- DEFAULT_VIDEO_IMAGE_FORMAT: "png" | "jpeg" | "none";
355
+ DEFAULT_STILL_IMAGE_FORMAT: "jpeg" | "png" | "webp" | "pdf";
356
+ DEFAULT_VIDEO_IMAGE_FORMAT: "jpeg" | "png" | "none";
336
357
  DEFAULT_JPEG_QUALITY: number;
337
358
  chalk: {
338
359
  enabled: () => boolean;
@@ -429,7 +450,7 @@ export declare const RenderInternals: {
429
450
  frame: number;
430
451
  serializedInputPropsWithCustomSchema: string;
431
452
  serializedResolvedPropsWithCustomSchema: string;
432
- imageFormat: "png" | "jpeg" | "pdf" | "webp";
453
+ imageFormat: "jpeg" | "png" | "webp" | "pdf";
433
454
  jpegQuality: number;
434
455
  puppeteerInstance: HeadlessBrowser | null;
435
456
  envVariables: Record<string, string>;
@@ -715,5 +736,12 @@ export declare const RenderInternals: {
715
736
  hostsToTry: string[];
716
737
  };
717
738
  makeDownloadMap: () => import("./assets/download-map").DownloadMap;
739
+ getExtensionFromAudioCodec: (audioCodec: "mp3" | "aac" | "pcm-16" | "opus") => "mp3" | "aac" | "wav" | "opus";
718
740
  makeFileExecutableIfItIsNot: (path: string) => void;
741
+ resolveAudioCodec: ({ codec, setting, preferLossless, separateAudioTo, }: {
742
+ setting: "mp3" | "aac" | "pcm-16" | "opus" | null;
743
+ codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
744
+ preferLossless: boolean;
745
+ separateAudioTo: string | null;
746
+ }) => "mp3" | "aac" | "pcm-16" | "opus" | null;
719
747
  };
package/dist/index.js CHANGED
@@ -29,7 +29,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.RenderInternals = exports.validateOutputFilename = exports.stitchFramesToVideo = exports.selectComposition = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.validateSelectedPixelFormatAndImageFormatCombination = exports.getVideoMetadata = exports.getSilentParts = exports.getCompositions = exports.extractAudio = exports.ErrorWithStackFrame = void 0;
30
30
  const execa_1 = __importDefault(require("execa"));
31
31
  const download_file_1 = require("./assets/download-file");
32
- const audio_codec_1 = require("./audio-codec");
33
32
  const browser_1 = require("./browser");
34
33
  const Browser_1 = require("./browser/Browser");
35
34
  const TimeoutSettings_1 = require("./browser/TimeoutSettings");
@@ -59,7 +58,6 @@ const get_frame_to_render_1 = require("./get-frame-to-render");
59
58
  const get_local_browser_executable_1 = require("./get-local-browser-executable");
60
59
  const get_port_1 = require("./get-port");
61
60
  const image_format_1 = require("./image-format");
62
- const is_audio_codec_1 = require("./is-audio-codec");
63
61
  const is_serve_url_1 = require("./is-serve-url");
64
62
  const jpeg_quality_1 = require("./jpeg-quality");
65
63
  const log_level_1 = require("./log-level");
@@ -112,6 +110,7 @@ var validate_output_filename_1 = require("./validate-output-filename");
112
110
  Object.defineProperty(exports, "validateOutputFilename", { enumerable: true, get: function () { return validate_output_filename_1.validateOutputFilename; } });
113
111
  const download_map_1 = require("./assets/download-map");
114
112
  const make_file_executable_1 = require("./compositor/make-file-executable");
113
+ const audio_codec_1 = require("./options/audio-codec");
115
114
  const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
116
115
  const validate_videobitrate_1 = require("./validate-videobitrate");
117
116
  const wait_for_symbolication_error_to_be_done_1 = require("./wait-for-symbolication-error-to-be-done");
@@ -153,7 +152,7 @@ exports.RenderInternals = {
153
152
  validateJpegQuality: jpeg_quality_1.validateJpegQuality,
154
153
  DEFAULT_TIMEOUT: TimeoutSettings_1.DEFAULT_TIMEOUT,
155
154
  DEFAULT_CODEC: codec_1.DEFAULT_CODEC,
156
- isAudioCodec: is_audio_codec_1.isAudioCodec,
155
+ isAudioCodec: audio_codec_1.isAudioCodec,
157
156
  logLevels: log_level_1.logLevels,
158
157
  isEqualOrBelowLogLevel: log_level_1.isEqualOrBelowLogLevel,
159
158
  isValidLogLevel: log_level_1.isValidLogLevel,
@@ -165,7 +164,6 @@ exports.RenderInternals = {
165
164
  getMinConcurrency: validate_concurrency_1.getMinConcurrency,
166
165
  getMaxConcurrency: validate_concurrency_1.getMaxConcurrency,
167
166
  getDefaultAudioCodec: audio_codec_1.getDefaultAudioCodec,
168
- validAudioCodecs: audio_codec_1.validAudioCodecs,
169
167
  defaultFileExtensionMap: file_extensions_1.defaultFileExtensionMap,
170
168
  supportedAudioCodecs: audio_codec_1.supportedAudioCodecs,
171
169
  makeFileExtensionMap: get_extension_from_codec_1.makeFileExtensionMap,
@@ -196,7 +194,9 @@ exports.RenderInternals = {
196
194
  getChromiumGpuInformation: test_gpu_1.getChromiumGpuInformation,
197
195
  getPortConfig: port_config_1.getPortConfig,
198
196
  makeDownloadMap: download_map_1.makeDownloadMap,
197
+ getExtensionFromAudioCodec: audio_codec_1.getExtensionFromAudioCodec,
199
198
  makeFileExecutableIfItIsNot: make_file_executable_1.makeFileExecutableIfItIsNot,
199
+ resolveAudioCodec: audio_codec_1.resolveAudioCodec,
200
200
  };
201
201
  // Warn of potential performance issues with Apple Silicon (M1 chip under Rosetta)
202
202
  (0, check_version_requirements_1.checkNodeVersionAndWarnAboutRosetta)('info', false);
@@ -1,15 +1,19 @@
1
1
  import type { DownloadMap } from './assets/download-map';
2
2
  import type { LogLevel } from './log-level';
3
+ import type { CancelSignal } from './make-cancel-signal';
3
4
  import type { PreprocessedAudioTrack } from './preprocess-audio-track';
4
5
  type Options = {
5
6
  files: PreprocessedAudioTrack[];
6
7
  outName: string;
7
- numberOfSeconds: number;
8
8
  downloadMap: DownloadMap;
9
9
  remotionRoot: string;
10
10
  indent: boolean;
11
11
  logLevel: LogLevel;
12
12
  binariesDirectory: string | null;
13
+ cancelSignal: CancelSignal | undefined;
14
+ onProgress: (progress: number) => void;
15
+ fps: number;
16
+ expectedFrames: number;
13
17
  };
14
18
  export declare const mergeAudioTrack: (options: Options) => Promise<void>;
15
19
  export {};
@@ -11,10 +11,14 @@ const create_ffmpeg_complex_filter_1 = require("./create-ffmpeg-complex-filter")
11
11
  const create_ffmpeg_merge_filter_1 = require("./create-ffmpeg-merge-filter");
12
12
  const create_silent_audio_1 = require("./create-silent-audio");
13
13
  const delete_directory_1 = require("./delete-directory");
14
+ const logger_1 = require("./logger");
14
15
  const p_limit_1 = require("./p-limit");
16
+ const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
15
17
  const tmp_dir_1 = require("./tmp-dir");
16
18
  const truthy_1 = require("./truthy");
17
- const mergeAudioTrackUnlimited = async ({ outName, files, numberOfSeconds, downloadMap, remotionRoot, indent, logLevel, binariesDirectory, }) => {
19
+ const mergeAudioTrackUnlimited = async ({ outName, files, downloadMap, remotionRoot, indent, logLevel, binariesDirectory, cancelSignal, onProgress, fps, expectedFrames, }) => {
20
+ var _a;
21
+ const numberOfSeconds = Number((expectedFrames / fps).toFixed(3));
18
22
  if (files.length === 0) {
19
23
  await (0, create_silent_audio_1.createSilentAudio)({
20
24
  outName,
@@ -22,7 +26,9 @@ const mergeAudioTrackUnlimited = async ({ outName, files, numberOfSeconds, downl
22
26
  indent,
23
27
  logLevel,
24
28
  binariesDirectory,
29
+ cancelSignal,
25
30
  });
31
+ onProgress(1);
26
32
  return;
27
33
  }
28
34
  // Previously a bug: We cannot optimize for files.length === 1 because we need to pad the audio
@@ -31,17 +37,30 @@ const mergeAudioTrackUnlimited = async ({ outName, files, numberOfSeconds, downl
31
37
  const chunked = (0, chunk_1.chunk)(files, 10);
32
38
  const tempPath = (0, tmp_dir_1.tmpDir)('remotion-large-audio-mixing');
33
39
  try {
40
+ const partialProgress = new Array(chunked.length).fill(0);
41
+ let finalProgress = 0;
42
+ const callProgress = () => {
43
+ const totalProgress = partialProgress.reduce((a, b) => a + b, 0) / chunked.length;
44
+ const combinedProgress = totalProgress * 0.8 + finalProgress * 0.2;
45
+ onProgress(combinedProgress);
46
+ };
34
47
  const chunkNames = await Promise.all(chunked.map(async (chunkFiles, i) => {
35
48
  const chunkOutname = node_path_1.default.join(tempPath, `chunk-${i}.wav`);
36
49
  await (0, exports.mergeAudioTrack)({
37
50
  files: chunkFiles,
38
- numberOfSeconds,
51
+ expectedFrames,
39
52
  outName: chunkOutname,
40
53
  downloadMap,
41
54
  remotionRoot,
42
55
  indent,
43
56
  logLevel,
44
57
  binariesDirectory,
58
+ cancelSignal,
59
+ onProgress: (progress) => {
60
+ partialProgress[i] = progress;
61
+ callProgress();
62
+ },
63
+ fps,
45
64
  });
46
65
  return chunkOutname;
47
66
  }));
@@ -53,13 +72,19 @@ const mergeAudioTrackUnlimited = async ({ outName, files, numberOfSeconds, downl
53
72
  },
54
73
  outName: c,
55
74
  })),
56
- numberOfSeconds,
57
75
  outName,
58
76
  downloadMap,
59
77
  remotionRoot,
60
78
  indent,
61
79
  logLevel,
62
80
  binariesDirectory,
81
+ cancelSignal,
82
+ onProgress: (progress) => {
83
+ finalProgress = progress;
84
+ callProgress();
85
+ },
86
+ fps,
87
+ expectedFrames,
63
88
  });
64
89
  return;
65
90
  }
@@ -86,8 +111,20 @@ const mergeAudioTrackUnlimited = async ({ outName, files, numberOfSeconds, downl
86
111
  indent,
87
112
  logLevel,
88
113
  binariesDirectory,
114
+ cancelSignal,
115
+ });
116
+ (_a = task.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
117
+ const utf8 = data.toString('utf8');
118
+ const parsed = (0, parse_ffmpeg_progress_1.parseFfmpegProgress)(utf8, fps);
119
+ if (parsed === undefined) {
120
+ logger_1.Log.verbose({ indent, logLevel }, utf8);
121
+ }
122
+ else {
123
+ onProgress(parsed / expectedFrames);
124
+ }
89
125
  });
90
126
  await task;
127
+ onProgress(1);
91
128
  cleanup();
92
129
  };
93
130
  // Must be at least 3 because recursively called twice in mergeAudioTrack
@@ -0,0 +1,55 @@
1
+ import type { Codec } from '../codec';
2
+ export declare const validAudioCodecs: readonly ["pcm-16", "aac", "mp3", "opus"];
3
+ export type AudioCodec = (typeof validAudioCodecs)[number];
4
+ export declare const isAudioCodec: (codec: Codec | undefined | null) => boolean;
5
+ export declare const supportedAudioCodecs: {
6
+ readonly h264: readonly ["aac", "pcm-16", "mp3"];
7
+ readonly 'h264-mkv': readonly ["pcm-16", "mp3"];
8
+ readonly 'h264-ts': readonly ["pcm-16", "aac"];
9
+ readonly aac: readonly ["aac", "pcm-16"];
10
+ readonly gif: readonly [];
11
+ readonly h265: readonly ["aac", "pcm-16"];
12
+ readonly mp3: readonly ["mp3", "pcm-16"];
13
+ readonly prores: readonly ["aac", "pcm-16"];
14
+ readonly vp8: readonly ["opus", "pcm-16"];
15
+ readonly vp9: readonly ["opus", "pcm-16"];
16
+ readonly wav: readonly ["pcm-16"];
17
+ };
18
+ declare const audioCodecNames: readonly ["pcm_s16le", "libfdk_aac", "libmp3lame", "libopus"];
19
+ type FfmpegAudioCodecName = (typeof audioCodecNames)[number];
20
+ export declare const mapAudioCodecToFfmpegAudioCodecName: (audioCodec: AudioCodec) => FfmpegAudioCodecName;
21
+ export declare const defaultAudioCodecs: {
22
+ [key in Codec]: {
23
+ [k in 'compressed' | 'lossless']: (typeof supportedAudioCodecs)[key][number] | null;
24
+ };
25
+ };
26
+ export declare const getExtensionFromAudioCodec: (audioCodec: AudioCodec) => "mp3" | "aac" | "wav" | "opus";
27
+ export declare const resolveAudioCodec: ({ codec, setting, preferLossless, separateAudioTo, }: {
28
+ setting: AudioCodec | null;
29
+ codec: Codec;
30
+ preferLossless: boolean;
31
+ separateAudioTo: string | null;
32
+ }) => "mp3" | "aac" | "pcm-16" | "opus" | null;
33
+ export declare const getDefaultAudioCodec: ({ codec, preferLossless, }: {
34
+ codec: Codec;
35
+ preferLossless: boolean;
36
+ }) => AudioCodec | null;
37
+ export declare const audioCodecOption: {
38
+ cliFlag: "audio-codec";
39
+ setConfig: (audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null) => void;
40
+ getValue: ({ commandLine }: {
41
+ commandLine: Record<string, unknown>;
42
+ }) => {
43
+ source: string;
44
+ value: "mp3" | "aac" | "pcm-16" | "opus";
45
+ } | {
46
+ source: string;
47
+ value: null;
48
+ };
49
+ description: () => string;
50
+ docLink: string;
51
+ name: string;
52
+ ssrName: "audioCodec";
53
+ type: "mp3" | "aac" | "pcm-16" | "opus";
54
+ };
55
+ export {};
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.audioCodecOption = exports.getDefaultAudioCodec = exports.resolveAudioCodec = exports.getExtensionFromAudioCodec = exports.defaultAudioCodecs = exports.mapAudioCodecToFfmpegAudioCodecName = exports.supportedAudioCodecs = exports.isAudioCodec = exports.validAudioCodecs = void 0;
4
+ const separate_audio_1 = require("./separate-audio");
5
+ exports.validAudioCodecs = ['pcm-16', 'aac', 'mp3', 'opus'];
6
+ const isAudioCodec = (codec) => {
7
+ return codec === 'mp3' || codec === 'aac' || codec === 'wav';
8
+ };
9
+ exports.isAudioCodec = isAudioCodec;
10
+ exports.supportedAudioCodecs = {
11
+ h264: ['aac', 'pcm-16', 'mp3'],
12
+ 'h264-mkv': ['pcm-16', 'mp3'],
13
+ 'h264-ts': ['pcm-16', 'aac'],
14
+ aac: ['aac', 'pcm-16'],
15
+ gif: [],
16
+ h265: ['aac', 'pcm-16'],
17
+ mp3: ['mp3', 'pcm-16'],
18
+ prores: ['aac', 'pcm-16'],
19
+ vp8: ['opus', 'pcm-16'],
20
+ vp9: ['opus', 'pcm-16'],
21
+ wav: ['pcm-16'],
22
+ };
23
+ const _satisfies = exports.supportedAudioCodecs;
24
+ if (_satisfies) {
25
+ // Just for type checking
26
+ }
27
+ const audioCodecNames = [
28
+ 'pcm_s16le',
29
+ 'libfdk_aac',
30
+ 'libmp3lame',
31
+ 'libopus',
32
+ ];
33
+ const mapAudioCodecToFfmpegAudioCodecName = (audioCodec) => {
34
+ if (audioCodec === 'aac') {
35
+ return 'libfdk_aac';
36
+ }
37
+ if (audioCodec === 'mp3') {
38
+ return 'libmp3lame';
39
+ }
40
+ if (audioCodec === 'opus') {
41
+ return 'libopus';
42
+ }
43
+ if (audioCodec === 'pcm-16') {
44
+ return 'pcm_s16le';
45
+ }
46
+ throw new Error('unknown audio codec: ' + audioCodec);
47
+ };
48
+ exports.mapAudioCodecToFfmpegAudioCodecName = mapAudioCodecToFfmpegAudioCodecName;
49
+ const cliFlag = 'audio-codec';
50
+ const ssrName = 'audioCodec';
51
+ exports.defaultAudioCodecs = {
52
+ 'h264-mkv': {
53
+ lossless: 'pcm-16',
54
+ compressed: 'pcm-16',
55
+ },
56
+ 'h264-ts': {
57
+ lossless: 'pcm-16',
58
+ compressed: 'aac',
59
+ },
60
+ aac: {
61
+ lossless: 'pcm-16',
62
+ compressed: 'aac',
63
+ },
64
+ gif: {
65
+ lossless: null,
66
+ compressed: null,
67
+ },
68
+ h264: {
69
+ lossless: 'pcm-16',
70
+ compressed: 'aac',
71
+ },
72
+ h265: {
73
+ lossless: 'pcm-16',
74
+ compressed: 'aac',
75
+ },
76
+ mp3: {
77
+ lossless: 'pcm-16',
78
+ compressed: 'mp3',
79
+ },
80
+ prores: {
81
+ lossless: 'pcm-16',
82
+ compressed: 'pcm-16',
83
+ },
84
+ vp8: {
85
+ lossless: 'pcm-16',
86
+ compressed: 'opus',
87
+ },
88
+ vp9: {
89
+ lossless: 'pcm-16',
90
+ compressed: 'opus',
91
+ },
92
+ wav: {
93
+ lossless: 'pcm-16',
94
+ compressed: 'pcm-16',
95
+ },
96
+ };
97
+ const extensionMap = {
98
+ aac: 'aac',
99
+ mp3: 'mp3',
100
+ opus: 'opus',
101
+ 'pcm-16': 'wav',
102
+ };
103
+ const getExtensionFromAudioCodec = (audioCodec) => {
104
+ if (extensionMap[audioCodec]) {
105
+ return extensionMap[audioCodec];
106
+ }
107
+ throw new Error(`Unsupported audio codec: ${audioCodec}`);
108
+ };
109
+ exports.getExtensionFromAudioCodec = getExtensionFromAudioCodec;
110
+ const resolveAudioCodec = ({ codec, setting, preferLossless, separateAudioTo, }) => {
111
+ let derivedFromSeparateAudioToExtension = null;
112
+ if (separateAudioTo) {
113
+ const extension = separateAudioTo.split('.').pop();
114
+ for (const [key, value] of Object.entries(extensionMap)) {
115
+ if (value === extension) {
116
+ derivedFromSeparateAudioToExtension = key;
117
+ if (!exports.supportedAudioCodecs[codec].includes(derivedFromSeparateAudioToExtension) &&
118
+ derivedFromSeparateAudioToExtension) {
119
+ throw new Error(`The codec is ${codec} but the audio codec derived from --${separate_audio_1.separateAudioOption.cliFlag} is ${derivedFromSeparateAudioToExtension}. The only supported codecs are: ${exports.supportedAudioCodecs[codec].join(', ')}`);
120
+ }
121
+ }
122
+ }
123
+ }
124
+ // Explanation: https://github.com/remotion-dev/remotion/issues/1647
125
+ if (preferLossless) {
126
+ const selected = (0, exports.getDefaultAudioCodec)({ codec, preferLossless });
127
+ if (derivedFromSeparateAudioToExtension &&
128
+ selected !== derivedFromSeparateAudioToExtension) {
129
+ throw new Error(`The audio codec derived from --${separate_audio_1.separateAudioOption.cliFlag} is ${derivedFromSeparateAudioToExtension}, but does not match the audio codec derived from the "Prefer lossless" option (${selected}). Remove any conflicting options.`);
130
+ }
131
+ return selected;
132
+ }
133
+ if (setting === null) {
134
+ if (derivedFromSeparateAudioToExtension) {
135
+ return derivedFromSeparateAudioToExtension;
136
+ }
137
+ return (0, exports.getDefaultAudioCodec)({ codec, preferLossless });
138
+ }
139
+ if (derivedFromSeparateAudioToExtension !== setting &&
140
+ derivedFromSeparateAudioToExtension) {
141
+ throw new Error(`The audio codec derived from --${separate_audio_1.separateAudioOption.cliFlag} is ${derivedFromSeparateAudioToExtension}, but does not match the audio codec derived from your ${exports.audioCodecOption.name} setting (${setting}). Remove any conflicting options.`);
142
+ }
143
+ return setting;
144
+ };
145
+ exports.resolveAudioCodec = resolveAudioCodec;
146
+ const getDefaultAudioCodec = ({ codec, preferLossless, }) => {
147
+ return exports.defaultAudioCodecs[codec][preferLossless ? 'lossless' : 'compressed'];
148
+ };
149
+ exports.getDefaultAudioCodec = getDefaultAudioCodec;
150
+ let _audioCodec = null;
151
+ exports.audioCodecOption = {
152
+ cliFlag,
153
+ setConfig: (audioCodec) => {
154
+ if (audioCodec === null) {
155
+ _audioCodec = null;
156
+ return;
157
+ }
158
+ if (!exports.validAudioCodecs.includes(audioCodec)) {
159
+ throw new Error(`Audio codec must be one of the following: ${exports.validAudioCodecs.join(', ')}, but got ${audioCodec}`);
160
+ }
161
+ _audioCodec = audioCodec;
162
+ },
163
+ getValue: ({ commandLine }) => {
164
+ if (commandLine[cliFlag]) {
165
+ const codec = commandLine[cliFlag];
166
+ if (!exports.validAudioCodecs.includes(commandLine[cliFlag])) {
167
+ throw new Error(`Audio codec must be one of the following: ${exports.validAudioCodecs.join(', ')}, but got ${codec}`);
168
+ }
169
+ return {
170
+ source: 'cli',
171
+ value: commandLine[cliFlag],
172
+ };
173
+ }
174
+ if (_audioCodec !== null) {
175
+ return {
176
+ source: 'config',
177
+ value: _audioCodec,
178
+ };
179
+ }
180
+ return {
181
+ source: 'default',
182
+ value: null,
183
+ };
184
+ },
185
+ 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.`,
186
+ docLink: 'https://www.remotion.dev/docs/encoding/#audio-codec',
187
+ name: 'Audio Codec',
188
+ ssrName,
189
+ type: 'aac',
190
+ };
@@ -9,7 +9,10 @@ export declare const enforceAudioOption: {
9
9
  commandLine: Record<string, unknown>;
10
10
  }) => {
11
11
  source: string;
12
- value: boolean;
12
+ value: true;
13
+ } | {
14
+ source: string;
15
+ value: false;
13
16
  };
14
17
  setConfig: (value: boolean) => void;
15
18
  };
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.enforceAudioOption = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const DEFAULT_ENFORCE_AUDIO_TRACK = true;
5
+ const DEFAULT_ENFORCE_AUDIO_TRACK = false;
6
6
  let enforceAudioTrackState = DEFAULT_ENFORCE_AUDIO_TRACK;
7
7
  const cliFlag = 'enforce-audio-track';
8
8
  exports.enforceAudioOption = {
@@ -13,10 +13,10 @@ exports.enforceAudioOption = {
13
13
  docLink: 'https://www.remotion.dev/docs/config#setenforceaudiotrack-',
14
14
  type: false,
15
15
  getValue: ({ commandLine }) => {
16
- if (commandLine[cliFlag] !== undefined) {
16
+ if (commandLine[cliFlag]) {
17
17
  return {
18
18
  source: 'cli',
19
- value: commandLine[cliFlag],
19
+ value: true,
20
20
  };
21
21
  }
22
22
  if (enforceAudioTrackState !== DEFAULT_ENFORCE_AUDIO_TRACK) {
@@ -12,7 +12,7 @@ const cliFlag = 'for-seamless-aac-concatenation';
12
12
  exports.forSeamlessAacConcatenationOption = {
13
13
  name: 'For seamless AAC concatenation',
14
14
  cliFlag,
15
- description: () => ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "If enabled, the audio is trimmed to the nearest AAC frame, which is required for seamless concatenation of AAC files. This is a requirement if you later want to combine multiple video snippets seamlessly." })),
15
+ description: () => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["If enabled, the audio is trimmed to the nearest AAC frame, which is required for seamless concatenation of AAC files. This is a requirement if you later want to combine multiple video snippets seamlessly.", (0, jsx_runtime_1.jsx)("br", {}), (0, jsx_runtime_1.jsx)("br", {}), " This option is used internally. There is currently no documentation yet for to concatenate the audio chunks."] })),
16
16
  docLink: 'https://remotion.dev/docs/renderer',
17
17
  getValue: ({ commandLine }) => {
18
18
  if (commandLine[cliFlag]) {