@remotion/renderer 4.0.530 → 4.0.531

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.
@@ -0,0 +1,6 @@
1
+ export declare const LIBFDK_AAC_LC_ENCODER_DELAY_IN_SAMPLES = 2048;
2
+ export declare const getAacPrimingInputArgs: ({ audioCodec, sampleRate, outputExtension, }: {
3
+ audioCodec: "aac" | "mp3" | "opus" | "pcm-16" | null;
4
+ sampleRate: number;
5
+ outputExtension: string | null;
6
+ }) => string[];
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAacPrimingInputArgs = exports.LIBFDK_AAC_LC_ENCODER_DELAY_IN_SAMPLES = void 0;
4
+ // libfdk_aac (AAC-LC) prepends 2048 samples of encoder delay ("priming") to
5
+ // its output. The audio is encoded to ADTS first (compressAudio, combineAudio),
6
+ // and ADTS cannot signal that delay, so stream-copying it into an MP4 or MOV
7
+ // produced an edit list starting at media time 0: players then played the
8
+ // priming as content and the audio was 2048 / sampleRate late (42.67ms at
9
+ // 48kHz). Shifting the ADTS input back by the delay makes the muxer write an
10
+ // edit list that skips the priming, like encoding straight to MP4 does.
11
+ exports.LIBFDK_AAC_LC_ENCODER_DELAY_IN_SAMPLES = 2048;
12
+ const getAacPrimingInputArgs = ({ audioCodec, sampleRate, outputExtension, }) => {
13
+ if (audioCodec !== 'aac') {
14
+ return [];
15
+ }
16
+ // Only containers with edit lists can carry the shift
17
+ const extension = outputExtension === null || outputExtension === void 0 ? void 0 : outputExtension.toLowerCase();
18
+ if (extension !== 'mp4' && extension !== 'mov') {
19
+ return [];
20
+ }
21
+ const delayInMicroseconds = Math.round((exports.LIBFDK_AAC_LC_ENCODER_DELAY_IN_SAMPLES / sampleRate) * 1000000);
22
+ return ['-itsoffset', `-${delayInMicroseconds}us`];
23
+ };
24
+ exports.getAacPrimingInputArgs = getAacPrimingInputArgs;
@@ -124,6 +124,8 @@ const internalCombineChunks = async ({ outputLocation: output, onProgress, codec
124
124
  cancelSignal,
125
125
  metadata,
126
126
  numberOfGifLoops,
127
+ audioCodec: resolvedAudioCodec,
128
+ sampleRate,
127
129
  });
128
130
  onProgress({ totalProgress: 1, frames: numberOfFrames });
129
131
  (0, node_fs_1.rmSync)(filelistDir, { recursive: true });
package/dist/crf.js CHANGED
@@ -60,6 +60,12 @@ const validateQualitySettings = ({ codec, crf, videoBitrate, encodingMaxRate, en
60
60
  if (encodingMaxRate && !encodingBufferSize) {
61
61
  throw new Error('"encodingMaxRate" can not be set without also setting "encodingBufferSize".');
62
62
  }
63
+ // libvpx and libaom-av1 reject -maxrate and -bufsize without -b:v
64
+ if ((encodingMaxRate || encodingBufferSize) &&
65
+ !videoBitrate &&
66
+ (codec === 'vp8' || codec === 'vp9' || codec === 'av1')) {
67
+ throw new Error(`The ${codec} codec needs "videoBitrate" when "encodingMaxRate" or "encodingBufferSize" is set.`);
68
+ }
63
69
  const bufSizeArray = encodingBufferSize
64
70
  ? ['-bufsize', encodingBufferSize]
65
71
  : [];
@@ -1974,7 +1974,7 @@ var encodingBufferSizeOption = {
1974
1974
  /* @__PURE__ */ jsx27("code", {
1975
1975
  children: "-bufsize"
1976
1976
  }),
1977
- " flag of FFmpeg. Should be used in conjunction with the encoding max rate flag."
1977
+ " flag of FFmpeg. Should be used in conjunction with the encoding max rate flag. With the VP8, VP9 and AV1 codecs, a video bitrate must also be set."
1978
1978
  ]
1979
1979
  }),
