@remotion/renderer 3.2.44 → 3.3.1

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/download-file.d.ts +6 -4
  3. package/dist/assets/download-file.js +44 -5
  4. package/dist/assets/get-audio-channels.d.ts +1 -1
  5. package/dist/assets/get-audio-channels.js +5 -4
  6. package/dist/assets/get-video-stream-duration.d.ts +1 -1
  7. package/dist/assets/get-video-stream-duration.js +5 -4
  8. package/dist/browser/Browser.d.ts +4 -2
  9. package/dist/browser/Browser.js +15 -12
  10. package/dist/browser/BrowserFetcher.d.ts +1 -0
  11. package/dist/browser/BrowserFetcher.js +11 -10
  12. package/dist/browser/BrowserPage.d.ts +8 -2
  13. package/dist/browser/BrowserPage.js +7 -10
  14. package/dist/browser/Connection.js +1 -1
  15. package/dist/browser/DOMWorld.d.ts +2 -1
  16. package/dist/browser/DOMWorld.js +8 -1
  17. package/dist/browser/FrameManager.d.ts +0 -2
  18. package/dist/browser/FrameManager.js +0 -3
  19. package/dist/browser/Launcher.d.ts +7 -1
  20. package/dist/browser/Launcher.js +3 -5
  21. package/dist/browser/NodeWebSocketTransport.js +1 -1
  22. package/dist/browser/PuppeteerNode.js +2 -6
  23. package/dist/combine-videos.d.ts +7 -2
  24. package/dist/combine-videos.js +4 -2
  25. package/dist/convert-to-pcm.d.ts +2 -1
  26. package/dist/convert-to-pcm.js +3 -2
  27. package/dist/create-silent-audio.d.ts +2 -1
  28. package/dist/create-silent-audio.js +3 -2
  29. package/dist/cycle-browser-tabs.d.ts +2 -5
  30. package/dist/cycle-browser-tabs.js +5 -5
  31. package/dist/ensure-ffmpeg.d.ts +10 -0
  32. package/dist/ensure-ffmpeg.js +50 -0
  33. package/dist/ensure-presentation-timestamp.d.ts +8 -1
  34. package/dist/ensure-presentation-timestamp.js +14 -5
  35. package/dist/extract-frame-from-video.d.ts +1 -0
  36. package/dist/extract-frame-from-video.js +22 -9
  37. package/dist/ffmpeg-flags.d.ts +16 -1
  38. package/dist/ffmpeg-flags.js +168 -7
  39. package/dist/get-browser-instance.js +1 -1
  40. package/dist/get-compositions.js +10 -6
  41. package/dist/get-extension-from-codec.d.ts +1 -1
  42. package/dist/get-video-info.d.ts +1 -1
  43. package/dist/get-video-info.js +5 -4
  44. package/dist/guess-extension-for-media.d.ts +5 -1
  45. package/dist/guess-extension-for-media.js +3 -2
  46. package/dist/index.d.ts +8 -3
  47. package/dist/index.js +7 -1
  48. package/dist/last-frame-from-video-cache.d.ts +1 -0
  49. package/dist/merge-audio-track.d.ts +1 -0
  50. package/dist/merge-audio-track.js +7 -2
  51. package/dist/offthread-video-server.d.ts +2 -1
  52. package/dist/offthread-video-server.js +2 -1
  53. package/dist/open-browser.js +1 -1
  54. package/dist/prepare-server.d.ts +2 -1
  55. package/dist/prepare-server.js +3 -1
  56. package/dist/preprocess-audio-track.d.ts +1 -0
  57. package/dist/preprocess-audio-track.js +4 -3
  58. package/dist/prespawn-ffmpeg.d.ts +1 -1
  59. package/dist/prespawn-ffmpeg.js +4 -3
  60. package/dist/puppeteer-screenshot.js +1 -1
  61. package/dist/render-frames.js +43 -28
  62. package/dist/render-media.d.ts +1 -0
  63. package/dist/render-media.js +4 -2
  64. package/dist/render-still.js +3 -1
  65. package/dist/replace-browser.d.ts +1 -1
  66. package/dist/replace-browser.js +3 -2
  67. package/dist/screenshot-task.d.ts +1 -1
  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 +55 -24
  75. package/dist/validate-ffmpeg.d.ts +4 -2
  76. package/dist/validate-ffmpeg.js +35 -46
  77. package/package.json +3 -3
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getCompositions = void 0;
4
4
  const download_map_1 = require("./assets/download-map");
