@remotion/renderer 4.0.175 → 4.0.177

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,8 @@
1
+ const out = await Bun.build({
2
+ entrypoints: ['src/ensure-browser.ts'],
3
+ target: 'node',
4
+ });
5
+
6
+ Bun.write('ensure-browser.mjs', await out.outputs[0].arrayBuffer());
7
+
8
+ export {};
@@ -1,3 +1,3 @@
1
- import type { TRenderAsset } from 'remotion/no-react';
1
+ import type { AudioOrVideoAsset } from 'remotion/no-react';
2
2
  import type { Assets } from './types';
3
- export declare const calculateAssetPositions: (frames: TRenderAsset[][]) => Assets;
3
+ export declare const calculateAssetPositions: (frames: AudioOrVideoAsset[][]) => Assets;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.calculateAssetPositions = void 0;
4
+ const filter_asset_types_1 = require("../filter-asset-types");
4
5
  const resolve_asset_src_1 = require("../resolve-asset-src");
5
6
  const flatten_volume_array_1 = require("./flatten-volume-array");
6
7
  const types_1 = require("./types");
@@ -16,8 +17,9 @@ const findFrom = (target, renderAsset) => {
16
17
  return true;
17
18
  };
18
19
  const copyAndDeduplicateAssets = (renderAssets) => {
20
+ const onlyAudioAndVideo = (0, filter_asset_types_1.onlyAudioAndVideoAssets)(renderAssets);
19
21
  const deduplicated = [];
20
- for (const renderAsset of renderAssets) {
22
+ for (const renderAsset of onlyAudioAndVideo) {
21
23
  if (!deduplicated.find((d) => d.id === renderAsset.id)) {
22
24
  deduplicated.push(renderAsset);
23
25
  }
@@ -1,4 +1,4 @@
1
- import type { TRenderAsset } from 'remotion/no-react';
1
+ import type { AudioOrVideoAsset } from 'remotion/no-react';
2
2
  import type { LogLevel } from '../log-level';
3
3
  import type { FrameAndAssets } from '../render-frames';
4
4
  import type { RenderMediaOnDownload } from './download-and-map-assets-to-file';
@@ -9,4 +9,4 @@ export declare const convertAssetsToFileUrls: ({ assets, onDownload, downloadMap
9
9
  downloadMap: DownloadMap;
10
10
  indent: boolean;
11
11
  logLevel: LogLevel;
12
- }) => Promise<TRenderAsset[][]>;
12
+ }) => Promise<AudioOrVideoAsset[][]>;
@@ -14,7 +14,7 @@ const convertAssetsToFileUrls = async ({ assets, onDownload, downloadMap, indent
14
14
  const results = [];
15
15
  for (const ch of chunks) {
16
16
  const assetPromises = ch.map((frame) => {
17
- const frameAssetPromises = frame.assets.map((a) => {
17
+ const frameAssetPromises = frame.audioAndVideoAssets.map((a) => {
18
18
  return (0, download_and_map_assets_to_file_1.downloadAndMapAssetsToFileUrl)({
19
19
  renderAsset: a,
20
20
  onDownload,
@@ -1,4 +1,4 @@
1
- import type { TRenderAsset } from 'remotion/no-react';
1
+ import type { AudioOrVideoAsset } from 'remotion/no-react';
2
2
  import type { LogLevel } from '../log-level';
3
3
  import type { DownloadMap } from './download-map';
4
4
  export type RenderMediaOnDownload = (src: string) => ((progress: {
@@ -20,10 +20,10 @@ export declare const getSanitizedFilenameForAssetUrl: ({ src, downloadDir, conte
20
20
  contentType: string | null;
21
21
  }) => string;
22
22
  export declare const downloadAndMapAssetsToFileUrl: ({ renderAsset, onDownload, downloadMap, logLevel, indent, }: {
23
- renderAsset: TRenderAsset;
23
+ renderAsset: AudioOrVideoAsset;
24
24
  onDownload: RenderMediaOnDownload | null;
25
25
  downloadMap: DownloadMap;
26
26
  logLevel: LogLevel;
27
27
  indent: boolean;
28
- }) => Promise<TRenderAsset>;
28
+ }) => Promise<AudioOrVideoAsset>;
29
29
  export declare const attachDownloadListenerToEmitter: (downloadMap: DownloadMap, onDownload: RenderMediaOnDownload | null) => () => void;
@@ -1,5 +1,5 @@
1
- import type { TRenderAsset } from 'remotion/no-react';
2
- export type UnsafeAsset = Omit<TRenderAsset, 'frame' | 'id' | 'volume' | 'mediaFrame' | 'audioStartFrom'> & {
1
+ import type { AudioOrVideoAsset } from 'remotion/no-react';
2
+ export type UnsafeAsset = Omit<AudioOrVideoAsset, 'frame' | 'id' | 'volume' | 'mediaFrame' | 'audioStartFrom'> & {
3
3
  startInVideo: number;
4
4
  duration: number | null;
5
5
  trimLeft: number;
@@ -14,5 +14,5 @@ export type MediaAsset = Omit<UnsafeAsset, 'duration' | 'volume'> & {
14
14
  duration: number;
15
15
  volume: AssetVolume;
16
16
  };
17
- export declare const uncompressMediaAsset: (allRenderAssets: TRenderAsset[], assetToUncompress: TRenderAsset) => TRenderAsset;
17
+ export declare const uncompressMediaAsset: (allRenderAssets: AudioOrVideoAsset[], assetToUncompress: AudioOrVideoAsset) => AudioOrVideoAsset;
18
18
  export type Assets = MediaAsset[];
@@ -52,7 +52,12 @@ const make_file_executable_1 = require("../compositor/make-file-executable");
52
52
  const logger_1 = require("../logger");
53
53
  const get_download_destination_1 = require("./get-download-destination");
54
54
  const TESTED_VERSION = '123.0.6312.86';
55
+ // https://github.com/microsoft/playwright/tree/v1.42.0
56
+ const PLAYWRIGHT_VERSION = '1105'; // 123.0.6312.4
55
57
  function getChromeDownloadUrl({ platform, version, }) {
58
+ if (platform === 'linux-arm64') {
59
+ return `https://playwright.azureedge.net/builds/chromium/${version !== null && version !== void 0 ? version : PLAYWRIGHT_VERSION}/chromium-linux-arm64.zip`;
60
+ }
56
61
  return `https://storage.googleapis.com/chrome-for-testing-public/${version !== null && version !== void 0 ? version : TESTED_VERSION}/${platform}/chrome-headless-shell-${platform}.zip`;
57
62
  }
58
63
  const mkdirAsync = fs.promises.mkdir;
@@ -70,7 +75,7 @@ const getPlatform = () => {
70
75
  case 'darwin':
71
76
  return os.arch() === 'arm64' ? 'mac-arm64' : 'mac-x64';
72
77
  case 'linux':
73
- return 'linux64';
78
+ return os.arch() === 'arm64' ? 'linux-arm64' : 'linux64';
74
79
  case 'win32':
75
80
  return 'win64';
76
81
  default:
@@ -99,13 +104,11 @@ const downloadBrowser = async ({ logLevel, indent, onProgress, version, }) => {
99
104
  recursive: true,
100
105
  });
101
106
  }
102
- // Use system Chromium builds on Linux ARM devices
103
- if (os.platform() !== 'darwin' && os.arch() === 'arm64') {
107
+ if (os.platform() !== 'darwin' &&
108
+ os.platform() !== 'linux' &&
109
+ os.arch() === 'arm64') {
104
110
  throw new Error([
105
- 'Chrome Headless Shell is not available for Linux for arm64 architecture.',
106
- 'If you are on Ubuntu, you can install with:',
107
- 'sudo apt install chromium',
108
- 'sudo apt install chromium-browser',
111
+ 'Chrome Headless Shell is not available for Windows for arm64 architecture.',
109
112
  ].join('\n'));
110
113
  }
111
114
  try {
@@ -127,6 +130,15 @@ const downloadBrowser = async ({ logLevel, indent, onProgress, version, }) => {
127
130
  });
128
131
  logger_1.Log.info({ indent, logLevel });
129
132
  await (0, extract_zip_1.default)(archivePath, { dir: outputPath });
133
+ const chromePath = path.join(outputPath, 'chrome-linux', 'chrome');
134
+ const chromeHeadlessShellPath = path.join(outputPath, 'chrome-linux', 'chrome-headless-shell');
135
+ if (fs.existsSync(chromePath)) {
136
+ fs.renameSync(chromePath, chromeHeadlessShellPath);
137
+ }
138
+ const chromeLinuxFolder = path.join(outputPath, 'chrome-linux');
139
+ if (fs.existsSync(chromeLinuxFolder)) {
140
+ fs.renameSync(chromeLinuxFolder, path.join(outputPath, 'chrome-headless-shell-linux-arm64'));
141
+ }
130
142
  }
131
143
  finally {
132
144
  if (await existsAsync(archivePath)) {
@@ -237,7 +237,7 @@ function waitForWSEndpoint(browserProcess, timeout) {
237
237
  let stderrString = '';
238
238
  return new Promise((resolve, reject) => {
239
239
  browserStderr.addListener('data', onData);
240
- browserProcess.addListener('close', onClose);
240
+ browserStderr.addListener('close', onClose);
241
241
  const listeners = [
242
242
  () => browserStderr.removeListener('data', onData),
243
243
  () => browserStderr.removeListener('close', onClose),
package/dist/client.d.ts CHANGED
@@ -604,17 +604,17 @@ export declare const BrowserSafeApis: {
604
604
  description: () => import("react/jsx-runtime").JSX.Element;
605
605
  ssrName: "x264Preset";
606
606
  docLink: string;
607
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
607
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
608
608
  getValue: ({ commandLine }: {
609
609
  commandLine: Record<string, unknown>;
610
610
  }) => {
611
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
611
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
612
612
  source: string;
613
613
  } | {
614
614
  value: null;
615
615
  source: string;
616
616
  };
617
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
617
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
618
618
  };
619
619
  logLevelOption: {
620
620
  cliFlag: "log";
@@ -864,17 +864,17 @@ export declare const BrowserSafeApis: {
864
864
  description: () => import("react/jsx-runtime").JSX.Element;
865
865
  ssrName: "x264Preset";
866
866
  docLink: string;
867
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
867
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
868
868
  getValue: ({ commandLine }: {
869
869
  commandLine: Record<string, unknown>;
870
870
  }) => {
871
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
871
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
872
872
  source: string;
873
873
  } | {
874
874
  value: null;
875
875
  source: string;
876
876
  };
877
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
877
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
878
878
  };
879
879
  readonly audioBitrate: {
880
880
  name: string;
@@ -1586,17 +1586,17 @@ export declare const BrowserSafeApis: {
1586
1586
  description: () => import("react/jsx-runtime").JSX.Element;
1587
1587
  ssrName: "x264Preset";
1588
1588
  docLink: string;
1589
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
1589
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
1590
1590
  getValue: ({ commandLine }: {
1591
1591
  commandLine: Record<string, unknown>;
1592
1592
  }) => {
1593
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
1593
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
1594
1594
  source: string;
1595
1595
  } | {
1596
1596
  value: null;
1597
1597
  source: string;
1598
1598
  };
1599
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
1599
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
1600
1600
  };
1601
1601
  readonly encodingMaxRate: {
1602
1602
  name: string;
@@ -1952,17 +1952,17 @@ export declare const BrowserSafeApis: {
1952
1952
  description: () => import("react/jsx-runtime").JSX.Element;
1953
1953
  ssrName: "x264Preset";
1954
1954
  docLink: string;
1955
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
1955
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
1956
1956
  getValue: ({ commandLine }: {
1957
1957
  commandLine: Record<string, unknown>;
1958
1958
  }) => {
1959
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
1959
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
1960
1960
  source: string;
1961
1961
  } | {
1962
1962
  value: null;
1963
1963
  source: string;
1964
1964
  };
1965
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
1965
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
1966
1966
  };
1967
1967
  readonly encodingMaxRate: {
1968
1968
  name: string;
@@ -0,0 +1,7 @@
1
+ import type { ArtifactAsset } from 'remotion/no-react';
2
+ import type { Page } from './browser/BrowserPage';
3
+ export declare const collectAssets: ({ frame, freePage, timeoutInMilliseconds, }: {
4
+ frame: number;
5
+ freePage: Page;
6
+ timeoutInMilliseconds: number;
7
+ }) => Promise<(import("remotion/no-react").AudioOrVideoAsset | ArtifactAsset)[]>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectAssets = void 0;
4
+ const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
5
+ const collectAssets = async ({ frame, freePage, timeoutInMilliseconds, }) => {
6
+ const { value } = await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
7
+ pageFunction: () => {
8
+ return window.remotion_collectAssets();
9
+ },
10
+ args: [],
11
+ frame,
12
+ page: freePage,
13
+ timeoutInMilliseconds,
14
+ });
15
+ const fixedArtifacts = value.map((asset) => {
16
+ if (asset.type !== 'artifact') {
17
+ return asset;
18
+ }
19
+ if (typeof asset.content !== 'string') {
20
+ throw new Error(`Expected string content for artifact ${asset.id}, but got ${asset.content}`);
21
+ }
22
+ const stringOrUintArray = asset.binary
23
+ ? new TextEncoder().encode(atob(asset.content))
24
+ : asset.content;
25
+ return {
26
+ ...asset,
27
+ content: stringOrUintArray,
28
+ };
29
+ });
30
+ return fixedArtifacts;
31
+ };
32
+ exports.collectAssets = collectAssets;
@@ -2,6 +2,6 @@
2
2
  * Since audio or video can be base64-encoded, those can be really long strings.
3
3
  * Since we track the `src` property for every frame, Node.JS can run out of memory easily. Instead of duplicating the src for every frame, we save memory by replacing the full base 64 encoded data with a string `same-as-[asset-id]-[frame]` referencing a previous asset with the same src.
4
4
  */
5
- import type { TRenderAsset } from 'remotion/no-react';
6
- export declare const compressAsset: (previousRenderAssets: TRenderAsset[], newRenderAsset: TRenderAsset) => TRenderAsset;
5
+ import type { AudioOrVideoAsset } from 'remotion/no-react';
6
+ export declare const compressAsset: (previousRenderAssets: AudioOrVideoAsset[], newRenderAsset: AudioOrVideoAsset) => AudioOrVideoAsset;
7
7
  export declare const isAssetCompressed: (src: string) => boolean;
@@ -0,0 +1,3 @@
1
+ import type { ArtifactAsset, AudioOrVideoAsset, TRenderAsset } from 'remotion/no-react';
2
+ export declare const onlyAudioAndVideoAssets: (assets: TRenderAsset[]) => AudioOrVideoAsset[];
3
+ export declare const onlyArtifact: (assets: TRenderAsset[]) => ArtifactAsset[];
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.onlyArtifact = exports.onlyAudioAndVideoAssets = void 0;
4
+ const onlyAudioAndVideoAssets = (assets) => {
5
+ return assets.filter((asset) => asset.type === 'audio' || asset.type === 'video');
6
+ };
7
+ exports.onlyAudioAndVideoAssets = onlyAudioAndVideoAssets;
8
+ const onlyArtifact = (assets) => {
9
+ return assets.filter((asset) => asset.type === 'artifact');
10
+ };
11
+ exports.onlyArtifact = onlyArtifact;
package/dist/index.d.ts CHANGED
@@ -37,10 +37,11 @@ export { X264Preset } from './options/x264-preset';
37
37
  export { PixelFormat } from './pixel-format';
38
38
  export { RemotionServer } from './prepare-server';
39
39
  export { ProResProfile } from './prores-profile';
40
- export { RenderFramesOptions, renderFrames } from './render-frames';
40
+ export { OnArtifact, RenderFramesOptions, renderFrames } from './render-frames';
41
41
  export { InternalRenderMediaOptions, RenderMediaOnProgress, RenderMediaOptions, SlowFrame, StitchingState, renderMedia, } from './render-media';
42
42
  export { RenderStillOptions, renderStill } from './render-still';
43
43
  export { SelectCompositionOptions, selectComposition, } from './select-composition';
44
+ export { EmittedArtifact } from './serialize-artifact';
44
45
  export { StitchFramesToVideoOptions, stitchFramesToVideo, } from './stitch-frames-to-video';
45
46
  export { SymbolicatedStackFrame } from './symbolicate-stacktrace';
46
47
  export { OnStartData, RenderFramesOutput } from './types';
@@ -337,7 +338,7 @@ export declare const RenderInternals: {
337
338
  makeFileExtensionMap: () => Record<string, ("h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif")[]>;
338
339
  defaultCodecsForFileExtension: Record<import("./file-extensions").FileExtension, "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif">;
339
340
  getExecutablePath: ({ indent, logLevel, type, binariesDirectory, }: {
340
- type: "compositor" | "ffmpeg" | "ffprobe";
341
+ type: "ffmpeg" | "ffprobe" | "compositor";
341
342
  indent: boolean;
342
343
  logLevel: "verbose" | "info" | "warn" | "error";
343
344
  binariesDirectory: string | null;
@@ -469,6 +470,7 @@ export declare const RenderInternals: {
469
470
  serveUrl: string;
470
471
  port: number | null;
471
472
  offthreadVideoCacheSizeInBytes: number | null;
473
+ onArtifact: import("./render-frames").OnArtifact | null;
472
474
  } & import("./options/option").ToOptions<{
473
475
  readonly offthreadVideoCacheSizeInBytes: {
474
476
  name: string;
@@ -748,7 +750,143 @@ export declare const RenderInternals: {
748
750
  setConfig: () => never;
749
751
  };
750
752
  }>) => Promise<import("remotion").VideoConfig[]>;
751
- internalRenderFrames: (args_0: import("./render-frames").InternalRenderFramesOptions) => Promise<import("./types").RenderFramesOutput>;
753
+ internalRenderFrames: (args_0: {
754
+ onStart: ((data: import("./types").OnStartData) => void) | null;
755
+ onFrameUpdate: ((framesRendered: number, frameIndex: number, timeToRenderInMilliseconds: number) => void) | null;
756
+ outputDir: string | null;
757
+ envVariables: Record<string, string>;
758
+ imageFormat: "jpeg" | "png" | "none";
759
+ jpegQuality: number;
760
+ frameRange: import("./frame-range").FrameRange | null;
761
+ everyNthFrame: number;
762
+ puppeteerInstance: HeadlessBrowser | undefined;
763
+ browserExecutable: import("./browser-executable").BrowserExecutable;
764
+ onBrowserLog: ((log: import("./browser-log").BrowserLog) => void) | null;
765
+ onFrameBuffer: ((buffer: Buffer, frame: number) => void) | null;
766
+ onDownload: import("./assets/download-and-map-assets-to-file").RenderMediaOnDownload | null;
767
+ chromiumOptions: import("./open-browser").ChromiumOptions;
768
+ scale: number;
769
+ port: number | null;
770
+ cancelSignal: import("./make-cancel-signal").CancelSignal | undefined;
771
+ composition: Omit<import("remotion").VideoConfig, "defaultProps" | "props">;
772
+ indent: boolean;
773
+ server: import("./prepare-server").RemotionServer | undefined;
774
+ muted: boolean;
775
+ concurrency: string | number | null;
776
+ webpackBundleOrServeUrl: string;
777
+ serializedInputPropsWithCustomSchema: string;
778
+ serializedResolvedPropsWithCustomSchema: string;
779
+ parallelEncodingEnabled: boolean;
780
+ compositionStart: number;
781
+ onArtifact: import("./render-frames").OnArtifact | null;
782
+ } & import("./options/option").ToOptions<{
783
+ readonly forSeamlessAacConcatenation: {
784
+ name: string;
785
+ cliFlag: "for-seamless-aac-concatenation";
786
+ description: () => import("react/jsx-runtime").JSX.Element;
787
+ docLink: string;
788
+ getValue: ({ commandLine }: {
789
+ commandLine: Record<string, unknown>;
790
+ }) => {
791
+ source: string;
792
+ value: true;
793
+ } | {
794
+ source: string;
795
+ value: false;
796
+ };
797
+ setConfig: (value: boolean) => void;
798
+ ssrName: string;
799
+ type: boolean;
800
+ };
801
+ readonly offthreadVideoCacheSizeInBytes: {
802
+ name: string;
803
+ cliFlag: "offthreadvideo-cache-size-in-bytes";
804
+ description: () => import("react/jsx-runtime").JSX.Element;
805
+ ssrName: "offthreadVideoCacheSizeInBytes";
806
+ docLink: string;
807
+ type: number | null;
808
+ getValue: ({ commandLine }: {
809
+ commandLine: Record<string, unknown>;
810
+ }) => {
811
+ source: string;
812
+ value: number;
813
+ } | {
814
+ source: string;
815
+ value: null;
816
+ };
817
+ setConfig: (size: number | null) => void;
818
+ };
819
+ readonly jpegQuality: {
820
+ name: string;
821
+ cliFlag: "jpeg-quality";
822
+ description: () => import("react/jsx-runtime").JSX.Element;
823
+ ssrName: string;
824
+ docLink: string;
825
+ type: number;
826
+ setConfig: (q: number | undefined) => void;
827
+ getValue: ({ commandLine }: {
828
+ commandLine: Record<string, unknown>;
829
+ }) => {
830
+ source: string;
831
+ value: number;
832
+ };
833
+ };
834
+ readonly logLevel: {
835
+ cliFlag: "log";
836
+ name: string;
837
+ ssrName: string;
838
+ description: () => import("react/jsx-runtime").JSX.Element;
839
+ docLink: string;
840
+ getValue: ({ commandLine }: {
841
+ commandLine: Record<string, unknown>;
842
+ }) => {
843
+ value: "verbose" | "info" | "warn" | "error";
844
+ source: string;
845
+ };
846
+ setConfig: (newLogLevel: "verbose" | "info" | "warn" | "error") => void;
847
+ type: "verbose" | "info" | "warn" | "error";
848
+ };
849
+ readonly timeoutInMilliseconds: {
850
+ name: string;
851
+ cliFlag: "timeout";
852
+ description: () => import("react/jsx-runtime").JSX.Element;
853
+ ssrName: "timeoutInMilliseconds";
854
+ docLink: string;
855
+ type: number;
856
+ getValue: ({ commandLine }: {
857
+ commandLine: Record<string, unknown>;
858
+ }) => {
859
+ source: string;
860
+ value: number;
861
+ };
862
+ setConfig: (value: number) => void;
863
+ };
864
+ readonly binariesDirectory: {
865
+ name: string;
866
+ cliFlag: "binaries-directory";
867
+ description: () => import("react/jsx-runtime").JSX.Element;
868
+ ssrName: "binariesDirectory";
869
+ docLink: string;
870
+ type: string | null;
871
+ getValue: ({ commandLine }: {
872
+ commandLine: Record<string, unknown>;
873
+ }) => {
874
+ source: string;
875
+ value: string | null;
876
+ };
877
+ setConfig: (value: string | null) => void;
878
+ };
879
+ readonly onBrowserDownload: {
880
+ name: string;
881
+ cliFlag: "on-browser-download";
882
+ description: () => import("react/jsx-runtime").JSX.Element;
883
+ ssrName: "onBrowserDownload";
884
+ docLink: string;
885
+ type: import("./options/on-browser-download").OnBrowserDownload;
886
+ getValue: () => never;
887
+ setConfig: () => never;
888
+ };
889
+ }>) => Promise<import("./types").RenderFramesOutput>;
752
890
  internalRenderMedia: (args_0: import("./render-media").InternalRenderMediaOptions) => Promise<{
753
891
  buffer: Buffer | null;
754
892
  slowestFrames: import("./render-media").SlowFrame[];
@@ -785,7 +923,7 @@ export declare const RenderInternals: {
785
923
  assetsInfo: import("./assets/download-map").RenderAssetInfo | null;
786
924
  enforceAudioTrack: boolean;
787
925
  muted: boolean;
788
- }) => "no" | "yes" | "maybe";
926
+ }) => "yes" | "maybe" | "no";
789
927
  codecSupportsMedia: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "h264-ts" | "gif") => {
790
928
  video: boolean;
791
929
  audio: boolean;
@@ -382,17 +382,17 @@ export declare const allOptions: {
382
382
  description: () => import("react/jsx-runtime").JSX.Element;
383
383
  ssrName: "x264Preset";
384
384
  docLink: string;
385
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
385
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
386
386
  getValue: ({ commandLine }: {
387
387
  commandLine: Record<string, unknown>;
388
388
  }) => {
389
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
389
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
390
390
  source: string;
391
391
  } | {
392
392
  value: null;
393
393
  source: string;
394
394
  };
395
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
395
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
396
396
  };
397
397
  logLevelOption: {
398
398
  cliFlag: "log";
@@ -72,17 +72,17 @@ export declare const optionsMap: {
72
72
  description: () => import("react/jsx-runtime").JSX.Element;
73
73
  ssrName: "x264Preset";
74
74
  docLink: string;
75
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
75
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
76
76
  getValue: ({ commandLine }: {
77
77
  commandLine: Record<string, unknown>;
78
78
  }) => {
79
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
79
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
80
80
  source: string;
81
81
  } | {
82
82
  value: null;
83
83
  source: string;
84
84
  };
85
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
85
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
86
86
  };
87
87
  readonly audioBitrate: {
88
88
  name: string;
@@ -794,17 +794,17 @@ export declare const optionsMap: {
794
794
  description: () => import("react/jsx-runtime").JSX.Element;
795
795
  ssrName: "x264Preset";
796
796
  docLink: string;
797
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
797
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
798
798
  getValue: ({ commandLine }: {
799
799
  commandLine: Record<string, unknown>;
800
800
  }) => {
801
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
801
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
802
802
  source: string;
803
803
  } | {
804
804
  value: null;
805
805
  source: string;
806
806
  };
807
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
807
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
808
808
  };
809
809
  readonly encodingMaxRate: {
810
810
  name: string;
@@ -1160,17 +1160,17 @@ export declare const optionsMap: {
1160
1160
  description: () => import("react/jsx-runtime").JSX.Element;
1161
1161
  ssrName: "x264Preset";
1162
1162
  docLink: string;
1163
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
1163
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
1164
1164
  getValue: ({ commandLine }: {
1165
1165
  commandLine: Record<string, unknown>;
1166
1166
  }) => {
1167
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
1167
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
1168
1168
  source: string;
1169
1169
  } | {
1170
1170
  value: null;
1171
1171
  source: string;
1172
1172
  };
1173
- setConfig: (profile: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
1173
+ setConfig: (profile: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null) => void;
1174
1174
  };
1175
1175
  readonly encodingMaxRate: {
1176
1176
  name: string;
@@ -11,11 +11,11 @@ export declare const x264Option: {
11
11
  description: () => import("react/jsx-runtime").JSX.Element;
12
12
  ssrName: "x264Preset";
13
13
  docLink: string;
14
- type: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | null;
14
+ type: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo" | null;
15
15
  getValue: ({ commandLine }: {
16
16
  commandLine: Record<string, unknown>;
17
17
  }) => {
18
- value: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
18
+ value: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
19
19
  source: string;
20
20
  } | {
21
21
  value: null;
@@ -1,6 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { TAsset } from 'remotion';
3
- import type { VideoConfig } from 'remotion/no-react';
2
+ import type { AudioOrVideoAsset, VideoConfig } from 'remotion/no-react';
4
3
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
5
4
  import type { BrowserExecutable } from './browser-executable';
6
5
  import type { BrowserLog } from './browser-log';
@@ -12,8 +11,10 @@ import type { ChromiumOptions } from './open-browser';
12
11
  import type { ToOptions } from './options/option';
13
12
  import type { optionsMap } from './options/options-map';
14
13
  import type { RemotionServer } from './prepare-server';
14
+ import type { EmittedArtifact } from './serialize-artifact';
15
15
  import type { OnStartData, RenderFramesOutput } from './types';
16
- export type InternalRenderFramesOptions = {
16
+ export type OnArtifact = (asset: EmittedArtifact) => void;
17
+ type InternalRenderFramesOptions = {
17
18
  onStart: null | ((data: OnStartData) => void);
18
19
  onFrameUpdate: null | ((framesRendered: number, frameIndex: number, timeToRenderInMilliseconds: number) => void);
19
20
  outputDir: string | null;
@@ -41,10 +42,16 @@ export type InternalRenderFramesOptions = {
41
42
  serializedResolvedPropsWithCustomSchema: string;
42
43
  parallelEncodingEnabled: boolean;
43
44
  compositionStart: number;
45
+ onArtifact: OnArtifact | null;
44
46
  } & ToOptions<typeof optionsMap.renderFrames>;
47
+ type ArtifactWithoutContent = {
48
+ frame: number;
49
+ filename: string;
50
+ };
45
51
  export type FrameAndAssets = {
46
52
  frame: number;
47
- assets: TAsset[];
53
+ audioAndVideoAssets: AudioOrVideoAsset[];
54
+ artifactAssets: ArtifactWithoutContent[];
48
55
  };
49
56
  export type RenderFramesOptions = {
50
57
  onStart: (data: OnStartData) => void;
@@ -80,6 +87,7 @@ export type RenderFramesOptions = {
80
87
  composition: VideoConfig;
81
88
  muted?: boolean;
82
89
  concurrency?: number | string | null;
90
+ onArtifact?: OnArtifact | null;
83
91
  serveUrl: string;
84
92
  } & Partial<ToOptions<typeof optionsMap.renderFrames>>;
85
93
  export declare const internalRenderFrames: (args_0: InternalRenderFramesOptions) => Promise<RenderFramesOutput>;
@@ -90,3 +98,4 @@ export declare const internalRenderFrames: (args_0: InternalRenderFramesOptions)
90
98
  * @returns {Promise<RenderFramesOutput>} Information about the rendered frames and assets.
91
99
  */
92
100
  export declare const renderFrames: (options: RenderFramesOptions) => Promise<RenderFramesOutput>;
101
+ export {};
@@ -16,6 +16,7 @@ const is_target_closed_err_1 = require("./browser/is-target-closed-err");
16
16
  const compress_assets_1 = require("./compress-assets");
17
17
  const cycle_browser_tabs_1 = require("./cycle-browser-tabs");
18
18
  const handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
19
+ const filter_asset_types_1 = require("./filter-asset-types");
19
20
  const find_closest_package_json_1 = require("./find-closest-package-json");
20
21
  const get_concurrency_1 = require("./get-concurrency");
21
22
  const get_duration_from_frame_range_1 = require("./get-duration-from-frame-range");
@@ -40,7 +41,7 @@ const validate_1 = require("./validate");
40
41
  const validate_scale_1 = require("./validate-scale");
41
42
  const wrap_with_error_handling_1 = require("./wrap-with-error-handling");
42
43
  const MAX_RETRIES_PER_FRAME = 1;
43
- const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serializedInputPropsWithCustomSchema, serializedResolvedPropsWithCustomSchema, jpegQuality, imageFormat, frameRange, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualConcurrency: concurrency, everyNthFrame, proxyPort, cancelSignal, downloadMap, muted, makeBrowser, browserReplacer, compositor, sourceMapGetter, logLevel, indent, parallelEncodingEnabled, compositionStart, forSeamlessAacConcatenation, }) => {
44
+ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serializedInputPropsWithCustomSchema, serializedResolvedPropsWithCustomSchema, jpegQuality, imageFormat, frameRange, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualConcurrency: concurrency, everyNthFrame, proxyPort, cancelSignal, downloadMap, muted, makeBrowser, browserReplacer, compositor, sourceMapGetter, logLevel, indent, parallelEncodingEnabled, compositionStart, forSeamlessAacConcatenation, onArtifact, }) => {
44
45
  if (outputDir) {
45
46
  if (!node_fs_1.default.existsSync(outputDir)) {
46
47
  node_fs_1.default.mkdirSync(outputDir, {
@@ -219,15 +220,39 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
219
220
  onFrameBuffer(buffer, frame);
220
221
  }
221
222
  (0, perf_1.stopPerfMeasure)(id);
222
- const compressedAssets = collectedAssets.map((asset) => (0, compress_assets_1.compressAsset)(assets
223
+ const previousAudioRenderAssets = assets
223
224
  .filter(truthy_1.truthy)
224
- .map((a) => a.assets)
225
- .flat(2), asset));
225
+ .map((a) => a.audioAndVideoAssets)
226
+ .flat(2);
227
+ const previousArtifactAssets = assets
228
+ .filter(truthy_1.truthy)
229
+ .map((a) => a.artifactAssets)
230
+ .flat(2);
231
+ const audioAndVideoAssets = (0, filter_asset_types_1.onlyAudioAndVideoAssets)(collectedAssets);
232
+ const artifactAssets = (0, filter_asset_types_1.onlyArtifact)(collectedAssets);
233
+ for (const artifact of artifactAssets) {
234
+ for (const previousArtifact of previousArtifactAssets) {
235
+ if (artifact.filename === previousArtifact.filename) {
236
+ reject(new Error(`An artifact with output "${artifact.filename}" was already registered at frame ${previousArtifact.frame}, but now registered again at frame ${artifact.frame}. Artifacts must have unique names. https://remotion.dev/docs/artifacts`));
237
+ return;
238
+ }
239
+ }
240
+ onArtifact === null || onArtifact === void 0 ? void 0 : onArtifact(artifact);
241
+ }
242
+ const compressedAssets = audioAndVideoAssets.map((asset) => {
243
+ return (0, compress_assets_1.compressAsset)(previousAudioRenderAssets, asset);
244
+ });
226
245
  assets.push({
227
- assets: compressedAssets,
246
+ audioAndVideoAssets: compressedAssets,
228
247
  frame,
248
+ artifactAssets: artifactAssets.map((a) => {
249
+ return {
250
+ frame: a.frame,
251
+ filename: a.filename,
252
+ };
253
+ }),
229
254
  });
230
- compressedAssets.forEach((renderAsset) => {
255
+ for (const renderAsset of compressedAssets) {
231
256
  (0, download_and_map_assets_to_file_1.downloadAndMapAssetsToFileUrl)({
232
257
  renderAsset,
233
258
  onDownload,
@@ -239,7 +264,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
239
264
  (renderAsset.src.length > 1000 ? '...' : '');
240
265
  onError(new Error(`Error while downloading ${truncateWithEllipsis}: ${err.stack}`));
241
266
  });
242
- });
267
+ }
243
268
  if (!assetsOnly) {
244
269
  framesRendered++;
245
270
  onFrameUpdate === null || onFrameUpdate === void 0 ? void 0 : onFrameUpdate(framesRendered, frame, perf_hooks_1.performance.now() - startTime);
@@ -385,7 +410,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
385
410
  frameCount: framesToRender.length,
386
411
  };
387
412
  };
388
- 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, onBrowserDownload, }) => {
413
+ 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, onBrowserDownload, onArtifact, }) => {
389
414
  (0, validate_1.validateDimension)(composition.height, 'height', 'in the `config` object passed to `renderFrames()`');
390
415
  (0, validate_1.validateDimension)(composition.width, 'width', 'in the `config` object passed to `renderFrames()`');
391
416
  (0, validate_1.validateFps)(composition.fps, 'in the `config` object of `renderFrames()`', false);
@@ -480,6 +505,7 @@ const internalRenderFramesRaw = ({ browserExecutable, cancelSignal, chromiumOpti
480
505
  forSeamlessAacConcatenation,
481
506
  compositionStart,
482
507
  onBrowserDownload,
508
+ onArtifact,
483
509
  });
484
510
  }),
485
511
  ])
@@ -530,7 +556,7 @@ exports.internalRenderFrames = (0, wrap_with_error_handling_1.wrapWithErrorHandl
530
556
  * @returns {Promise<RenderFramesOutput>} Information about the rendered frames and assets.
531
557
  */
532
558
  const renderFrames = (options) => {
533
- const { composition, inputProps, onFrameUpdate, onStart, outputDir, serveUrl, browserExecutable, cancelSignal, chromiumOptions, concurrency, dumpBrowserLogs, envVariables, everyNthFrame, frameRange, imageFormat, jpegQuality, muted, onBrowserLog, onDownload, onFrameBuffer, port, puppeteerInstance, scale, timeoutInMilliseconds, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, binariesDirectory, onBrowserDownload, } = options;
559
+ const { composition, inputProps, onFrameUpdate, onStart, outputDir, serveUrl, browserExecutable, cancelSignal, chromiumOptions, concurrency, dumpBrowserLogs, envVariables, everyNthFrame, frameRange, imageFormat, jpegQuality, muted, onBrowserLog, onDownload, onFrameBuffer, port, puppeteerInstance, scale, timeoutInMilliseconds, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, binariesDirectory, onBrowserDownload, onArtifact, } = options;
534
560
  if (!composition) {
535
561
  throw new Error('No `composition` option has been specified for renderFrames()');
536
562
  }
@@ -584,6 +610,7 @@ const renderFrames = (options) => {
584
610
  compositionStart: 0,
585
611
  forSeamlessAacConcatenation: false,
586
612
  onBrowserDownload: onBrowserDownload !== null && onBrowserDownload !== void 0 ? onBrowserDownload : (0, browser_download_progress_bar_1.defaultBrowserDownloadProgress)({ indent, logLevel, api: 'renderFrames()' }),
613
+ onArtifact: onArtifact !== null && onArtifact !== void 0 ? onArtifact : null,
587
614
  });
588
615
  };
589
616
  exports.renderFrames = renderFrames;
@@ -16,6 +16,7 @@ import type { optionsMap } from './options/options-map';
16
16
  import type { PixelFormat } from './pixel-format';
17
17
  import type { RemotionServer } from './prepare-server';
18
18
  import type { ProResProfile } from './prores-profile';
19
+ import type { OnArtifact } from './render-frames';
19
20
  import type { OnStartData } from './types';
20
21
  export type StitchingState = 'encoding' | 'muxing';
21
22
  export type SlowFrame = {
@@ -66,6 +67,7 @@ export type InternalRenderMediaOptions = {
66
67
  concurrency: number | string | null;
67
68
  binariesDirectory: string | null;
68
69
  compositionStart: number;
70
+ onArtifact: OnArtifact | null;
69
71
  } & MoreRenderMediaOptions;
70
72
  type Prettify<T> = {
71
73
  [K in keyof T]: T[K];
@@ -118,6 +120,7 @@ export type RenderMediaOptions = Prettify<{
118
120
  colorSpace?: ColorSpace;
119
121
  repro?: boolean;
120
122
  binariesDirectory?: string | null;
123
+ onArtifact?: OnArtifact;
121
124
  }> & Partial<MoreRenderMediaOptions>;
122
125
  type RenderMediaResult = {
123
126
  buffer: Buffer | null;
@@ -131,5 +134,5 @@ export declare const internalRenderMedia: (args_0: InternalRenderMediaOptions) =
131
134
  * @returns {Promise<RenderMediaResult>} A promise that resolves to the rendering result, including a buffer and information about the slowest frames.
132
135
  *
133
136
  */
134
- export declare const renderMedia: ({ proResProfile, x264Preset, crf, composition, inputProps, 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, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, }: RenderMediaOptions) => Promise<RenderMediaResult>;
137
+ export declare const renderMedia: ({ proResProfile, x264Preset, crf, composition, inputProps, 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, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, }: RenderMediaOptions) => Promise<RenderMediaResult>;
135
138
  export {};
@@ -50,7 +50,7 @@ const validate_scale_1 = require("./validate-scale");
50
50
  const validate_videobitrate_1 = require("./validate-videobitrate");
51
51
  const wrap_with_error_handling_1 = require("./wrap-with-error-handling");
52
52
  const SLOWEST_FRAME_COUNT = 10;
53
- 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, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, compositionStart, onBrowserDownload, }) => {
53
+ 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, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, compositionStart, onBrowserDownload, onArtifact, }) => {
54
54
  if (repro) {
55
55
  (0, repro_1.enableRepro)({
56
56
  serveUrl,
@@ -354,6 +354,7 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, s
354
354
  compositionStart,
355
355
  forSeamlessAacConcatenation,
356
356
  onBrowserDownload,
357
+ onArtifact,
357
358
  });
358
359
  return renderFramesProc;
359
360
  })
@@ -492,7 +493,7 @@ exports.internalRenderMedia = (0, wrap_with_error_handling_1.wrapWithErrorHandli
492
493
  * @returns {Promise<RenderMediaResult>} A promise that resolves to the rendering result, including a buffer and information about the slowest frames.
493
494
  *
494
495
  */
495
- const renderMedia = ({ proResProfile, x264Preset, crf, composition, inputProps, 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, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, }) => {
496
+ const renderMedia = ({ proResProfile, x264Preset, crf, composition, inputProps, 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, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, }) => {
496
497
  var _a, _b;
497
498
  if (quality !== undefined) {
498
499
  console.warn(`The "quality" option has been renamed. Please use "jpegQuality" instead.`);
@@ -558,6 +559,7 @@ const renderMedia = ({ proResProfile, x264Preset, crf, composition, inputProps,
558
559
  separateAudioTo: separateAudioTo !== null && separateAudioTo !== void 0 ? separateAudioTo : null,
559
560
  forSeamlessAacConcatenation: forSeamlessAacConcatenation !== null && forSeamlessAacConcatenation !== void 0 ? forSeamlessAacConcatenation : false,
560
561
  onBrowserDownload: onBrowserDownload !== null && onBrowserDownload !== void 0 ? onBrowserDownload : (0, browser_download_progress_bar_1.defaultBrowserDownloadProgress)({ indent, logLevel, api: 'renderMedia()' }),
562
+ onArtifact: onArtifact !== null && onArtifact !== void 0 ? onArtifact : null,
561
563
  // TODO: In the future, introduce this as a public API when launching the distributed rendering API
562
564
  compositionStart: 0,
563
565
  });
@@ -10,6 +10,7 @@ import type { ChromiumOptions } from './open-browser';
10
10
  import type { ToOptions } from './options/option';
11
11
  import type { optionsMap } from './options/options-map';
12
12
  import type { RemotionServer } from './prepare-server';
13
+ import type { OnArtifact } from './render-frames';
13
14
  type InternalRenderStillOptions = {
14
15
  composition: VideoConfig;
15
16
  output: string | null;
@@ -32,6 +33,7 @@ type InternalRenderStillOptions = {
32
33
  serveUrl: string;
33
34
  port: number | null;
34
35
  offthreadVideoCacheSizeInBytes: number | null;
36
+ onArtifact: OnArtifact | null;
35
37
  } & ToOptions<typeof optionsMap.renderStill>;
36
38
  export type RenderStillOptions = {
37
39
  port?: number | null;
@@ -62,6 +64,7 @@ export type RenderStillOptions = {
62
64
  * @deprecated Renamed to `jpegQuality`
63
65
  */
64
66
  quality?: never;
67
+ onArtifact?: OnArtifact;
65
68
  } & Partial<ToOptions<typeof optionsMap.renderStill>>;
66
69
  type RenderStillReturnValue = {
67
70
  buffer: Buffer | null;
@@ -36,6 +36,7 @@ const browser_download_progress_bar_1 = require("./browser/browser-download-prog
36
36
  const convert_to_positive_frame_index_1 = require("./convert-to-positive-frame-index");
37
37
  const ensure_output_directory_1 = require("./ensure-output-directory");
38
38
  const handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
39
+ const filter_asset_types_1 = require("./filter-asset-types");
39
40
  const find_closest_package_json_1 = require("./find-closest-package-json");
40
41
  const image_format_1 = require("./image-format");
41
42
  const jpeg_quality_1 = require("./jpeg-quality");
@@ -51,7 +52,7 @@ const validate_1 = require("./validate");
51
52
  const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
52
53
  const validate_scale_1 = require("./validate-scale");
53
54
  const wrap_with_error_handling_1 = require("./wrap-with-error-handling");
54
- const innerRenderStill = async ({ composition, imageFormat = image_format_1.DEFAULT_STILL_IMAGE_FORMAT, serveUrl, puppeteerInstance, onError, serializedInputPropsWithCustomSchema, envVariables, output, frame = 0, overwrite, browserExecutable, timeoutInMilliseconds, chromiumOptions, scale, proxyPort, cancelSignal, jpegQuality, onBrowserLog, compositor, sourceMapGetter, downloadMap, logLevel, indent, serializedResolvedPropsWithCustomSchema, onBrowserDownload, }) => {
55
+ const innerRenderStill = async ({ composition, imageFormat = image_format_1.DEFAULT_STILL_IMAGE_FORMAT, serveUrl, puppeteerInstance, onError, serializedInputPropsWithCustomSchema, envVariables, output, frame = 0, overwrite, browserExecutable, timeoutInMilliseconds, chromiumOptions, scale, proxyPort, cancelSignal, jpegQuality, onBrowserLog, compositor, sourceMapGetter, downloadMap, logLevel, indent, serializedResolvedPropsWithCustomSchema, onBrowserDownload, onArtifact, }) => {
55
56
  (0, validate_1.validateDimension)(composition.height, 'height', 'in the `config` object passed to `renderStill()`');
56
57
  (0, validate_1.validateDimension)(composition.width, 'width', 'in the `config` object passed to `renderStill()`');
57
58
  (0, validate_1.validateFps)(composition.fps, 'in the `config` object of `renderStill()`', false);
@@ -187,7 +188,7 @@ const innerRenderStill = async ({ composition, imageFormat = image_format_1.DEFA
187
188
  logLevel,
188
189
  attempt: 0,
189
190
  });
190
- const { buffer } = await (0, take_frame_and_compose_1.takeFrameAndCompose)({
191
+ const { buffer, collectedAssets } = await (0, take_frame_and_compose_1.takeFrameAndCompose)({
191
192
  frame: stillFrame,
192
193
  freePage: page,
193
194
  height: composition.height,
@@ -201,6 +202,17 @@ const innerRenderStill = async ({ composition, imageFormat = image_format_1.DEFA
201
202
  downloadMap,
202
203
  timeoutInMilliseconds,
203
204
  });
205
+ const artifactAssets = (0, filter_asset_types_1.onlyArtifact)(collectedAssets);
206
+ const previousArtifactAssets = [];
207
+ for (const artifact of artifactAssets) {
208
+ for (const previousArtifact of previousArtifactAssets) {
209
+ if (artifact.filename === previousArtifact.filename) {
210
+ throw new Error(`An artifact with output "${artifact.filename}" was already registered at frame ${previousArtifact.frame}, but now registered again at frame ${artifact.frame}. Artifacts must have unique names. https://remotion.dev/docs/artifacts`);
211
+ }
212
+ }
213
+ previousArtifactAssets.push(artifact);
214
+ onArtifact === null || onArtifact === void 0 ? void 0 : onArtifact(artifact);
215
+ }
204
216
  await cleanup();
205
217
  return { buffer: output ? null : buffer };
206
218
  };
@@ -264,7 +276,7 @@ exports.internalRenderStill = (0, wrap_with_error_handling_1.wrapWithErrorHandli
264
276
  */
265
277
  const renderStill = (options) => {
266
278
  var _a, _b;
267
- const { composition, serveUrl, browserExecutable, cancelSignal, chromiumOptions, dumpBrowserLogs, envVariables, frame, imageFormat, inputProps, jpegQuality, onBrowserLog, onDownload, output, overwrite, port, puppeteerInstance, scale, timeoutInMilliseconds, verbose, quality, offthreadVideoCacheSizeInBytes, logLevel: passedLogLevel, binariesDirectory, onBrowserDownload, } = options;
279
+ const { composition, serveUrl, browserExecutable, cancelSignal, chromiumOptions, dumpBrowserLogs, envVariables, frame, imageFormat, inputProps, jpegQuality, onBrowserLog, onDownload, output, overwrite, port, puppeteerInstance, scale, timeoutInMilliseconds, verbose, quality, offthreadVideoCacheSizeInBytes, logLevel: passedLogLevel, binariesDirectory, onBrowserDownload, onArtifact, } = options;
268
280
  if (typeof jpegQuality !== 'undefined' && imageFormat !== 'jpeg') {
269
281
  throw new Error("You can only pass the `quality` option if `imageFormat` is 'jpeg'.");
270
282
  }
@@ -307,6 +319,7 @@ const renderStill = (options) => {
307
319
  offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes !== null && offthreadVideoCacheSizeInBytes !== void 0 ? offthreadVideoCacheSizeInBytes : null,
308
320
  binariesDirectory: binariesDirectory !== null && binariesDirectory !== void 0 ? binariesDirectory : null,
309
321
  onBrowserDownload: onBrowserDownload !== null && onBrowserDownload !== void 0 ? onBrowserDownload : (0, browser_download_progress_bar_1.defaultBrowserDownloadProgress)({ indent, logLevel, api: 'renderStill()' }),
322
+ onArtifact: onArtifact !== null && onArtifact !== void 0 ? onArtifact : null,
310
323
  });
311
324
  };
312
325
  exports.renderStill = renderStill;
@@ -79,7 +79,7 @@ const waitForReady = ({ page, timeoutInMilliseconds, frame, indent, logLevel, })
79
79
  args: [],
80
80
  frame,
81
81
  page,
82
- timeoutInMilliseconds,
82
+ timeoutInMilliseconds: 5000,
83
83
  })
84
84
  .then((res) => {
85
85
  reject(new Error(`Timeout exceeded rendering the component${frame ? ' at frame ' + frame : ''}. ${res.value ? `Open delayRender() handles: ${res.value}` : ''}`));
@@ -0,0 +1,5 @@
1
+ export type EmittedArtifact = {
2
+ filename: string;
3
+ content: string | Uint8Array;
4
+ frame: number;
5
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -6,13 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.takeFrameAndCompose = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
+ const collect_assets_1 = require("./collect-assets");
9
10
  const compose_1 = require("./compositor/compose");
10
11
  const provide_screenshot_1 = require("./provide-screenshot");
11
12
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
12
13
  const truthy_1 = require("./truthy");
13
14
  const takeFrameAndCompose = async ({ freePage, imageFormat, jpegQuality, frame, width, height, output, scale, downloadMap, wantsBuffer, compositor, timeoutInMilliseconds, }) => {
14
15
  var _a;
15
- const [{ value: clipRegion }, { value: collectedAssets }] = await Promise.all([
16
+ const [{ value: clipRegion }, collectedAssets] = await Promise.all([
16
17
  (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
17
18
  pageFunction: () => {
18
19
  if (typeof window.remotion_getClipRegion === 'undefined') {
@@ -25,15 +26,7 @@ const takeFrameAndCompose = async ({ freePage, imageFormat, jpegQuality, frame,
25
26
  page: freePage,
26
27
  timeoutInMilliseconds,
27
28
  }),
28
- (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
29
- pageFunction: () => {
30
- return window.remotion_collectAssets();
31
- },
32
- args: [],
33
- frame,
34
- page: freePage,
35
- timeoutInMilliseconds,
36
- }),
29
+ (0, collect_assets_1.collectAssets)({ frame, freePage, timeoutInMilliseconds }),
37
30
  ]);
38
31
  if (imageFormat === 'none') {
39
32
  return { buffer: null, collectedAssets };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "4.0.175",
3
+ "version": "4.0.177",
4
4
  "description": "Renderer for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,8 +17,8 @@
17
17
  "execa": "5.1.1",
18
18
  "extract-zip": "2.0.1",
19
19
  "source-map": "^0.8.0-beta.0",
20
- "ws": "8.7.0",
21
- "remotion": "4.0.175"
20
+ "ws": "8.17.1",
21
+ "remotion": "4.0.177"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "react": ">=16.8.0",
@@ -41,16 +41,16 @@
41
41
  "react-dom": "18.3.1",
42
42
  "vitest": "0.31.1",
43
43
  "@types/ws": "8.5.10",
44
- "@remotion/streaming": "4.0.175"
44
+ "@remotion/streaming": "4.0.177"
45
45
  },
46
46
  "optionalDependencies": {
47
- "@remotion/compositor-linux-arm64-gnu": "4.0.175",
48
- "@remotion/compositor-darwin-arm64": "4.0.175",
49
- "@remotion/compositor-linux-x64-gnu": "4.0.175",
50
- "@remotion/compositor-darwin-x64": "4.0.175",
51
- "@remotion/compositor-linux-x64-musl": "4.0.175",
52
- "@remotion/compositor-win32-x64-msvc": "4.0.175",
53
- "@remotion/compositor-linux-arm64-musl": "4.0.175"
47
+ "@remotion/compositor-darwin-arm64": "4.0.177",
48
+ "@remotion/compositor-linux-arm64-gnu": "4.0.177",
49
+ "@remotion/compositor-darwin-x64": "4.0.177",
50
+ "@remotion/compositor-linux-arm64-musl": "4.0.177",
51
+ "@remotion/compositor-linux-x64-gnu": "4.0.177",
52
+ "@remotion/compositor-linux-x64-musl": "4.0.177",
53
+ "@remotion/compositor-win32-x64-msvc": "4.0.177"
54
54
  },
55
55
  "keywords": [
56
56
  "remotion",