1980
1980
  ssrName: "encodingBufferSize",
@@ -2015,7 +2015,7 @@ var encodingMaxRateOption = {
2015
2015
  /* @__PURE__ */ jsx28("code", {
2016
2016
  children: "-maxrate"
2017
2017
  }),
2018
- " flag of FFmpeg. Should be used in conjunction with the encoding buffer size flag."
2018
+ " flag of FFmpeg. Should be used in conjunction with the encoding buffer size flag. With the VP8, VP9 and AV1 codecs, a video bitrate must also be set."
2019
2019
  ]
2020
2020
  }),
2021
2021
  ssrName: "encodingMaxRate",
@@ -21643,6 +21643,9 @@ var validateQualitySettings = ({
21643
21643
  if (encodingMaxRate && !encodingBufferSize) {
21644
21644
  throw new Error('"encodingMaxRate" can not be set without also setting "encodingBufferSize".');
21645
21645
  }
21646
+ if ((encodingMaxRate || encodingBufferSize) && !videoBitrate && (codec === "vp8" || codec === "vp9" || codec === "av1")) {
21647
+ throw new Error(`The ${codec} codec needs "videoBitrate" when "encodingMaxRate" or "encodingBufferSize" is set.`);
21648
+ }
21646
21649
  const bufSizeArray = encodingBufferSize ? ["-bufsize", encodingBufferSize] : [];
21647
21650
  const maxRateArray = encodingMaxRate ? ["-maxrate", encodingMaxRate] : [];
21648
21651
  if (videoBitrate) {
@@ -22388,6 +22391,24 @@ var validateSelectedCodecAndProResCombination = ({
22388
22391
  import { cpSync as cpSync2, promises as promises5, rmSync as rmSync4 } from "node:fs";
22389
22392
  import path29 from "node:path";
22390
22393
 
22394
+ // src/aac-priming.ts
22395
+ var LIBFDK_AAC_LC_ENCODER_DELAY_IN_SAMPLES = 2048;
22396
+ var getAacPrimingInputArgs = ({
22397
+ audioCodec,
22398
+ sampleRate,
22399
+ outputExtension
22400
+ }) => {
22401
+ if (audioCodec !== "aac") {
22402
+ return [];
22403
+ }
22404
+ const extension = outputExtension?.toLowerCase();
22405
+ if (extension !== "mp4" && extension !== "mov") {
22406
+ return [];
22407
+ }
22408
+ const delayInMicroseconds = Math.round(LIBFDK_AAC_LC_ENCODER_DELAY_IN_SAMPLES / sampleRate * 1e6);
22409
+ return ["-itsoffset", `-${delayInMicroseconds}us`];
22410
+ };
22411
+
22391
22412
  // src/convert-number-of-gif-loops-to-ffmpeg.ts
22392
22413
  var convertNumberOfGifLoopsToFfmpegSyntax = (loops) => {
22393
22414
  if (loops === null) {
@@ -23768,7 +23789,17 @@ var innerStitchFramesToVideo = async ({
23768
23789
  ["-i", assetsInfo.imageSequenceName],
23769
23790
  codec === "gif" ? ["-filter_complex", "split[v],palettegen,[v]paletteuse"] : null
23770
23791
  ],
23771
- audio && !separateAudioTo ? ["-i", audio, "-c:a", "copy"] : ["-an"],
23792
+ audio && !separateAudioTo ? [
23793
+ ...getAacPrimingInputArgs({
23794
+ audioCodec: resolvedAudioCodec,
23795
+ sampleRate,
23796
+ outputExtension
23797
+ }),
23798
+ "-i",
23799
+ audio,
23800
+ "-c:a",
23801
+ "copy"
23802
+ ] : ["-an"],
23772
23803
  numberOfGifLoops === null ? null : ["-loop", convertNumberOfGifLoopsToFfmpegSyntax(numberOfGifLoops)],
23773
23804
  ...generateFfmpegArgs({
23774
23805
  codec,
@@ -25633,7 +25664,9 @@ var muxVideoAndAudio = async ({
25633
25664
  fps,
25634
25665
  cancelSignal,
25635
25666
  metadata,
25636
- numberOfGifLoops
25667
+ numberOfGifLoops,
25668
+ audioCodec,
25669
+ sampleRate
25637
25670
  }) => {
25638
25671
  const startTime = Date.now();
25639
25672
  Log.verbose({ indent, logLevel }, "Muxing video and audio together");
@@ -25643,6 +25676,11 @@ var muxVideoAndAudio = async ({
25643
25676
  "-hide_banner",
25644
25677
  videoOutput ? "-i" : null,
25645
25678
  videoOutput,
25679
+ ...audioOutput ? getAacPrimingInputArgs({
25680
+ audioCodec,
25681
+ sampleRate,
25682
+ outputExtension
25683
+ }) : [],
25646
25684
  audioOutput ? "-i" : null,
25647
25685
  audioOutput,
25648
25686
  videoOutput ? "-c:v" : null,
@@ -25791,7 +25829,9 @@ var internalCombineChunks = async ({
25791
25829
  fps,
25792
25830
  cancelSignal,
25793
25831
  metadata,
25794
- numberOfGifLoops
25832
+ numberOfGifLoops,
25833
+ audioCodec: resolvedAudioCodec,
25834
+ sampleRate
25795
25835
  });
25796
25836
  onProgress({ totalProgress: 1, frames: numberOfFrames });
25797
25837
  rmSync6(filelistDir, { recursive: true });
@@ -1,5 +1,5 @@
1
1
  import type { CancelSignal } from './make-cancel-signal';
2
- export declare const muxVideoAndAudio: ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, metadata, numberOfGifLoops, }: {
2
+ export declare const muxVideoAndAudio: ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, metadata, numberOfGifLoops, audioCodec, sampleRate, }: {
3
3
  videoOutput: string | null;
4
4
  audioOutput: string | null;
5
5
  output: string;
@@ -11,4 +11,6 @@ export declare const muxVideoAndAudio: ({ videoOutput, audioOutput, output, inde
11
11
  cancelSignal: CancelSignal | undefined;
12
12
  metadata?: Record<string, string> | null | undefined;
13
13
  numberOfGifLoops: number | null;
14
+ audioCodec: "aac" | "mp3" | "opus" | "pcm-16" | null;
15
+ sampleRate: number;
14
16
  }) => Promise<void>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.muxVideoAndAudio = void 0;
4
+ const aac_priming_1 = require("./aac-priming");
4
5
  const call_ffmpeg_1 = require("./call-ffmpeg");
5
6
  const convert_number_of_gif_loops_to_ffmpeg_1 = require("./convert-number-of-gif-loops-to-ffmpeg");
6
7
  const get_extension_of_filename_1 = require("./get-extension-of-filename");
@@ -9,7 +10,7 @@ const logger_1 = require("./logger");
9
10
  const make_metadata_args_1 = require("./make-metadata-args");
10
11
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
11
12
  const truthy_1 = require("./truthy");
12
- const muxVideoAndAudio = async ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, metadata, numberOfGifLoops, }) => {
13
+ const muxVideoAndAudio = async ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, metadata, numberOfGifLoops, audioCodec, sampleRate, }) => {
13
14
  var _a;
14
15
  const startTime = Date.now();
15
16
  logger_1.Log.verbose({ indent, logLevel }, 'Muxing video and audio together');
@@ -21,6 +22,13 @@ const muxVideoAndAudio = async ({ videoOutput, audioOutput, output, indent, logL
21
22
  '-hide_banner',
22
23
  videoOutput ? '-i' : null,
23
24
  videoOutput,
25
+ ...(audioOutput
26
+ ? (0, aac_priming_1.getAacPrimingInputArgs)({
27
+ audioCodec,
28
+ sampleRate,
29
+ outputExtension,
30
+ })
31
+ : []),
24
32
  audioOutput ? '-i' : null,
25
33
  audioOutput,
26
34
  videoOutput ? '-c:v' : null,
@@ -15,7 +15,7 @@ exports.encodingBufferSizeOption = {
15
15
  cliFlag,
16
16
  description: () => (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: ["The value for the ",
17
17
  jsx_runtime_1.jsx("code", { children: "-bufsize" }),
18
- " flag of FFmpeg. Should be used in conjunction with the encoding max rate flag."] })),
18
+ " flag of FFmpeg. Should be used in conjunction with the encoding max rate flag. With the VP8, VP9 and AV1 codecs, a video bitrate must also be set."] })),
19
19
  ssrName: 'encodingBufferSize',
20
20
  docLink: 'https://www.remotion.dev/docs/renderer/render-media#encodingbuffersize',
21
21
  type: '',
@@ -9,7 +9,7 @@ exports.encodingMaxRateOption = {
9
9
  cliFlag,
10
10
  description: () => (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: ["The value for the ",
11
11
  jsx_runtime_1.jsx("code", { children: "-maxrate" }),
12
- " flag of FFmpeg. Should be used in conjunction with the encoding buffer size flag."] })),
12
+ " flag of FFmpeg. Should be used in conjunction with the encoding buffer size flag. With the VP8, VP9 and AV1 codecs, a video bitrate must also be set."] })),
13
13
  ssrName: 'encodingMaxRate',
14
14
  docLink: 'https://www.remotion.dev/docs/renderer/render-media#encodingmaxrate',
15
15
  type: '',
@@ -1,6 +1,6 @@
1
- export declare const sidebarTabsOption: {
1
+ export declare const experimentalClientSideRenderingOption: {
2
2
  name: string;
3
- cliFlag: "disable-sidebar-tabs";
3
+ cliFlag: "enable-experimental-client-side-rendering";
4
4
  description: () => import("react/jsx-runtime").JSX.Element;
5
5
  ssrName: null;
6
6
  docLink: string;
@@ -12,7 +12,5 @@ export declare const sidebarTabsOption: {
12
12
  source: string;
13
13
  };
14
14
  setConfig(value: boolean): void;
15
- getConfigValue: () => boolean | null;
16
- reset: () => void;
17
- id: "disable-sidebar-tabs";
15
+ id: "enable-experimental-client-side-rendering";
18
16
  };
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.experimentalClientSideRenderingOption = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ let experimentalClientSideRenderingEnabled = false;
6
+ const cliFlag = 'enable-experimental-client-side-rendering';
7
+ exports.experimentalClientSideRenderingOption = {
8
+ name: 'Enable Experimental Client-Side Rendering',
9
+ cliFlag,
10
+ description: () => (jsx_runtime_1.jsx(jsx_runtime_1.Fragment, { children: "Enable WIP client-side rendering in the Remotion Studio. See https://www.remotion.dev/docs/client-side-rendering/ for notes." })),
11
+ ssrName: null,
12
+ docLink: 'https://www.remotion.dev/docs/client-side-rendering',
13
+ type: false,
14
+ getValue: ({ commandLine }) => {
15
+ if (commandLine[cliFlag] !== null) {
16
+ return {
17
+ value: commandLine[cliFlag],
18
+ source: 'cli',
19
+ };
20
+ }
21
+ return {
22
+ value: experimentalClientSideRenderingEnabled,
23
+ source: 'config',
24
+ };
25
+ },
26
+ setConfig(value) {
27
+ experimentalClientSideRenderingEnabled = value;
28
+ },
29
+ id: cliFlag,
30
+ };
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.stitchFramesToVideo = exports.internalStitchFramesToVideo = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
+ const aac_priming_1 = require("./aac-priming");
9
10
  const download_map_1 = require("./assets/download-map");
10
11
  const call_ffmpeg_1 = require("./call-ffmpeg");
11
12
  const codec_1 = require("./codec");
@@ -224,7 +225,19 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec:
224
225
  ? ['-filter_complex', 'split[v],palettegen,[v]paletteuse']
225
226
  : null,
226
227
  ]),
227
- audio && !separateAudioTo ? ['-i', audio, '-c:a', 'copy'] : ['-an'],
228
+ audio && !separateAudioTo
229
+ ? [
230
+ ...(0, aac_priming_1.getAacPrimingInputArgs)({
231
+ audioCodec: resolvedAudioCodec,
232
+ sampleRate,
233
+ outputExtension,
234
+ }),
235
+ '-i',
236
+ audio,
237
+ '-c:a',
238
+ 'copy',
239
+ ]
240
+ : ['-an'],
228
241
  numberOfGifLoops === null
229
242
  ? null
230
243
  : ['-loop', (0, convert_number_of_gif_loops_to_ffmpeg_1.convertNumberOfGifLoopsToFfmpegSyntax)(numberOfGifLoops)],
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/renderer"
4
4
  },
5
5
  "name": "@remotion/renderer",
6
- "version": "4.0.530",
6
+ "version": "4.0.531",
7
7
  "description": "Render Remotion videos using Node.js or Bun",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "execa": "5.1.1",
25
- "remotion": "4.0.530",
26
- "@remotion/streaming": "4.0.530",
25
+ "remotion": "4.0.531",
26
+ "@remotion/streaming": "4.0.531",
27
27
  "source-map": "0.8.0",
28
28
  "ws": "8.21.0",
29
- "@remotion/licensing": "4.0.530"
29
+ "@remotion/licensing": "4.0.531"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "react": ">=16.8.0",
@@ -40,19 +40,19 @@
40
40
  "react-dom": "19.2.3",
41
41
  "@typescript/native-preview": "7.0.0-dev.20260217.1",
42
42
  "@types/ws": "8.5.10",
43
- "@remotion/example-videos": "4.0.530",
44
- "@remotion/eslint-config-internal": "4.0.530",
43
+ "@remotion/example-videos": "4.0.531",
44
+ "@remotion/eslint-config-internal": "4.0.531",
45
45
  "eslint": "9.19.0",
46
46
  "@types/node": "20.12.14"
47
47
  },
