@remotion/renderer 3.2.44 → 3.3.0

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 (77) hide show
  1. package/dist/assets/download-and-map-assets-to-file.js +7 -7
  2. package/dist/assets/get-audio-channels.d.ts +1 -1
  3. package/dist/assets/get-audio-channels.js +5 -4
  4. package/dist/assets/get-video-stream-duration.d.ts +1 -1
  5. package/dist/assets/get-video-stream-duration.js +5 -4
  6. package/dist/browser/Browser.d.ts +4 -2
  7. package/dist/browser/Browser.js +16 -12
  8. package/dist/browser/BrowserFetcher.d.ts +1 -0
  9. package/dist/browser/BrowserFetcher.js +11 -10
  10. package/dist/browser/BrowserPage.d.ts +8 -2
  11. package/dist/browser/BrowserPage.js +7 -10
  12. package/dist/browser/Connection.js +1 -1
  13. package/dist/browser/DOMWorld.d.ts +2 -1
  14. package/dist/browser/DOMWorld.js +8 -1
  15. package/dist/browser/FrameManager.d.ts +0 -2
  16. package/dist/browser/FrameManager.js +0 -3
  17. package/dist/browser/Launcher.d.ts +7 -1
  18. package/dist/browser/Launcher.js +3 -5
  19. package/dist/browser/NodeWebSocketTransport.js +1 -1
  20. package/dist/browser/PuppeteerNode.js +2 -6
  21. package/dist/combine-videos.d.ts +7 -2
  22. package/dist/combine-videos.js +4 -2
  23. package/dist/convert-to-pcm.d.ts +2 -1
  24. package/dist/convert-to-pcm.js +3 -2
  25. package/dist/create-silent-audio.d.ts +2 -1
  26. package/dist/create-silent-audio.js +3 -2
  27. package/dist/cycle-browser-tabs.d.ts +2 -5
  28. package/dist/cycle-browser-tabs.js +5 -5
  29. package/dist/ensure-ffmpeg.d.ts +10 -0
  30. package/dist/ensure-ffmpeg.js +50 -0
  31. package/dist/ensure-presentation-timestamp.d.ts +8 -1
  32. package/dist/ensure-presentation-timestamp.js +14 -5
  33. package/dist/extract-frame-from-video.d.ts +1 -1
  34. package/dist/extract-frame-from-video.js +22 -9
  35. package/dist/ffmpeg-flags.d.ts +16 -1
  36. package/dist/ffmpeg-flags.js +168 -7
  37. package/dist/get-browser-instance.js +1 -1
  38. package/dist/get-compositions.js +10 -6
  39. package/dist/get-extension-from-codec.d.ts +1 -1
  40. package/dist/get-video-info.d.ts +1 -1
  41. package/dist/get-video-info.js +5 -4
  42. package/dist/guess-extension-for-media.d.ts +5 -1
  43. package/dist/guess-extension-for-media.js +3 -2
  44. package/dist/index.d.ts +10 -4
  45. package/dist/index.js +7 -1
  46. package/dist/last-frame-from-video-cache.d.ts +1 -1
  47. package/dist/merge-audio-track.d.ts +1 -0
  48. package/dist/merge-audio-track.js +7 -2
  49. package/dist/offthread-video-server.d.ts +2 -1
  50. package/dist/offthread-video-server.js +2 -1
  51. package/dist/open-browser.js +1 -1
  52. package/dist/prepare-server.d.ts +2 -1
  53. package/dist/prepare-server.js +3 -1
  54. package/dist/preprocess-audio-track.d.ts +1 -0
  55. package/dist/preprocess-audio-track.js +4 -3
  56. package/dist/prespawn-ffmpeg.d.ts +1 -1
  57. package/dist/prespawn-ffmpeg.js +4 -3
  58. package/dist/provide-screenshot.d.ts +0 -1
  59. package/dist/puppeteer-screenshot.d.ts +0 -1
  60. package/dist/puppeteer-screenshot.js +1 -1
  61. package/dist/render-frames.js +43 -28
  62. package/dist/render-media.js +4 -2
  63. package/dist/render-still.js +3 -1
  64. package/dist/replace-browser.d.ts +1 -1
  65. package/dist/replace-browser.js +3 -2
  66. package/dist/screenshot-dom-element.d.ts +0 -1
  67. package/dist/screenshot-task.d.ts +1 -2
  68. package/dist/screenshot-task.js +3 -3
  69. package/dist/seek-to-frame.d.ts +1 -0
  70. package/dist/seek-to-frame.js +24 -3
  71. package/dist/serve-static.d.ts +1 -0
  72. package/dist/serve-static.js +1 -0
  73. package/dist/stitch-frames-to-video.d.ts +7 -0
  74. package/dist/stitch-frames-to-video.js +27 -20
  75. package/dist/validate-ffmpeg.d.ts +4 -2
  76. package/dist/validate-ffmpeg.js +35 -46
  77. package/package.json +3 -3
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export { BrowserLog } from './browser-log';
11
11
  export { Codec, CodecOrUndefined } from './codec';
12
12
  export { combineVideos } from './combine-videos';
