@remotion/renderer 4.0.125 → 4.0.127

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 (65) hide show
  1. package/dist/assets/convert-assets-to-file-urls.d.ts +2 -1
  2. package/dist/assets/convert-assets-to-file-urls.js +6 -4
  3. package/dist/assets/download-map.d.ts +6 -2
  4. package/dist/assets/ffmpeg-volume-expression.js +7 -3
  5. package/dist/calculate-ffmpeg-filters.d.ts +4 -2
  6. package/dist/calculate-ffmpeg-filters.js +10 -17
  7. package/dist/check-apple-silicon.d.ts +1 -3
  8. package/dist/check-apple-silicon.js +2 -32
  9. package/dist/client.d.ts +124 -88
  10. package/dist/combine-audio.js +6 -6
  11. package/dist/combine-videos.js +1 -0
  12. package/dist/compress-audio.d.ts +2 -2
  13. package/dist/compress-audio.js +4 -7
  14. package/dist/create-audio.d.ts +11 -4
  15. package/dist/create-audio.js +7 -5
  16. package/dist/create-combined-video.d.ts +3 -2
  17. package/dist/create-combined-video.js +7 -1
  18. package/dist/create-ffmpeg-complex-filter.d.ts +1 -4
  19. package/dist/create-silent-audio.d.ts +2 -2
  20. package/dist/create-silent-audio.js +2 -2
  21. package/dist/does-have-m2-bug.d.ts +3 -0
  22. package/dist/does-have-m2-bug.js +12 -0
  23. package/dist/get-extension-from-audio-codec.d.ts +2 -2
  24. package/dist/get-extension-from-codec.d.ts +2 -2
  25. package/dist/get-extra-frames-to-capture.d.ts +13 -0
  26. package/dist/get-extra-frames-to-capture.js +63 -0
  27. package/dist/index.d.ts +40 -40
  28. package/dist/logger.js +3 -1
  29. package/dist/merge-audio-track.d.ts +1 -1
  30. package/dist/merge-audio-track.js +7 -11
  31. package/dist/options/audio-codec.d.ts +5 -5
  32. package/dist/options/index.d.ts +44 -8
  33. package/dist/options/index.js +4 -0
  34. package/dist/options/options-map.d.ts +26 -26
  35. package/dist/options/options-map.js +1 -1
  36. package/dist/options/prores-profile.d.ts +0 -0
  37. package/dist/options/prores-profile.js +1 -0
  38. package/dist/options/{separate-audio-to.d.ts → public-dir.d.ts} +5 -5
  39. package/dist/options/public-dir.js +37 -0
  40. package/dist/options/public-path.d.ts +18 -0
  41. package/dist/options/public-path.js +37 -0
  42. package/dist/options/video-codec.d.ts +1 -1
  43. package/dist/preprocess-audio-track.d.ts +3 -1
  44. package/dist/preprocess-audio-track.js +7 -7
  45. package/dist/pure.d.ts +3 -3
  46. package/dist/render-frames.d.ts +6 -0
  47. package/dist/render-frames.js +70 -29
  48. package/dist/render-media.d.ts +1 -0
  49. package/dist/render-media.js +5 -2
  50. package/dist/stitch-frames-to-video.d.ts +1 -1
  51. package/dist/stitch-frames-to-video.js +9 -9
  52. package/dist/stringify-ffmpeg-filter.d.ts +3 -2
  53. package/dist/stringify-ffmpeg-filter.js +56 -14
  54. package/dist/take-frame-and-compose.d.ts +1 -0
  55. package/dist/validate-output-filename.d.ts +1 -1
  56. package/dist/x264-preset.d.ts +15 -0
  57. package/dist/x264-preset.js +26 -1
  58. package/package.json +9 -9
  59. package/dist/can-concatenate-seamlessly.d.ts +0 -3
  60. package/dist/can-concatenate-seamlessly.js +0 -7
  61. package/dist/options/separate-audio-to.js +0 -31
  62. package/dist/should-seamless.d.ts +0 -3
  63. package/dist/should-seamless.js +0 -7
  64. package/dist/supported-audio-codecs.d.ts +0 -13
  65. package/dist/supported-audio-codecs.js +0 -16