48
48
  "optionalDependencies": {
49
- "@remotion/compositor-darwin-arm64": "4.0.530",
50
- "@remotion/compositor-darwin-x64": "4.0.530",
51
- "@remotion/compositor-linux-arm64-gnu": "4.0.530",
52
- "@remotion/compositor-linux-arm64-musl": "4.0.530",
53
- "@remotion/compositor-linux-x64-gnu": "4.0.530",
54
- "@remotion/compositor-linux-x64-musl": "4.0.530",
55
- "@remotion/compositor-win32-x64-msvc": "4.0.530"
49
+ "@remotion/compositor-darwin-arm64": "4.0.531",
50
+ "@remotion/compositor-darwin-x64": "4.0.531",
51
+ "@remotion/compositor-linux-arm64-gnu": "4.0.531",
52
+ "@remotion/compositor-linux-arm64-musl": "4.0.531",
53
+ "@remotion/compositor-linux-x64-gnu": "4.0.531",
54
+ "@remotion/compositor-linux-x64-musl": "4.0.531",
55
+ "@remotion/compositor-win32-x64-msvc": "4.0.531"
56
56
  },
57
57
  "keywords": [
58
58
  "remotion",
@@ -1,38 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sidebarTabsOption = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- let sidebarTabsEnabled = true;
6
- let configuredSidebarTabsEnabled = null;
7
- const cliFlag = 'disable-sidebar-tabs';
8
- exports.sidebarTabsOption = {
9
- name: 'Disable or enable Studio sidebar tabs',
10
- cliFlag,
11
- description: () => (jsx_runtime_1.jsx(jsx_runtime_1.Fragment, { children: "Enable or disable the tabs at the top of the Studio sidebars." })),
12
- ssrName: null,
13
- docLink: 'https://www.remotion.dev/docs/config#setsidebartabsenabled',
14
- type: false,
15
- getValue: ({ commandLine }) => {
16
- if (commandLine[cliFlag] !== undefined && commandLine[cliFlag] !== null) {
17
- sidebarTabsEnabled = commandLine[cliFlag] === false;
18
- return {
19
- value: sidebarTabsEnabled,
20
- source: 'cli',
21
- };
22
- }
23
- return {
24
- value: sidebarTabsEnabled,
25
- source: 'config',
26
- };
27
- },
28
- setConfig(value) {
29
- sidebarTabsEnabled = value;
30
- configuredSidebarTabsEnabled = value;
31
- },
32
- getConfigValue: () => configuredSidebarTabsEnabled,
33
- reset: () => {
34
- sidebarTabsEnabled = true;
35
- configuredSidebarTabsEnabled = null;
36
- },
37
- id: cliFlag,
38
- };