13
13
  export { Crf } from './crf';
14
+ export { ensureFfmpeg, EnsureFfmpegOptions, ensureFfprobe, } from './ensure-ffmpeg';
14
15
  export { ErrorWithStackFrame } from './error-handling/handle-javascript-exception';
15
16
  export { FfmpegExecutable } from './ffmpeg-executable';
16
17
  export { FfmpegVersion } from './ffmpeg-flags';
@@ -34,12 +35,13 @@ export { OpenGlRenderer } from './validate-opengl-renderer';
34
35
  export { validateOutputFilename } from './validate-output-filename';
35
36
  export declare const RenderInternals: {
36
37
  ensureLocalBrowser: (browser: import("./browser").Browser, preferredBrowserExecutable: import("./browser-executable").BrowserExecutable) => Promise<void>;
37
- ffmpegHasFeature: ({ ffmpegExecutable, feature, }: {
38
+ ffmpegHasFeature: ({ ffmpegExecutable, feature, remotionRoot, }: {
38
39
  ffmpegExecutable: string | null;
39
40
  feature: "enable-gpl" | "enable-libx265" | "enable-libvpx";
41
+ remotionRoot: string;
40
42
  }) => Promise<boolean>;
41
43
  getActualConcurrency: (userPreference: number | null) => number;
42
- validateFfmpeg: (customFfmpegBinary: string | null) => Promise<void>;
44
+ validateFfmpeg: (customFfmpegBinary: string | null, remotionRoot: string, binary: "ffmpeg" | "ffprobe") => Promise<void>;
43
45
  serveStatic: (path: string | null, options: {
44
46
  port: number | null;
45
47
  ffmpegExecutable: import("./ffmpeg-executable").FfmpegExecutable;
@@ -47,6 +49,7 @@ export declare const RenderInternals: {
47
49
  onDownload: import("./assets/download-and-map-assets-to-file").RenderMediaOnDownload;
48
50
  onError: (err: Error) => void;
49
51
  downloadMap: import("./assets/download-map").DownloadMap;
52
+ remotionRoot: string;
50
53
  }) => Promise<{
51
54
  port: number;
52
55
  close: () => Promise<void>;
@@ -111,8 +114,8 @@ export declare const RenderInternals: {
111
114
  validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
112
115
  DEFAULT_BROWSER: import("./browser").Browser;
113
116
  validateFrameRange: (frameRange: import("./frame-range").FrameRange | null) => void;
114
- DEFAULT_OPENGL_RENDERER: "swangle" | "angle" | "egl" | "swiftshader" | null;
115
- validateOpenGlRenderer: (option: "swangle" | "angle" | "egl" | "swiftshader" | null) => "swangle" | "angle" | "egl" | "swiftshader" | null;
117
+ DEFAULT_OPENGL_RENDERER: "angle" | "swangle" | "egl" | "swiftshader" | null;
118
+ validateOpenGlRenderer: (option: "angle" | "swangle" | "egl" | "swiftshader" | null) => "angle" | "swangle" | "egl" | "swiftshader" | null;
116
119
  validImageFormats: readonly ["png", "jpeg", "none"];
117
120
  validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "gif"];
118
121
  DEFAULT_PIXEL_FORMAT: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
@@ -131,8 +134,11 @@ export declare const RenderInternals: {
131
134
  frame: number;
132
135
  durationInFrames: number;
133
136
  }) => number;
137
+ findRemotionRoot: () => string;
138
+ getExecutableBinary: (ffmpegExecutable: import("./ffmpeg-executable").FfmpegExecutable, remotionRoot: string, binary: "ffmpeg" | "ffprobe") => string | Promise<string>;
134
139
  validateBitrate: (bitrate: unknown, name: string) => void;
135
140
  getFfmpegVersion: (options: {
136
141
  ffmpegExecutable: string | null;
142
+ remotionRoot: string;
137
143
  }) => Promise<import("./ffmpeg-flags").FfmpegVersion>;
138
144
  };
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.RenderInternals = exports.validateOutputFilename = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.validImageFormats = exports.validateSelectedPixelFormatAndImageFormatCombination = exports.getCompositions = exports.ErrorWithStackFrame = exports.combineVideos = void 0;
29
+ exports.RenderInternals = exports.validateOutputFilename = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.validImageFormats = exports.validateSelectedPixelFormatAndImageFormatCombination = exports.getCompositions = exports.ErrorWithStackFrame = exports.ensureFfprobe = exports.ensureFfmpeg = exports.combineVideos = void 0;
30
30
  const execa_1 = __importDefault(require("execa"));
31
31
  const download_file_1 = require("./assets/download-file");
32
32
  const download_map_1 = require("./assets/download-map");
@@ -41,6 +41,7 @@ const ensure_output_directory_1 = require("./ensure-output-directory");
41
41
  const symbolicate_error_1 = require("./error-handling/symbolicate-error");
42
42
  const symbolicateable_error_1 = require("./error-handling/symbolicateable-error");
43
43
  const ffmpeg_flags_1 = require("./ffmpeg-flags");
44
+ const find_closest_package_json_1 = require("./find-closest-package-json");
44
45
  const frame_range_1 = require("./frame-range");
45
46
  const get_concurrency_1 = require("./get-concurrency");
46
47
  const get_duration_from_frame_range_1 = require("./get-duration-from-frame-range");
@@ -72,6 +73,9 @@ const validate_videobitrate_1 = require("./validate-videobitrate");
72
73
  const wait_for_symbolication_error_to_be_done_1 = require("./wait-for-symbolication-error-to-be-done");
73
74
  var combine_videos_1 = require("./combine-videos");
74
75
  Object.defineProperty(exports, "combineVideos", { enumerable: true, get: function () { return combine_videos_1.combineVideos; } });
76
+ var ensure_ffmpeg_1 = require("./ensure-ffmpeg");
77
+ Object.defineProperty(exports, "ensureFfmpeg", { enumerable: true, get: function () { return ensure_ffmpeg_1.ensureFfmpeg; } });
78
+ Object.defineProperty(exports, "ensureFfprobe", { enumerable: true, get: function () { return ensure_ffmpeg_1.ensureFfprobe; } });
75
79
  var handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
76
80
  Object.defineProperty(exports, "ErrorWithStackFrame", { enumerable: true, get: function () { return handle_javascript_exception_1.ErrorWithStackFrame; } });
77
81
  var get_compositions_1 = require("./get-compositions");
@@ -143,6 +147,8 @@ exports.RenderInternals = {
143
147
  makeDownloadMap: download_map_1.makeDownloadMap,
144
148
  cleanDownloadMap: download_map_1.cleanDownloadMap,
145
149
  convertToPositiveFrameIndex: convert_to_positive_frame_index_1.convertToPositiveFrameIndex,
150
+ findRemotionRoot: find_closest_package_json_1.findRemotionRoot,
151
+ getExecutableBinary: ffmpeg_flags_1.getExecutableBinary,
146
152
  validateBitrate: validate_videobitrate_1.validateBitrate,
147
153
  getFfmpegVersion: ffmpeg_flags_1.getFfmpegVersion,
148
154
  };
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { OffthreadVideoImageFormat } from 'remotion';
3
2
  import type { DownloadMap, SpecialVCodecForTransparency } from './assets/download-map';
4
3
  import type { FfmpegExecutable } from './ffmpeg-executable';
@@ -11,6 +10,7 @@ export declare type LastFrameOptions = {
11
10
  imageFormat: OffthreadVideoImageFormat;
12
11
  needsResize: [number, number] | null;
13
12
  downloadMap: DownloadMap;
13
+ remotionRoot: string;
14
14
  };
15
15
  export declare const setLastFrameInCache: (options: LastFrameOptions, data: Buffer) => void;
16
16
  export declare const getLastFrameFromCache: (options: LastFrameOptions) => Buffer | null;
@@ -6,6 +6,7 @@ declare type Options = {
6
6
  outName: string;
7
7
  numberOfSeconds: number;
8
8
  downloadMap: DownloadMap;
9
+ remotionRoot: string;
9
10
  };
10
11
  export declare const mergeAudioTrack: (options: Options) => Promise<void>;
11
12
  export {};
@@ -11,15 +11,17 @@ const convert_to_pcm_1 = require("./convert-to-pcm");
11
11
  const create_ffmpeg_complex_filter_1 = require("./create-ffmpeg-complex-filter");
12
12
  const create_silent_audio_1 = require("./create-silent-audio");
13
13
  const delete_directory_1 = require("./delete-directory");
14
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
14
15
  const p_limit_1 = require("./p-limit");
15
16
  const tmp_dir_1 = require("./tmp-dir");
16
17
  const truthy_1 = require("./truthy");
17
- const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numberOfSeconds, downloadMap, }) => {
18
+ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numberOfSeconds, downloadMap, remotionRoot, }) => {
18
19
  if (files.length === 0) {
19
20
  await (0, create_silent_audio_1.createSilentAudio)({
20
21
  outName,
21
22
  ffmpegExecutable,
22
23
  numberOfSeconds,
24
+ remotionRoot,
23
25
  });
24
26
  return;
25
27
  }
@@ -28,6 +30,7 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
28
30
  outName,
29
31
  ffmpegExecutable,
30
32
  input: files[0],
33
+ remotionRoot,
31
34
  });