@@ -123,17 +123,17 @@ export declare const optionsMap: {
123
123
  description: () => import("react/jsx-runtime").JSX.Element;
124
124
  ssrName: string;
125
125
  docLink: string;
126
- type: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
126
+ type: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
127
127
  getValue: ({ commandLine }: {
128
128
  commandLine: Record<string, unknown>;
129
129
  }, { compositionCodec, configFile, downloadName, outName, uiCodec, }: {
130
130
  outName: string | null;
131
131
  downloadName: string | null;
132
- configFile: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif" | null;
133
- uiCodec: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif" | null;
134
- compositionCodec: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif" | null;
132
+ configFile: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif" | null;
133
+ uiCodec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif" | null;
134
+ compositionCodec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif" | null;
135
135
  }) => {
136
- value: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
136
+ value: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
137
137
  source: string;
138
138
  };
139
139
  setConfig: (newCodec: import("..").CodecOrUndefined) => void;
@@ -287,12 +287,12 @@ export declare const optionsMap: {
287
287
  };
288
288
  readonly audioCodec: {
289
289
  cliFlag: "audio-codec";
290
- setConfig: (audioCodec: "pcm-16" | "aac" | "mp3" | "opus" | null) => void;
290
+ setConfig: (audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null) => void;
291
291
  getValue: ({ commandLine }: {
292
292
  commandLine: Record<string, unknown>;
293
293
  }) => {
294
294
  source: string;
295
- value: "pcm-16" | "aac" | "mp3" | "opus";
295
+ value: "mp3" | "aac" | "pcm-16" | "opus";
296
296
  } | {
297
297
  source: string;
298
298
  value: null;
@@ -301,28 +301,10 @@ export declare const optionsMap: {
301
301
  docLink: string;
302
302
  name: string;
303
303
  ssrName: "audioCodec";
304
- type: "pcm-16" | "aac" | "mp3" | "opus";
304
+ type: "mp3" | "aac" | "pcm-16" | "opus";
305
305
  };
306
306
  };
307
307
  readonly stitchFramesToVideo: {
308
- readonly forSeamlessAacConcatenation: {
309
- name: string;
310
- cliFlag: "for-seamless-aac-concatenation";
311
- description: () => import("react/jsx-runtime").JSX.Element;
312
- docLink: string;
313
- getValue: ({ commandLine }: {
314
- commandLine: Record<string, unknown>;
315
- }) => {
316
- source: string;
317
- value: true;
318
- } | {
319
- source: string;
320
- value: false;
321
- };
322
- setConfig: (value: boolean) => void;
323
- ssrName: string;
324
- type: boolean;
325
- };
326
308
  readonly separateAudioTo: {
327
309
  cliFlag: string;
328
310
  description: () => string;
@@ -553,6 +535,24 @@ export declare const optionsMap: {
553
535
  };
554
536
  };
555
537
  readonly renderFrames: {
538
+ readonly forSeamlessAacConcatenation: {
539
+ name: string;
540
+ cliFlag: "for-seamless-aac-concatenation";
541
+ description: () => import("react/jsx-runtime").JSX.Element;
542
+ docLink: string;
543
+ getValue: ({ commandLine }: {
544
+ commandLine: Record<string, unknown>;
545
+ }) => {
546
+ source: string;
547
+ value: true;
548
+ } | {
549
+ source: string;
550
+ value: false;
551
+ };
552
+ setConfig: (value: boolean) => void;
553
+ ssrName: string;
554
+ type: boolean;
555
+ };
556
556
  readonly offthreadVideoCacheSizeInBytes: {
557
557
  name: string;
558
558
  cliFlag: "offthreadvideo-cache-size-in-bytes";
@@ -46,7 +46,6 @@ exports.optionsMap = {
46
46
  audioCodec: audio_codec_1.audioCodecOption,
47
47
  },
48
48
  stitchFramesToVideo: {
49
- forSeamlessAacConcatenation: for_seamless_aac_concatenation_1.forSeamlessAacConcatenationOption,
50
49
  separateAudioTo: separate_audio_1.separateAudioOption,
51
50
  },
52
51
  renderStill: {
@@ -69,6 +68,7 @@ exports.optionsMap = {
69
68
  binariesDirectory: binaries_directory_1.binariesDirectoryOption,
70
69
  },
71
70
  renderFrames: {
71
+ forSeamlessAacConcatenation: for_seamless_aac_concatenation_1.forSeamlessAacConcatenationOption,
72
72
  offthreadVideoCacheSizeInBytes: offthreadvideo_cache_size_1.offthreadVideoCacheSizeInBytesOption,
73
73
  jpegQuality: jpeg_quality_1.jpegQualityOption,
74
74
  logLevel: log_level_1.logLevelOption,
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -1,6 +1,8 @@
1
- export declare const separateAudioOption: {
2
- cliFlag: string;
1
+ export declare const publicDirOption: {
2
+ name: string;
3
+ cliFlag: "public-dir";
3
4
  description: () => import("react/jsx-runtime").JSX.Element;
5
+ ssrName: "publicDir";
4
6
  docLink: string;
5
7
  getValue: ({ commandLine }: {
6
8
  commandLine: Record<string, unknown>;
@@ -11,8 +13,6 @@ export declare const separateAudioOption: {
11
13
  source: string;
12
14
  value: null;
13
15
  };
14
- name: string;
15
- setConfig: () => never;
16
- ssrName: string;
16
+ setConfig: (value: string | null) => void;
17
17
  type: string | null;
18
18
  };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.publicDirOption = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const cliFlag = 'public-dir';
6
+ let currentPublicDir = null;
7
+ exports.publicDirOption = {
8
+ name: 'Public Directory',
9
+ cliFlag,
10
+ description: () => {
11
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Define the location of the", ' ', (0, jsx_runtime_1.jsx)("a", { href: "/docs/terminology/public-dir", children: (0, jsx_runtime_1.jsx)("code", { children: "public/ directory" }) }), ". If not defined, Remotion will assume the location is the `public` folder in your Remotion root."] }));
12
+ },
13
+ ssrName: 'publicDir',
14
+ docLink: 'https://www.remotion.dev/docs/terminology/public-dir',
15
+ getValue: ({ commandLine }) => {
16
+ if (commandLine[cliFlag] !== undefined) {
17
+ return {
18
+ source: 'cli',
19
+ value: commandLine[cliFlag],
20
+ };
21
+ }
22
+ if (currentPublicDir !== null) {
23
+ return {
24
+ source: 'config',
25
+ value: currentPublicDir,
26
+ };
27
+ }
28
+ return {
29
+ source: 'default',
30
+ value: null,
31
+ };
32
+ },
33
+ setConfig: (value) => {
34
+ currentPublicDir = value;
35
+ },
36
+ type: '',
37
+ };
@@ -0,0 +1,18 @@
1
+ export declare const publicPathOption: {
2
+ name: string;
3
+ cliFlag: "public-path";
4
+ description: () => import("react/jsx-runtime").JSX.Element;
5
+ ssrName: "publicPath";
6
+ docLink: string;
7
+ getValue: ({ commandLine }: {
8
+ commandLine: Record<string, unknown>;
9
+ }) => {
10
+ source: string;
11
+ value: string;
12
+ } | {
13
+ source: string;
14
+ value: null;
15
+ };
16
+ setConfig: (value: string | null) => void;
17
+ type: string | null;
18
+ };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.publicPathOption = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const cliFlag = 'public-path';
6
+ let currentPublicPath = null;
7
+ exports.publicPathOption = {
8
+ name: 'Public Path',
9
+ cliFlag,
10
+ description: () => {
11
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["The path of the URL where the bundle is going to be hosted. By default it is ", (0, jsx_runtime_1.jsx)("code", { children: "/" }), ", meaning that the bundle is going to be hosted at the root of the domain (e.g. ", (0, jsx_runtime_1.jsx)("code", { children: "https://localhost:3000/" }), "). If you are deploying to a subdirectory (e.g. ", (0, jsx_runtime_1.jsx)("code", { children: "/sites/my-site/" }), "), you should set this to the subdirectory."] }));
12
+ },
13
+ ssrName: 'publicPath',
14
+ docLink: 'https://www.remotion.dev/docs/renderer',
15
+ getValue: ({ commandLine }) => {
16
+ if (commandLine[cliFlag] !== undefined) {
17
+ return {
18
+ source: 'cli',
19
+ value: commandLine[cliFlag],
20
+ };
21
+ }
22
+ if (currentPublicPath !== null) {
23
+ return {
24
+ source: 'config',
25
+ value: currentPublicPath,
26
+ };
27
+ }
28
+ return {
29
+ source: 'default',
30
+ value: null,
31
+ };
32
+ },
33
+ setConfig: (value) => {
34
+ currentPublicPath = value;
35
+ },
36
+ type: '',
37
+ };
@@ -6,7 +6,7 @@ export declare const videoCodecOption: {
6
6
  description: () => import("react/jsx-runtime").JSX.Element;
7
7
  ssrName: string;
8
8
  docLink: string;
9
- type: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
9
+ type: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif";
10
10
  getValue: ({ commandLine }: {
11
11
  commandLine: Record<string, unknown>;
12
12
  }, { compositionCodec, configFile, downloadName, outName, uiCodec, }: {
@@ -6,13 +6,15 @@ import type { ProcessedTrack } from './stringify-ffmpeg-filter';
6
6
  type Options = {
7
7
  outName: string;
8
8
  asset: MediaAsset;
9
- expectedFrames: number;
10
9
  fps: number;
11
10
  downloadMap: DownloadMap;
12
11
  indent: boolean;
13
12
  logLevel: LogLevel;
14
13
  binariesDirectory: string | null;
15
14
  cancelSignal: CancelSignal | undefined;
15
+ chunkLengthInSeconds: number;
16
+ trimLeftOffset: number;
17
+ trimRightOffset: number;
16
18
  forSeamlessAacConcatenation: boolean;
17
19
  onProgress: (progress: number) => void;
18
20
  };
@@ -10,7 +10,7 @@ const p_limit_1 = require("./p-limit");
10
10
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
11
11
  const resolve_asset_src_1 = require("./resolve-asset-src");
12
12
  const sample_rate_1 = require("./sample-rate");
13
- const preprocessAudioTrackUnlimited = async ({ outName, asset, expectedFrames, fps, downloadMap, indent, logLevel, binariesDirectory, cancelSignal, forSeamlessAacConcatenation, onProgress, }) => {
13
+ const preprocessAudioTrackUnlimited = async ({ outName, asset, fps, downloadMap, indent, logLevel, binariesDirectory, cancelSignal, onProgress, chunkLengthInSeconds, trimLeftOffset, trimRightOffset, forSeamlessAacConcatenation, }) => {
14
14
  var _a;
15
15
  const { channels, duration } = await (0, get_audio_channels_1.getAudioChannelsAndDuration)({
16
16
  downloadMap,
@@ -22,10 +22,12 @@ const preprocessAudioTrackUnlimited = async ({ outName, asset, expectedFrames, f
22
22
  });
23
23
  const filter = (0, calculate_ffmpeg_filters_1.calculateFfmpegFilter)({
24
24
  asset,
25
- durationInFrames: expectedFrames,
26
25
  fps,
27
26
  channels,
28
27
  assetDuration: duration,
28
+ chunkLengthInSeconds,
29
+ trimLeftOffset,
30
+ trimRightOffset,
29
31
  forSeamlessAacConcatenation,
30
32
  });
31
33
  if (filter === null) {
@@ -33,6 +35,7 @@ const preprocessAudioTrackUnlimited = async ({ outName, asset, expectedFrames, f
33
35
  }
34
36
  const { cleanup, file } = await (0, ffmpeg_filter_file_1.makeFfmpegFilterFile)(filter, downloadMap);
35
37
  const args = [
38
+ ['-hide_banner'],
36
39
  ['-i', (0, resolve_asset_src_1.resolveAssetSrc)(asset.src)],
37
40
  ['-ac', '2'],
38
41
  ['-filter_script:a', file],
@@ -53,11 +56,8 @@ const preprocessAudioTrackUnlimited = async ({ outName, asset, expectedFrames, f
53
56
  (_a = task.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
54
57
  const utf8 = data.toString('utf8');
55
58
  const parsed = (0, parse_ffmpeg_progress_1.parseFfmpegProgress)(utf8, fps);
56
- if (parsed === undefined) {
57
- logger_1.Log.verbose({ indent, logLevel }, utf8);
58
- }
59
- else {
60
- onProgress(parsed / expectedFrames);
59
+ if (parsed !== undefined) {
60
+ onProgress(parsed / (chunkLengthInSeconds * fps));
61
61
  }
62
62
  });
63
63
  await task;
package/dist/pure.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export declare const NoReactAPIs: {
2
2
  wrapWithErrorHandling: <A extends unknown[], R>(fn: (...args: A) => Promise<R>) => (...args: A) => Promise<R>;
3
3
  getExtensionOfFilename: (filename: string | null) => string | null;
4
- getFileExtensionFromCodec: <T extends "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif">(codec: T, audioCodec: "pcm-16" | "aac" | "mp3" | "opus" | null) => import("./file-extensions").FileExtension;
5
- validateOutputFilename: <T_1 extends "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif">({ codec, audioCodecSetting, extension, preferLossless, separateAudioTo, }: {
4
+ 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;
5
+ validateOutputFilename: <T_1 extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif">({ codec, audioCodecSetting, extension, preferLossless, separateAudioTo, }: {
6
6
  codec: T_1;
7
- audioCodecSetting: "pcm-16" | "aac" | "mp3" | "opus" | null;
7
+ audioCodecSetting: "mp3" | "aac" | "pcm-16" | "opus" | null;
8
8
  extension: string;
9
9
  preferLossless: boolean;
10
10
  separateAudioTo: string | null;
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import type { TAsset } from 'remotion';
2
3
  import type { VideoConfig } from 'remotion/no-react';
3
4
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
4
5
  import type { BrowserExecutable } from './browser-executable';
@@ -39,7 +40,12 @@ export type InternalRenderFramesOptions = {
39
40
  serializedInputPropsWithCustomSchema: string;
40
41
  serializedResolvedPropsWithCustomSchema: string;
41
42
  parallelEncodingEnabled: boolean;
43
+ compositionStart: number;
42
44
  } & ToOptions<typeof optionsMap.renderFrames>;
45
+ export type FrameAndAssets = {
46
+ frame: number;
47
+ assets: TAsset[];
48
+ };
43
49
  export type RenderFramesOptions = {
44
50
  onStart: (data: OnStartData) => void;
45
51
  onFrameUpdate: (framesRendered: number, frameIndex: number, timeToRenderInMilliseconds: number) => void;
@@ -18,6 +18,7 @@ const handle_javascript_exception_1 = require("./error-handling/handle-javascrip
18
18
  const find_closest_package_json_1 = require("./find-closest-package-json");
19
19
  const get_concurrency_1 = require("./get-concurrency");
20
20
  const get_duration_from_frame_range_1 = require("./get-duration-from-frame-range");
21
+ const get_extra_frames_to_capture_1 = require("./get-extra-frames-to-capture");
21
22
  const get_frame_padded_index_1 = require("./get-frame-padded-index");
22
23
  const get_frame_to_render_1 = require("./get-frame-to-render");
23
24
  const jpeg_quality_1 = require("./jpeg-quality");
@@ -37,7 +38,7 @@ const validate_1 = require("./validate");
37
38
  const validate_scale_1 = require("./validate-scale");
38
39
  const wrap_with_error_handling_1 = require("./wrap-with-error-handling");
39
40
  const MAX_RETRIES_PER_FRAME = 1;
40
- const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serializedInputPropsWithCustomSchema, serializedResolvedPropsWithCustomSchema, jpegQuality, imageFormat, frameRange, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualConcurrency, everyNthFrame, proxyPort, cancelSignal, downloadMap, muted, makeBrowser, browserReplacer, compositor, sourceMapGetter, logLevel, indent, parallelEncodingEnabled, }) => {
41
+ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serializedInputPropsWithCustomSchema, serializedResolvedPropsWithCustomSchema, jpegQuality, imageFormat, frameRange, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualConcurrency, everyNthFrame, proxyPort, cancelSignal, downloadMap, muted, makeBrowser, browserReplacer, compositor, sourceMapGetter, logLevel, indent, parallelEncodingEnabled, compositionStart, forSeamlessAacConcatenation, }) => {
41
42
  if (outputDir) {
42
43
  if (!node_fs_1.default.existsSync(outputDir)) {
43
44
  node_fs_1.default.mkdirSync(outputDir, {
@@ -47,6 +48,12 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
47
48
  }
48
49
  const downloadPromises = [];
49
50
  const realFrameRange = (0, get_frame_to_render_1.getRealFrameRange)(composition.durationInFrames, frameRange);
51
+ const { extraFramesToCaptureAssets, chunkLengthInSeconds, trimLeftOffset, trimRightOffset, } = (0, get_extra_frames_to_capture_1.getExtraFramesToCapture)({
52
+ fps: composition.fps,
53
+ compositionStart,
54
+ realFrameRange,
55
+ forSeamlessAacConcatenation,
56
+ });
50
57
  const framesToRender = (0, get_duration_from_frame_range_1.getFramesToRender)(realFrameRange, everyNthFrame);
51
58
  const lastFrame = framesToRender[framesToRender.length - 1];
52
59
  const makePage = async (context) => {
@@ -136,13 +143,13 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
136
143
  frameCount: framesToRender.length,
137
144
  parallelEncoding: parallelEncodingEnabled,
138
145
  });
139
- const assets = new Array(framesToRender.length).fill(undefined);
146
+ const assets = [];
140
147
  let stopped = false;
141
148
  cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
142
149
  stopped = true;
143
150
  });
144
151
  const frameDir = outputDir !== null && outputDir !== void 0 ? outputDir : downloadMap.compositingDir;
145
- const renderFrameWithOptionToReject = async ({ frame, index, reject, width, height, compId, }) => {
152
+ const renderFrameWithOptionToReject = async ({ frame, index, reject, width, height, compId, assetsOnly, }) => {
146
153
  const pool = await poolPromise;
147
154
  const freePage = await pool.acquire();
148
155
  if (stopped) {
@@ -182,15 +189,17 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
182
189
  frame,
183
190
  freePage,
184
191
  height,
185
- imageFormat,
186
- output: node_path_1.default.join(frameDir, (0, get_frame_padded_index_1.getFrameOutputFileName)({
187
- frame,
188
- imageFormat,
189
- index,
190
- countType,
191
- lastFrame,
192
- totalFrames: framesToRender.length,
193
- })),
192
+ imageFormat: assetsOnly ? 'none' : imageFormat,
193
+ output: index === null
194
+ ? null
195
+ : node_path_1.default.join(frameDir, (0, get_frame_padded_index_1.getFrameOutputFileName)({
196
+ frame,
197
+ imageFormat,
198
+ index,
199
+ countType,
200
+ lastFrame,
201
+ totalFrames: framesToRender.length,
202
+ })),
194
203
  jpegQuality,
195
204
  width,
196
205
  scale,
@@ -199,15 +208,21 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
199
208
  compositor,
200
209
  timeoutInMilliseconds,
201
210
  });
202
- if (onFrameBuffer) {
211
+ if (onFrameBuffer && !assetsOnly) {
203
212
  if (!buffer) {
204
213
  throw new Error('unexpected null buffer');
205
214
  }
206
215
  onFrameBuffer(buffer, frame);
207
216
  }
208
217
  (0, perf_1.stopPerfMeasure)(id);
209
- const compressedAssets = collectedAssets.map((asset) => (0, compress_assets_1.compressAsset)(assets.filter(truthy_1.truthy).flat(1), asset));
210
- assets[index] = compressedAssets;
218
+ const compressedAssets = collectedAssets.map((asset) => (0, compress_assets_1.compressAsset)(assets
219
+ .filter(truthy_1.truthy)
220
+ .map((a) => a.assets)
221
+ .flat(2), asset));
222
+ assets.push({
223
+ assets: compressedAssets,
224
+ frame,
225
+ });
211
226
  compressedAssets.forEach((renderAsset) => {
212
227
  (0, download_and_map_assets_to_file_1.downloadAndMapAssetsToFileUrl)({
213
228
  renderAsset,
@@ -219,13 +234,15 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
219
234
  onError(new Error(`Error while downloading asset: ${err.stack}`));
220
235
  });
221
236
  });
222
- framesRendered++;
223
- onFrameUpdate === null || onFrameUpdate === void 0 ? void 0 : onFrameUpdate(framesRendered, frame, perf_hooks_1.performance.now() - startTime);
237
+ if (!assetsOnly) {
238
+ framesRendered++;
239
+ onFrameUpdate === null || onFrameUpdate === void 0 ? void 0 : onFrameUpdate(framesRendered, frame, perf_hooks_1.performance.now() - startTime);
240
+ }
224
241
  cleanupPageError();
225
242
  freePage.off('error', errorCallbackOnFrame);
226
243
  pool.release(freePage);
227
244
  };
228
- const renderFrame = (frame, index) => {
245
+ const renderFrame = (frame, index, assetsOnly) => {
229
246
  return new Promise((resolve, reject) => {
230
247
  renderFrameWithOptionToReject({
231
248
  frame,
@@ -234,6 +251,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
234
251
  width: composition.width,
235
252
  height: composition.height,
236
253
  compId: composition.id,
254
+ assetsOnly,
237
255
  })
238
256
  .then(() => {
239
257
  resolve();
@@ -243,10 +261,10 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
243
261
  });
244
262
  });
245
263
  };
246
- const renderFrameAndRetryTargetClose = async ({ frame, index, retriesLeft, attempt, }) => {
264
+ const renderFrameAndRetryTargetClose = async ({ frame, index, retriesLeft, attempt, assetsOnly, }) => {
247
265
  try {
248
266
  await Promise.race([
249
- renderFrame(frame, index),
267
+ renderFrame(frame, index, assetsOnly),
250
268
  new Promise((_, reject) => {
251
269
  cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
252
270
  reject(new Error(make_cancel_signal_1.cancelErrorMessages.renderFrames));
@@ -284,23 +302,42 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
284
302
  index,
285
303
  retriesLeft: retriesLeft - 1,
286
304
  attempt: attempt + 1,
305
+ assetsOnly,
287
306
  });
288
307
  }
289
308
  };
290
- const progress = Promise.all(framesToRender.map((frame, index) => renderFrameAndRetryTargetClose({
291
- frame,
292
- index,
293
- retriesLeft: MAX_RETRIES_PER_FRAME,
294
- attempt: 1,
295
- })));
296
- const happyPath = progress.then(() => {
309
+ const extraFrames = Promise.all(extraFramesToCaptureAssets.map((frame) => {
310
+ return renderFrameAndRetryTargetClose({
311
+ frame,
312
+ index: null,
313
+ retriesLeft: MAX_RETRIES_PER_FRAME,
314
+ attempt: 1,
315
+ assetsOnly: true,
316
+ });
317
+ }));
318
+ const mainFrames = Promise.all(framesToRender.map((frame, index) => {
319
+ return renderFrameAndRetryTargetClose({
320
+ frame,
321
+ index,
322
+ retriesLeft: MAX_RETRIES_PER_FRAME,
323
+ attempt: 1,
324
+ assetsOnly: false,
325
+ });
326
+ }));
327
+ const happyPath = Promise.all([extraFrames, mainFrames]).then(() => {
297
328
  const firstFrameIndex = countType === 'from-zero' ? 0 : framesToRender[0];
298
329
  const returnValue = {
299
330
  assetsInfo: {
300
- assets,
331
+ assets: assets.sort((a, b) => {
332
+ return a.frame - b.frame;
333
+ }),
301
334
  imageSequenceName: node_path_1.default.join(frameDir, `element-%0${filePadLength}d.${imageFormat}`),
302
335
  firstFrameIndex,
303
336
  downloadMap,
337
+ trimLeftOffset,
338
+ trimRightOffset,
339
+ chunkLengthInSeconds,
340
+ forSeamlessAacConcatenation,
304
341
  },
305
342
  frameCount: framesToRender.length,
306
343
  };
@@ -310,7 +347,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
310
347
  await Promise.all(downloadPromises);
311
348
  return result;
312
349
  };
313
- const internalRenderFramesRaw = ({ browserExecutable, cancelSignal, chromiumOptions, composition, concurrency, envVariables, everyNthFrame, frameRange, imageFormat, indent, jpegQuality, muted, onBrowserLog, onDownload, onFrameBuffer, onFrameUpdate, onStart, outputDir, port, puppeteerInstance, scale, server, timeoutInMilliseconds, logLevel, webpackBundleOrServeUrl, serializedInputPropsWithCustomSchema, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, parallelEncodingEnabled, binariesDirectory, }) => {
350
+ const internalRenderFramesRaw = ({ browserExecutable, cancelSignal, chromiumOptions, composition, concurrency, envVariables, everyNthFrame, frameRange, imageFormat, indent, jpegQuality, muted, onBrowserLog, onDownload, onFrameBuffer, onFrameUpdate, onStart, outputDir, port, puppeteerInstance, scale, server, timeoutInMilliseconds, logLevel, webpackBundleOrServeUrl, serializedInputPropsWithCustomSchema, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, parallelEncodingEnabled, binariesDirectory, forSeamlessAacConcatenation, compositionStart, }) => {
314
351
  (0, validate_1.validateDimension)(composition.height, 'height', 'in the `config` object passed to `renderFrames()`');
315
352
  (0, validate_1.validateDimension)(composition.width, 'width', 'in the `config` object passed to `renderFrames()`');
316
353
  (0, validate_1.validateFps)(composition.fps, 'in the `config` object of `renderFrames()`', false);
@@ -401,6 +438,8 @@ const internalRenderFramesRaw = ({ browserExecutable, cancelSignal, chromiumOpti
401
438
  serializedResolvedPropsWithCustomSchema,
402
439
  parallelEncodingEnabled,
403
440
  binariesDirectory,
441
+ forSeamlessAacConcatenation,
442
+ compositionStart,
404
443
  });
405
444
  }),
406
445
  ])
@@ -493,6 +532,8 @@ const renderFrames = (options) => {
493
532
  offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes !== null && offthreadVideoCacheSizeInBytes !== void 0 ? offthreadVideoCacheSizeInBytes : null,
494
533
  parallelEncodingEnabled: false,
495
534
  binariesDirectory: binariesDirectory !== null && binariesDirectory !== void 0 ? binariesDirectory : null,
535
+ compositionStart: 0,
536
+ forSeamlessAacConcatenation: false,
496
537
  });
497
538
  };
498
539
  exports.renderFrames = renderFrames;
@@ -65,6 +65,7 @@ export type InternalRenderMediaOptions = {
65
65
  concurrency: number | string | null;
66
66
  finishRenderProgress: () => void;
67
67
  binariesDirectory: string | null;
68
+ compositionStart: number;
68
69
  } & MoreRenderMediaOptions;
69
70
  type Prettify<T> = {
70
71
  [K in keyof T]: T[K];
@@ -47,7 +47,7 @@ const validate_scale_1 = require("./validate-scale");
47
47
  const validate_videobitrate_1 = require("./validate-videobitrate");
48
48
  const wrap_with_error_handling_1 = require("./wrap-with-error-handling");
49
49
  const SLOWEST_FRAME_COUNT = 10;
50
- const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, serializedInputPropsWithCustomSchema, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, concurrency, disallowParallelEncoding, everyNthFrame, imageFormat: provisionalImageFormat, indent, jpegQuality, numberOfGifLoops, onCtrlCExit, preferLossless, serveUrl, server: reusedServer, logLevel, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, colorSpace, repro, finishRenderProgress, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, }) => {
50
+ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, serializedInputPropsWithCustomSchema, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, concurrency, disallowParallelEncoding, everyNthFrame, imageFormat: provisionalImageFormat, indent, jpegQuality, numberOfGifLoops, onCtrlCExit, preferLossless, serveUrl, server: reusedServer, logLevel, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, colorSpace, repro, finishRenderProgress, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, compositionStart, }) => {
51
51
  if (repro) {
52
52
  (0, repro_1.enableRepro)({
53
53
  serveUrl,
@@ -340,6 +340,8 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, s
340
340
  offthreadVideoCacheSizeInBytes,
341
341
  parallelEncodingEnabled: parallelEncoding,
342
342
  binariesDirectory,
343
+ compositionStart,
344
+ forSeamlessAacConcatenation,
343
345
  });
344
346
  return renderFramesProc;
345
347
  })
@@ -399,7 +401,6 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, s
399
401
  colorSpace,
400
402
  binariesDirectory,
401
403
  separateAudioTo,
402
- forSeamlessAacConcatenation,
403
404
  }),
404
405
  stitchStart,
405
406
  ]);
@@ -547,6 +548,8 @@ const renderMedia = ({ proResProfile, x264Preset, crf, composition, inputProps,
547
548
  binariesDirectory: binariesDirectory !== null && binariesDirectory !== void 0 ? binariesDirectory : null,
548
549
  separateAudioTo: separateAudioTo !== null && separateAudioTo !== void 0 ? separateAudioTo : null,
549
550
  forSeamlessAacConcatenation: forSeamlessAacConcatenation !== null && forSeamlessAacConcatenation !== void 0 ? forSeamlessAacConcatenation : false,
551
+ // TODO: In the future, introduce this as a public API when launching the distributed rendering API
552
+ compositionStart: 0,
550
553
  });
551
554
  };
552
555
  exports.renderMedia = renderMedia;
@@ -75,5 +75,5 @@ export declare const internalStitchFramesToVideo: (options: InternalStitchFrames
75
75
  * @description Takes a series of images and audio information generated by renderFrames() and encodes it to a video.
76
76
  * @see [Documentation](https://www.remotion.dev/docs/renderer/stitch-frames-to-video)
77
77
  */
78
- export declare const stitchFramesToVideo: ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, encodingMaxRate, encodingBufferSize, x264Preset, colorSpace, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, }: StitchFramesToVideoOptions) => Promise<Buffer | null>;
78
+ export declare const stitchFramesToVideo: ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, encodingMaxRate, encodingBufferSize, x264Preset, colorSpace, binariesDirectory, separateAudioTo, }: StitchFramesToVideoOptions) => Promise<Buffer | null>;
79
79
  export {};