5
5
  const handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
6
+ const find_closest_package_json_1 = require("./find-closest-package-json");
6
7
  const get_browser_instance_1 = require("./get-browser-instance");
7
8
  const prepare_server_1 = require("./prepare-server");
8
9
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
10
+ const seek_to_frame_1 = require("./seek-to-frame");
9
11
  const set_props_and_env_1 = require("./set-props-and-env");
10
12
  const validate_ffmpeg_1 = require("./validate-ffmpeg");
11
13
  const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
@@ -43,7 +45,7 @@ const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
43
45
  frame: null,
44
46
  args: [],
45
47
  });
46
- await page.waitForFunction(page.browser, 'window.ready === true');
48
+ await (0, seek_to_frame_1.waitForReady)(page);
47
49
  const result = await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
48
50
  pageFunction: () => {
49
51
  return window.getStaticCompositions();
@@ -55,13 +57,14 @@ const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
55
57
  return result;
56
58
  };
57
59
  const getCompositions = async (serveUrlOrWebpackUrl, config) => {
58
- var _a, _b, _c, _d;
59
- await (0, validate_ffmpeg_1.validateFfmpeg)((_a = config === null || config === void 0 ? void 0 : config.ffmpegExecutable) !== null && _a !== void 0 ? _a : null);
60
- const downloadMap = (_b = config === null || config === void 0 ? void 0 : config.downloadMap) !== null && _b !== void 0 ? _b : (0, download_map_1.makeDownloadMap)();
60
+ var _a, _b, _c, _d, _e;
61
+ await (0, validate_ffmpeg_1.validateFfmpeg)((_a = config === null || config === void 0 ? void 0 : config.ffmpegExecutable) !== null && _a !== void 0 ? _a : null, (0, find_closest_package_json_1.findRemotionRoot)(), 'ffmpeg');
62
+ await (0, validate_ffmpeg_1.validateFfmpeg)((_b = config === null || config === void 0 ? void 0 : config.ffprobeExecutable) !== null && _b !== void 0 ? _b : null, (0, find_closest_package_json_1.findRemotionRoot)(), 'ffprobe');
63
+ const downloadMap = (_c = config === null || config === void 0 ? void 0 : config.downloadMap) !== null && _c !== void 0 ? _c : (0, download_map_1.makeDownloadMap)();
61
64
  const { page, cleanup } = await (0, get_browser_instance_1.getPageAndCleanupFn)({
62
65
  passedInInstance: config === null || config === void 0 ? void 0 : config.puppeteerInstance,
63
- browserExecutable: (_c = config === null || config === void 0 ? void 0 : config.browserExecutable) !== null && _c !== void 0 ? _c : null,
64
- chromiumOptions: (_d = config === null || config === void 0 ? void 0 : config.chromiumOptions) !== null && _d !== void 0 ? _d : {},
66
+ browserExecutable: (_d = config === null || config === void 0 ? void 0 : config.browserExecutable) !== null && _d !== void 0 ? _d : null,
67
+ chromiumOptions: (_e = config === null || config === void 0 ? void 0 : config.chromiumOptions) !== null && _e !== void 0 ? _e : {},
65
68
  });
66
69
  return new Promise((resolve, reject) => {
67
70
  var _a, _b, _c;
@@ -80,6 +83,7 @@ const getCompositions = async (serveUrlOrWebpackUrl, config) => {
80
83
  ffprobeExecutable: (_b = config === null || config === void 0 ? void 0 : config.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
81
84
  port: (_c = config === null || config === void 0 ? void 0 : config.port) !== null && _c !== void 0 ? _c : null,
82
85
  downloadMap,
86
+ remotionRoot: (0, find_closest_package_json_1.findRemotionRoot)(),
83
87
  })
84
88
  .then(({ serveUrl, closeServer, offthreadPort }) => {
85
89
  close = closeServer;
@@ -1,2 +1,2 @@
1
1
  import type { Codec } from './codec';
2
- export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "mp4" | "mkv" | "mov" | "webm";
2
+ export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "webm" | "mp4" | "mov" | "mkv";
@@ -1,3 +1,3 @@
1
1
  import type { DownloadMap, Vp9Result } from './assets/download-map';
2
2
  import type { FfmpegExecutable } from './ffmpeg-executable';
3
- export declare const getVideoInfo: (downloadMap: DownloadMap, src: string, ffprobeExecutable: FfmpegExecutable) => Promise<Vp9Result>;
3
+ export declare const getVideoInfo: (downloadMap: DownloadMap, src: string, ffprobeExecutable: FfmpegExecutable, remotionRoot: string) => Promise<Vp9Result>;
@@ -6,14 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getVideoInfo = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
8
  const calculate_sar_dar_pixels_1 = require("./calculate-sar-dar-pixels");
9
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
9
10
  const p_limit_1 = require("./p-limit");
10
11
  const limit = (0, p_limit_1.pLimit)(1);
11
- async function getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable) {
12
+ async function getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable, remotionRoot) {
12
13
  var _a;
13
14
  if (typeof downloadMap.isVp9VideoCache[src] !== 'undefined') {
14
15
  return downloadMap.isVp9VideoCache[src];
15
16
  }
16
- const task = await (0, execa_1.default)(ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : 'ffprobe', [src]);
17
+ const task = await (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffprobeExecutable, remotionRoot, 'ffprobe'), [src]);
17
18
  const isVp9 = task.stderr.includes('Video: vp9');
18
19
  const isVp8 = task.stderr.includes('Video: vp8');
19
20
  const dimensions = (_a = task.stderr
@@ -43,7 +44,7 @@ async function getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable) {
43
44
  downloadMap.isVp9VideoCache[src] = result;
44
45
  return downloadMap.isVp9VideoCache[src];
45
46
  }
46
- const getVideoInfo = (downloadMap, src, ffprobeExecutable) => {
47
- return limit(() => getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable));
47
+ const getVideoInfo = (downloadMap, src, ffprobeExecutable, remotionRoot) => {
48
+ return limit(() => getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable, remotionRoot));
48
49
  };
49
50
  exports.getVideoInfo = getVideoInfo;
@@ -1 +1,5 @@
1
- export declare const guessExtensionForVideo: (src: string) => Promise<"mp3" | "wav" | "webm" | "mp4">;
1
+ export declare const guessExtensionForVideo: ({ src, remotionRoot, ffprobeBinary, }: {
2
+ src: string;
3
+ remotionRoot: string;
4
+ ffprobeBinary: string | null;
5
+ }) => Promise<"mp3" | "wav" | "webm" | "mp4">;
@@ -5,8 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.guessExtensionForVideo = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
- const guessExtensionForVideo = async (src) => {
9
- const { stderr } = await (0, execa_1.default)('ffprobe', [src]);
8
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
9
+ const guessExtensionForVideo = async ({ src, remotionRoot, ffprobeBinary, }) => {
10
+ const { stderr } = await (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffprobeBinary, remotionRoot, 'ffprobe'), [src]);
10
11
  if (stderr.includes('mp3,')) {
11
12
  return 'mp3';
12
13
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import execa from 'execa';
3
2
  import { SymbolicateableError } from './error-handling/symbolicateable-error';
4
3
  import { mimeContentType, mimeLookup } from './mime-types';
@@ -11,6 +10,7 @@ export { BrowserLog } from './browser-log';
11
10
  export { Codec, CodecOrUndefined } from './codec';
12
11
  export { combineVideos } from './combine-videos';
13
12
  export { Crf } from './crf';
13
+ export { ensureFfmpeg, EnsureFfmpegOptions, ensureFfprobe, } from './ensure-ffmpeg';
14
14
  export { ErrorWithStackFrame } from './error-handling/handle-javascript-exception';
15
15
  export { FfmpegExecutable } from './ffmpeg-executable';
16
16
  export { FfmpegVersion } from './ffmpeg-flags';
@@ -34,12 +34,13 @@ export { OpenGlRenderer } from './validate-opengl-renderer';
34
34
  export { validateOutputFilename } from './validate-output-filename';
35
35
  export declare const RenderInternals: {
36
36
  ensureLocalBrowser: (browser: import("./browser").Browser, preferredBrowserExecutable: import("./browser-executable").BrowserExecutable) => Promise<void>;
37
- ffmpegHasFeature: ({ ffmpegExecutable, feature, }: {
37
+ ffmpegHasFeature: ({ ffmpegExecutable, feature, remotionRoot, }: {
38
38
  ffmpegExecutable: string | null;
39
39
  feature: "enable-gpl" | "enable-libx265" | "enable-libvpx";
40
+ remotionRoot: string;
40
41
  }) => Promise<boolean>;
41
42
  getActualConcurrency: (userPreference: number | null) => number;
42
- validateFfmpeg: (customFfmpegBinary: string | null) => Promise<void>;
43
+ validateFfmpeg: (customFfmpegBinary: string | null, remotionRoot: string, binary: "ffmpeg" | "ffprobe") => Promise<void>;
43
44
  serveStatic: (path: string | null, options: {
44
45
  port: number | null;
45
46
  ffmpegExecutable: import("./ffmpeg-executable").FfmpegExecutable;
@@ -47,6 +48,7 @@ export declare const RenderInternals: {
47
48
  onDownload: import("./assets/download-and-map-assets-to-file").RenderMediaOnDownload;
48
49
  onError: (err: Error) => void;
49
50
  downloadMap: import("./assets/download-map").DownloadMap;
51
+ remotionRoot: string;
50
52
  }) => Promise<{
51
53
  port: number;
52
54
  close: () => Promise<void>;
@@ -131,8 +133,11 @@ export declare const RenderInternals: {
131
133
  frame: number;
132
134
  durationInFrames: number;
133
135
  }) => number;
136
+ findRemotionRoot: () => string;
137
+ getExecutableBinary: (ffmpegExecutable: import("./ffmpeg-executable").FfmpegExecutable, remotionRoot: string, binary: "ffmpeg" | "ffprobe") => string | Promise<string>;
134
138
  validateBitrate: (bitrate: unknown, name: string) => void;
135
139
  getFfmpegVersion: (options: {
136
140
  ffmpegExecutable: string | null;
141
+ remotionRoot: string;
137
142
  }) => Promise<import("./ffmpeg-flags").FfmpegVersion>;
138
143
  };
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
  };
@@ -11,6 +11,7 @@ export declare type LastFrameOptions = {
11
11
  imageFormat: OffthreadVideoImageFormat;
12
12
  needsResize: [number, number] | null;
13
13
  downloadMap: DownloadMap;
14
+ remotionRoot: string;
14
15
  };
15
16
  export declare const setLastFrameInCache: (options: LastFrameOptions, data: Buffer) => void;
16
17
  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
  });
@@ -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);
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { SmallTCompMetadata } from 'remotion';
2
3
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
3
4
  import type { DownloadMap } from './assets/download-map';