32
35
  return;
33
36
  }
@@ -43,6 +46,7 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
43
46
  numberOfSeconds,
44
47
  outName: chunkOutname,
45
48
  downloadMap,
49
+ remotionRoot,
46
50
  });
47
51
  return chunkOutname;
48
52
  }));
@@ -52,6 +56,7 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
52
56
  numberOfSeconds,
53
57
  outName,
54
58
  downloadMap,
59
+ remotionRoot,
55
60
  });
56
61
  await (0, delete_directory_1.deleteDirectory)(tempPath);
57
62
  return;
@@ -66,7 +71,7 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
66
71
  ]
67
72
  .filter(truthy_1.truthy)
68
73
  .flat(2);
69
- const task = (0, execa_1.default)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : 'ffmpeg', args);
74
+ const task = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), args);
70
75
  await task;
71
76
  cleanup();
72
77
  };
@@ -8,10 +8,11 @@ export declare const extractUrlAndSourceFromUrl: (url: string) => {
8
8
  time: number;
9
9
  imageFormat: OffthreadVideoImageFormat;
10
10
  };
11
- export declare const startOffthreadVideoServer: ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, downloadMap, }: {
11
+ export declare const startOffthreadVideoServer: ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, downloadMap, remotionRoot, }: {
12
12
  ffmpegExecutable: FfmpegExecutable;
13
13
  ffprobeExecutable: FfmpegExecutable;
14
14
  onDownload: RenderMediaOnDownload;
15
15
  onError: (err: Error) => void;
16
16
  downloadMap: DownloadMap;
17
+ remotionRoot: string;
17
18
  }) => RequestListener;
@@ -32,7 +32,7 @@ const extractUrlAndSourceFromUrl = (url) => {
32
32
  };
33
33
  };
34
34
  exports.extractUrlAndSourceFromUrl = extractUrlAndSourceFromUrl;
35
- const startOffthreadVideoServer = ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, downloadMap, }) => {
35
+ const startOffthreadVideoServer = ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, downloadMap, remotionRoot, }) => {
36
36
  return (req, res) => {
37
37
  if (!req.url) {
38
38
  throw new Error('Request came in without URL');
@@ -65,6 +65,7 @@ const startOffthreadVideoServer = ({ ffmpegExecutable, ffprobeExecutable, onDown
65
65
  ffprobeExecutable,
66
66
  imageFormat,
67
67
  downloadMap,
68
+ remotionRoot,
68
69
  });
69
70
  })
70
71
  .then((readable) => {
@@ -21,7 +21,7 @@ const browserInstances = [];
21
21
  const killAllBrowsers = async () => {
22
22
  for (const browser of browserInstances) {
23
23
  try {
24
- await browser.close();
24
+ await browser.close(true);
25
25
  }
26
26
  catch (err) { }
27
27
  }
@@ -1,7 +1,7 @@
1
1
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
2
2
  import type { DownloadMap } from './assets/download-map';
3
3
  import type { FfmpegExecutable } from './ffmpeg-executable';
4
- export declare const prepareServer: ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, downloadMap, }: {
4
+ export declare const prepareServer: ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, downloadMap, remotionRoot, }: {
5
5
  webpackConfigOrServeUrl: string;
6
6
  onDownload: RenderMediaOnDownload;
7
7
  onError: (err: Error) => void;
@@ -9,6 +9,7 @@ export declare const prepareServer: ({ ffmpegExecutable, ffprobeExecutable, onDo
9
9
  ffprobeExecutable: FfmpegExecutable;
10
10
  port: number | null;
11
11
  downloadMap: DownloadMap;
12
+ remotionRoot: string;
12
13
  }) => Promise<{
13
14
  serveUrl: string;
14
15
  closeServer: () => Promise<unknown>;
@@ -9,7 +9,7 @@ const path_1 = __importDefault(require("path"));
9
9
  const is_serve_url_1 = require("./is-serve-url");
10
10
  const serve_static_1 = require("./serve-static");
11
11
  const wait_for_symbolication_error_to_be_done_1 = require("./wait-for-symbolication-error-to-be-done");
12
- const prepareServer = async ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, downloadMap, }) => {
12
+ const prepareServer = async ({ ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, downloadMap, remotionRoot, }) => {
13
13
  if ((0, is_serve_url_1.isServeUrl)(webpackConfigOrServeUrl)) {
14
14
  const { port: offthreadPort, close: closeProxy } = await (0, serve_static_1.serveStatic)(null, {
15
15
  onDownload,
@@ -18,6 +18,7 @@ const prepareServer = async ({ ffmpegExecutable, ffprobeExecutable, onDownload,
18
18
  ffprobeExecutable,
19
19
  port,
20
20
  downloadMap,
21
+ remotionRoot,
21
22
  });
22
23
  return Promise.resolve({
23
24
  serveUrl: webpackConfigOrServeUrl,
@@ -40,6 +41,7 @@ const prepareServer = async ({ ffmpegExecutable, ffprobeExecutable, onDownload,
40
41
  ffprobeExecutable,
41
42
  port,
42
43
  downloadMap,
44
+ remotionRoot,
43
45
  });
44
46
  return Promise.resolve({
45
47
  closeServer: () => {
@@ -9,6 +9,7 @@ declare type Options = {
9
9
  expectedFrames: number;
10
10
  fps: number;
11
11
  downloadMap: DownloadMap;
12
+ remotionRoot: string;
12
13
  };
13
14
  export declare const preprocessAudioTrack: (options: Options) => Promise<string | null>;
14
15
  export {};
@@ -8,10 +8,11 @@ const execa_1 = __importDefault(require("execa"));
8
8
  const get_audio_channels_1 = require("./assets/get-audio-channels");
9
9
  const calculate_ffmpeg_filters_1 = require("./calculate-ffmpeg-filters");
10
10
  const ffmpeg_filter_file_1 = require("./ffmpeg-filter-file");
11
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
11
12
  const p_limit_1 = require("./p-limit");
12
13
  const resolve_asset_src_1 = require("./resolve-asset-src");
13
- const preprocessAudioTrackUnlimited = async ({ ffmpegExecutable, ffprobeExecutable, outName, asset, expectedFrames, fps, downloadMap, }) => {
14
- const { channels, duration } = await (0, get_audio_channels_1.getAudioChannelsAndDuration)(downloadMap, (0, resolve_asset_src_1.resolveAssetSrc)(asset.src), ffprobeExecutable);
14
+ const preprocessAudioTrackUnlimited = async ({ ffmpegExecutable, ffprobeExecutable, outName, asset, expectedFrames, fps, downloadMap, remotionRoot, }) => {
15
+ const { channels, duration } = await (0, get_audio_channels_1.getAudioChannelsAndDuration)(downloadMap, (0, resolve_asset_src_1.resolveAssetSrc)(asset.src), ffprobeExecutable, remotionRoot);
15
16
  const filter = (0, calculate_ffmpeg_filters_1.calculateFfmpegFilter)({
16
17
  asset,
17
18
  durationInFrames: expectedFrames,
@@ -30,7 +31,7 @@ const preprocessAudioTrackUnlimited = async ({ ffmpegExecutable, ffprobeExecutab
30
31
  ['-c:a', 'pcm_s16le'],
31
32
  ['-y', outName],
32
33
  ].flat(2);
33
- await (0, execa_1.default)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : 'ffmpeg', args);
34
+ await (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), args);
34
35
  cleanup();
35
36
  return outName;
36
37
  };
@@ -23,7 +23,7 @@ declare type PreSticherOptions = {
23
23
  signal: CancelSignal;
24
24
  videoBitrate: string | null;
25
25
  };
26
- export declare const prespawnFfmpeg: (options: PreSticherOptions) => Promise<{
26
+ export declare const prespawnFfmpeg: (options: PreSticherOptions, remotionRoot: string) => Promise<{
27
27
  task: execa.ExecaChildProcess<string>;
28
28
  getLogs: () => string;
29
29
  }>;
@@ -8,13 +8,14 @@ const execa_1 = __importDefault(require("execa"));
8
8
  const remotion_1 = require("remotion");
9
9
  const codec_1 = require("./codec");
10
10
  const crf_1 = require("./crf");
11
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
11
12
  const get_codec_name_1 = require("./get-codec-name");
12
13
  const get_prores_profile_name_1 = require("./get-prores-profile-name");
13
14
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
14
15
  const pixel_format_1 = require("./pixel-format");
15
16
  const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
16
17
  const validate_ffmpeg_1 = require("./validate-ffmpeg");
17
- const prespawnFfmpeg = async (options) => {
18
+ const prespawnFfmpeg = async (options, remotionRoot) => {
18
19
  var _a, _b, _c, _d, _e, _f;
19
20
  remotion_1.Internals.validateDimension(options.height, 'height', 'passed to `stitchFramesToVideo()`');
20
21
  remotion_1.Internals.validateDimension(options.width, 'width', 'passed to `stitchFramesToVideo()`');
@@ -27,7 +28,7 @@ const prespawnFfmpeg = async (options) => {
27
28
  scale: 1,
28
29
  });
29
30
  const pixelFormat = (_b = options.pixelFormat) !== null && _b !== void 0 ? _b : pixel_format_1.DEFAULT_PIXEL_FORMAT;
30
- await (0, validate_ffmpeg_1.validateFfmpeg)((_c = options.ffmpegExecutable) !== null && _c !== void 0 ? _c : null);
31
+ await (0, validate_ffmpeg_1.validateFfmpeg)((_c = options.ffmpegExecutable) !== null && _c !== void 0 ? _c : null, remotionRoot, 'ffmpeg');
31
32
  const encoderName = (0, get_codec_name_1.getCodecName)(codec);
32
33
  const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec, options.proResProfile);
33
34
  if (encoderName === null) {
@@ -79,7 +80,7 @@ const prespawnFfmpeg = async (options) => {
79
80
  const finalFfmpegString = options.ffmpegOverride
80
81
  ? options.ffmpegOverride({ type: 'pre-stitcher', args: ffmpegString })
81
82
  : ffmpegString;
82
- const task = (0, execa_1.default)((_e = options.ffmpegExecutable) !== null && _e !== void 0 ? _e : 'ffmpeg', finalFfmpegString);
83
+ const task = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)((_e = options.ffmpegExecutable) !== null && _e !== void 0 ? _e : null, remotionRoot, 'ffmpeg'), finalFfmpegString);
83
84
  options.signal(() => {
84
85
  task.kill();
85
86
  });
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ImageFormat } from './image-format';
4
3
  export declare const provideScreenshot: ({ page, imageFormat, options, quality, }: {
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
4
3
  export declare const screenshot: (page: Page, options: ScreenshotOptions) => Promise<Buffer | string | void>;
@@ -70,6 +70,6 @@ const screenshot = (page, options) => {
70
70
  assert.ok(options.clip.width !== 0, 'Expected options.clip.width not to be 0.');
71
71
  assert.ok(options.clip.height !== 0, 'Expected options.clip.height not to be 0.');
72
72
  }
73
- return page.screenshotTaskQueue.postTask(() => (0, screenshot_task_1._screenshotTask)(page, screenshotType, options));
73
+ return page.screenshotTaskQueue.postTask(() => (0, screenshot_task_1.screenshotTask)(page, screenshotType, options));
74
74
  };
75
75
  exports.screenshot = screenshot;
@@ -14,6 +14,7 @@ const browser_1 = require("./browser");
14
14
  const compress_assets_1 = require("./compress-assets");
15
15
  const cycle_browser_tabs_1 = require("./cycle-browser-tabs");
16
16
  const handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
17
+ const find_closest_package_json_1 = require("./find-closest-package-json");
17
18
  const get_concurrency_1 = require("./get-concurrency");
18
19
  const get_duration_from_frame_range_1 = require("./get-duration-from-frame-range");
19
20
  const get_frame_padded_index_1 = require("./get-frame-padded-index");
@@ -27,6 +28,7 @@ const prepare_server_1 = require("./prepare-server");
27
28
  const provide_screenshot_1 = require("./provide-screenshot");
28
29
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
29
30
  const quality_1 = require("./quality");
31
+ const replace_browser_1 = require("./replace-browser");
30
32
  const seek_to_frame_1 = require("./seek-to-frame");
31
33
  const set_props_and_env_1 = require("./set-props-and-env");
32
34
  const truthy_1 = require("./truthy");
@@ -50,15 +52,7 @@ const getConcurrency = (others) => {
50
52
  }
51
53
  return undefined;
52
54
  };
53
- const getPool = async (pages) => {
54
- const puppeteerPages = await Promise.all(pages);
55
- const pool = new pool_1.Pool(puppeteerPages);
56
- return pool;
57
- };
58
- const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, quality, imageFormat = image_format_1.DEFAULT_IMAGE_FORMAT, frameRange, puppeteerInstance, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualConcurrency, everyNthFrame = 1, proxyPort, cancelSignal, downloadMap, muted, }) => {
59
- if (!puppeteerInstance) {
60
- throw new Error('no puppeteer instance passed to innerRenderFrames - internal error');
61
- }
55
+ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, quality, imageFormat = image_format_1.DEFAULT_IMAGE_FORMAT, frameRange, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualConcurrency, everyNthFrame = 1, proxyPort, cancelSignal, downloadMap, muted, makeBrowser, browserReplacer, }) => {
62
56
  if (outputDir) {
63
57
  if (!fs_1.default.existsSync(outputDir)) {
64
58
  fs_1.default.mkdirSync(outputDir, {
@@ -71,7 +65,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
71
65
  const framesToRender = (0, get_duration_from_frame_range_1.getFramesToRender)(realFrameRange, everyNthFrame);
72
66
  const lastFrame = framesToRender[framesToRender.length - 1];
73
67
  const makePage = async () => {
74
- const page = await puppeteerInstance.newPage();
68
+ const page = await browserReplacer.getBrowser().newPage();
75
69
  pagesArray.push(page);
76
70
  await page.setViewport({
77
71
  width: composition.width,
@@ -128,7 +122,12 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
128
122
  page.off('console', logCallback);
129
123
  return page;
130
124
  };
131
- const pages = new Array(actualConcurrency).fill(true).map(makePage);
125
+ const getPool = async () => {
126
+ const pages = new Array(actualConcurrency).fill(true).map(() => makePage());
127
+ const puppeteerPages = await Promise.all(pages);
128
+ const pool = new pool_1.Pool(puppeteerPages);
129
+ return pool;
130
+ };
132
131
  // If rendering a GIF and skipping frames, we must ensure it starts from 0
133
132
  // and then is consecutive so FFMPEG recognizes the sequence
134
133
  const countType = everyNthFrame === 1 ? 'actual-frames' : 'from-zero';
@@ -138,7 +137,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
138
137
  countType,
139
138
  });
140
139
  let framesRendered = 0;
141
- const poolPromise = getPool(pages);
140
+ const poolPromise = getPool();
142
141
  onStart({
143
142
  frameCount: framesToRender.length,
144
143
  });
@@ -239,12 +238,13 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
239
238
  });
240
239
  };
241
240
  const renderFrameAndRetryTargetClose = async (frame, index, retriesLeft, attempt) => {
242
- var _a;
241
+ var _a, _b;
243
242
  try {
244
243
  await renderFrame(frame, index);
245
244
  }
246
245
  catch (err) {
247
- if (!((_a = err === null || err === void 0 ? void 0 : err.message) === null || _a === void 0 ? void 0 : _a.includes('Target closed'))) {
246
+ if (!((_a = err === null || err === void 0 ? void 0 : err.message) === null || _a === void 0 ? void 0 : _a.includes('Target closed')) &&
247
+ !((_b = err === null || err === void 0 ? void 0 : err.message) === null || _b === void 0 ? void 0 : _b.includes('Session closed'))) {
248
248
  throw err;
249
249
  }
250
250
  if (retriesLeft === 0) {
@@ -252,9 +252,16 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
252
252
  throw err;
253
253
  }
254
254
  console.warn(`The browser crashed while rendering frame ${frame}, retrying ${retriesLeft} more times. Learn more about this error under https://www.remotion.dev/docs/target-closed`);
255
- const pool = await poolPromise;
256
- const page = await makePage();
257
- pool.release(page);
255
+ await browserReplacer.replaceBrowser(makeBrowser, async () => {
256
+ const pages = new Array(actualConcurrency)
257
+ .fill(true)
258
+ .map(() => makePage());
259
+ const puppeteerPages = await Promise.all(pages);
260
+ const pool = await poolPromise;
261
+ for (const newPage of puppeteerPages) {
262
+ pool.release(newPage);
263
+ }
264
+ });
258
265
  await renderFrameAndRetryTargetClose(frame, index, retriesLeft - 1, attempt + 1);
259
266
  }
260
267
  };
@@ -279,7 +286,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
279
286
  .then(() => happyPath);
280
287
  };
281
288
  const renderFrames = (options) => {
282
- var _a, _b, _c, _d;
289
+ var _a, _b, _c;
283
290
  const composition = getComposition(options);
284
291
  const concurrency = getConcurrency(options);
285
292
  if (!composition) {
@@ -295,14 +302,18 @@ const renderFrames = (options) => {
295
302
  const selectedServeUrl = (0, legacy_webpack_config_1.getServeUrlWithFallback)(options);
296
303
  (0, quality_1.validateQuality)(options.quality);
297
304
  (0, validate_scale_1.validateScale)(options.scale);
298
- const browserInstance = (_a = options.puppeteerInstance) !== null && _a !== void 0 ? _a : (0, open_browser_1.openBrowser)(browser_1.DEFAULT_BROWSER, {
299
- shouldDumpIo: options.dumpBrowserLogs,
300
- browserExecutable: options.browserExecutable,
301
- chromiumOptions: options.chromiumOptions,
302
- forceDeviceScaleFactor: (_b = options.scale) !== null && _b !== void 0 ? _b : 1,
303
- });
304
- const downloadMap = (_c = options.downloadMap) !== null && _c !== void 0 ? _c : (0, download_map_1.makeDownloadMap)();
305
- const onDownload = (_d = options.onDownload) !== null && _d !== void 0 ? _d : (() => () => undefined);
305
+ const makeBrowser = () => {
306
+ var _a;
307
+ return (0, open_browser_1.openBrowser)(browser_1.DEFAULT_BROWSER, {
308
+ shouldDumpIo: options.dumpBrowserLogs,
309
+ browserExecutable: options.browserExecutable,
310
+ chromiumOptions: options.chromiumOptions,
311
+ forceDeviceScaleFactor: (_a = options.scale) !== null && _a !== void 0 ? _a : 1,
312
+ });
313
+ };
314
+ const browserInstance = (_a = options.puppeteerInstance) !== null && _a !== void 0 ? _a : makeBrowser();
315
+ const downloadMap = (_b = options.downloadMap) !== null && _b !== void 0 ? _b : (0, download_map_1.makeDownloadMap)();
316
+ const onDownload = (_c = options.onDownload) !== null && _c !== void 0 ? _c : (() => () => undefined);
306
317
  const actualConcurrency = (0, get_concurrency_1.getActualConcurrency)(concurrency !== null && concurrency !== void 0 ? concurrency : null);
307
318
  const openedPages = [];
308
319
  return new Promise((resolve, reject) => {
@@ -327,10 +338,12 @@ const renderFrames = (options) => {
327
338
  ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
328
339
  port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
329
340
  downloadMap,
341
+ remotionRoot: (0, find_closest_package_json_1.findRemotionRoot)(),
330
342
  }),
331
343
  browserInstance,
332
344
  ]).then(([{ serveUrl, closeServer, offthreadPort }, puppeteerInstance]) => {
333
- const { stopCycling } = (0, cycle_browser_tabs_1.cycleBrowserTabs)(puppeteerInstance, actualConcurrency);
345
+ const browserReplacer = (0, replace_browser_1.handleBrowserCrash)(puppeteerInstance);
346
+ const { stopCycling } = (0, cycle_browser_tabs_1.cycleBrowserTabs)(browserReplacer, actualConcurrency);
334
347
  cleanup.push(stopCycling);
335
348
  cleanup.push(closeServer);
336
349
  return innerRenderFrames({
@@ -344,6 +357,8 @@ const renderFrames = (options) => {
344
357
  onDownload,
345
358
  proxyPort: offthreadPort,
346
359
  downloadMap,
360
+ makeBrowser,
361
+ browserReplacer,
347
362
  });
348
363
  }),
349
364
  ])
@@ -363,7 +378,7 @@ const renderFrames = (options) => {
363
378
  else {
364
379
  Promise.resolve(browserInstance)
365
380
  .then((puppeteerInstance) => {
366
- return puppeteerInstance.close();
381
+ return puppeteerInstance.close(true);
367
382
  })
368
383
  .catch((err) => {
369
384
  console.log('Unable to close browser', err);
@@ -15,6 +15,7 @@ const crf_1 = require("./crf");
15
15
  const delete_directory_1 = require("./delete-directory");
16
16
  const ensure_frames_in_order_1 = require("./ensure-frames-in-order");
17
17
  const ensure_output_directory_1 = require("./ensure-output-directory");
18
+ const find_closest_package_json_1 = require("./find-closest-package-json");
18
19
  const get_duration_from_frame_range_1 = require("./get-duration-from-frame-range");
19
20
  const get_extension_from_codec_1 = require("./get-extension-from-codec");
20
21
  const get_extension_of_filename_1 = require("./get-extension-of-filename");
@@ -56,7 +57,8 @@ const getConcurrency = (others) => {
56
57
  */
57
58
  const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, onSlowestFrames, ...options }) => {
58
59
  var _a, _b, _c, _d;
59
- (0, validate_ffmpeg_1.validateFfmpeg)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null);
60
+ const remotionRoot = (0, find_closest_package_json_1.findRemotionRoot)();
61
+ (0, validate_ffmpeg_1.validateFfmpeg)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null, remotionRoot, 'ffmpeg');
60
62
  (0, quality_1.validateQuality)(options.quality);
61
63
  (0, crf_1.validateQualitySettings)({ crf, codec, videoBitrate });
62
64
  (0, validate_videobitrate_1.validateBitrate)(audioBitrate, 'audioBitrate');
@@ -168,7 +170,7 @@ const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprob
168
170
  signal: cancelPrestitcher.cancelSignal,
169
171
  ffmpegOverride: ffmpegOverride !== null && ffmpegOverride !== void 0 ? ffmpegOverride : (({ args }) => args),
170
172
  videoBitrate: videoBitrate !== null && videoBitrate !== void 0 ? videoBitrate : null,
171
- });
173
+ }, remotionRoot);
172
174
  stitcherFfmpeg = preStitcher.task;
173
175
  }
174
176
  };
@@ -35,6 +35,7 @@ const browser_1 = require("./browser");
35
35
  const convert_to_positive_frame_index_1 = require("./convert-to-positive-frame-index");
36
36
  const ensure_output_directory_1 = require("./ensure-output-directory");
37
37
  const handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
38
+ const find_closest_package_json_1 = require("./find-closest-package-json");
38
39
  const image_format_1 = require("./image-format");
39
40
  const legacy_webpack_config_1 = require("./legacy-webpack-config");
40
41
  const open_browser_1 = require("./open-browser");
@@ -105,7 +106,7 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
105
106
  await page.close();
106
107
  }
107
108
  else {
108
- browserInstance.close().catch((err) => {
109
+ browserInstance.close(true).catch((err) => {
109
110
  console.log('Unable to close browser', err);
110
111
  });
111
112
  }
@@ -183,6 +184,7 @@ const renderStill = (options) => {
183
184
  ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
184
185
  port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
185
186
  downloadMap,
187
+ remotionRoot: (0, find_closest_package_json_1.findRemotionRoot)(),
186
188
  })
187
189
  .then(({ serveUrl, closeServer, offthreadPort }) => {
188
190
  close = closeServer;
@@ -1,6 +1,6 @@
1
1
  import type { Browser } from './browser/Browser';
2
2
  export declare type BrowserReplacer = {
3
3
  getBrowser: () => Browser;
4
- replaceBrowser: (make: () => Promise<Browser>) => Promise<Browser>;
4
+ replaceBrowser: (make: () => Promise<Browser>, makeNewPages: () => Promise<void>) => Promise<Browser>;
5
5
  };
6
6
  export declare const handleBrowserCrash: (instance: Browser) => BrowserReplacer;
@@ -7,7 +7,7 @@ const handleBrowserCrash = (instance) => {
7
7
  let replacing = false;
8
8
  return {
9
9
  getBrowser: () => _instance,
10
- replaceBrowser: async (make) => {
10
+ replaceBrowser: async (make, makeNewPages) => {
11
11
  if (replacing) {
12
12
  const waiter = new Promise((resolve, reject) => {
13
13
  waiters.push({
@@ -19,7 +19,7 @@ const handleBrowserCrash = (instance) => {
19
19
  }
20
20
  try {
21
21
  replacing = true;
22
- await instance
22
+ await _instance
23
23
  .close(true)
24
24
  .then(() => {
25
25
  console.log('Killed previous browser and making new one');
@@ -29,6 +29,7 @@ const handleBrowserCrash = (instance) => {
29
29
  });
30
30
  const browser = await make();
31
31
  _instance = browser;
32
+ await makeNewPages();
32
33
  waiters.forEach((w) => w.resolve(browser));
33
34
  console.log('Made new browser');
34
35
  return browser;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ImageFormat } from './image-format';
4
3
  export declare const screenshotDOMElement: ({ page, imageFormat, quality, opts, }: {
@@ -1,5 +1,4 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
4
3
  import type { StillImageFormat } from './image-format';
5
- export declare const _screenshotTask: (page: Page, format: StillImageFormat, options: ScreenshotOptions) => Promise<Buffer | string>;
4
+ export declare const screenshotTask: (page: Page, format: StillImageFormat, options: ScreenshotOptions) => Promise<Buffer | string>;