@remotion/renderer 4.0.0-alpha4 → 4.0.0-alpha6

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 (143) hide show
  1. package/README.md +5 -43
  2. package/dist/assets/download-and-map-assets-to-file.js +6 -6
  3. package/dist/assets/download-file.d.ts +3 -2
  4. package/dist/assets/download-file.js +18 -3
  5. package/dist/assets/download-map.d.ts +0 -26
  6. package/dist/assets/download-map.js +7 -12
  7. package/dist/assets/get-audio-channels.d.ts +1 -2
  8. package/dist/assets/get-audio-channels.js +5 -9
  9. package/dist/assets/read-file.d.ts +1 -1
  10. package/dist/assets/read-file.js +2 -2
  11. package/dist/assets/sanitize-filepath.js +2 -2
  12. package/dist/audio-codec.d.ts +4 -3
  13. package/dist/audio-codec.js +3 -9
  14. package/dist/browser/BrowserFetcher.d.ts +0 -1
  15. package/dist/browser/BrowserFetcher.js +14 -15
  16. package/dist/browser/BrowserRunner.d.ts +1 -1
  17. package/dist/browser/BrowserRunner.js +10 -4
  18. package/dist/browser/FrameManager.js +2 -3
  19. package/dist/browser/LaunchOptions.d.ts +1 -0
  20. package/dist/browser/Launcher.js +6 -5
  21. package/dist/browser/NodeWebSocketTransport.js +4 -4
  22. package/dist/browser/devtools-commands.d.ts +5 -1
  23. package/dist/browser/devtools-types.d.ts +78 -0
  24. package/dist/browser/get-download-destination.js +8 -8
  25. package/dist/browser/is-target-closed-err.d.ts +1 -0
  26. package/dist/browser/is-target-closed-err.js +9 -0
  27. package/dist/call-ffmpeg.d.ts +14 -0
  28. package/dist/call-ffmpeg.js +40 -0
  29. package/dist/check-apple-silicon.js +2 -45
  30. package/dist/client.d.ts +79 -42
  31. package/dist/client.js +27 -1
  32. package/dist/codec-supports-media.d.ts +2 -1
  33. package/dist/codec-supports-media.js +20 -5
  34. package/dist/combine-videos.d.ts +0 -3
  35. package/dist/combine-videos.js +9 -13
  36. package/dist/compositor/compose.d.ts +3 -1
  37. package/dist/compositor/compose.js +41 -18
  38. package/dist/compositor/compositor.d.ts +12 -0
  39. package/dist/compositor/compositor.js +204 -0
  40. package/dist/compositor/get-executable-path.d.ts +1 -1
  41. package/dist/compositor/get-executable-path.js +27 -8
  42. package/dist/compositor/make-nonce.d.ts +1 -0
  43. package/dist/compositor/make-nonce.js +8 -0
  44. package/dist/compositor/payloads.d.ts +34 -7
  45. package/dist/create-ffmpeg-complex-filter.d.ts +5 -5
  46. package/dist/create-ffmpeg-complex-filter.js +2 -4
  47. package/dist/create-ffmpeg-merge-filter.d.ts +2 -5
  48. package/dist/create-ffmpeg-merge-filter.js +2 -10
  49. package/dist/create-silent-audio.d.ts +1 -4
  50. package/dist/create-silent-audio.js +3 -7
  51. package/dist/crf.js +8 -2
  52. package/dist/delete-directory.js +18 -18
  53. package/dist/does-have-m2-bug.js +2 -2
  54. package/dist/ensure-output-directory.js +5 -5
  55. package/dist/ffmpeg-filter-file.js +7 -7
  56. package/dist/file-extensions.d.ts +1 -12
  57. package/dist/file-extensions.js +8 -14
  58. package/dist/find-closest-package-json.js +6 -6
  59. package/dist/get-compositions.d.ts +3 -5
  60. package/dist/get-compositions.js +8 -11
  61. package/dist/get-concurrency.js +3 -3
  62. package/dist/get-extension-from-codec.d.ts +2 -2
  63. package/dist/get-extension-of-filename.js +2 -2
  64. package/dist/get-frame-padded-index.d.ts +2 -1
  65. package/dist/get-local-browser-executable.js +4 -4
  66. package/dist/get-video-threads-flag.js +3 -3
  67. package/dist/guess-extension-for-media.d.ts +1 -3
  68. package/dist/guess-extension-for-media.js +4 -8
  69. package/dist/image-format.d.ts +12 -6
  70. package/dist/image-format.js +16 -13
  71. package/dist/index.d.ts +80 -61
  72. package/dist/index.js +15 -17
  73. package/dist/jpeg-quality.d.ts +1 -0
  74. package/dist/jpeg-quality.js +21 -0
  75. package/dist/merge-audio-track.d.ts +0 -2
  76. package/dist/merge-audio-track.js +5 -12
  77. package/dist/mime-types.js +2 -2
  78. package/dist/offthread-video-server.d.ts +9 -9
  79. package/dist/offthread-video-server.js +65 -58
  80. package/dist/open-browser.d.ts +1 -0
  81. package/dist/open-browser.js +7 -6
  82. package/dist/options/audio-bitrate.d.ts +2 -0
  83. package/dist/options/audio-bitrate.js +11 -0
  84. package/dist/options/crf.d.ts +2 -0
  85. package/dist/options/crf.js +11 -0
  86. package/dist/options/enforce-audio.d.ts +2 -0
  87. package/dist/options/enforce-audio.js +11 -0
  88. package/dist/options/jpeg-quality.d.ts +2 -0
  89. package/dist/options/jpeg-quality.js +11 -0
  90. package/dist/options/mute.d.ts +2 -0
  91. package/dist/options/mute.js +11 -0
  92. package/dist/options/option.d.ts +8 -0
  93. package/dist/options/option.js +2 -0
  94. package/dist/options/scale.d.ts +2 -0
  95. package/dist/options/scale.js +11 -0
  96. package/dist/options/video-bitrate.d.ts +2 -0
  97. package/dist/options/video-bitrate.js +11 -0
  98. package/dist/options/video-codec.d.ts +2 -0
  99. package/dist/options/video-codec.js +11 -0
  100. package/dist/perf.d.ts +1 -1
  101. package/dist/perf.js +9 -7
  102. package/dist/prepare-server.d.ts +3 -4
  103. package/dist/prepare-server.js +9 -9
  104. package/dist/preprocess-audio-track.d.ts +0 -4
  105. package/dist/preprocess-audio-track.js +4 -8
  106. package/dist/prespawn-ffmpeg.d.ts +6 -9
  107. package/dist/prespawn-ffmpeg.js +7 -12
  108. package/dist/prestitcher-memory-usage.d.ts +0 -4
  109. package/dist/prestitcher-memory-usage.js +4 -5
  110. package/dist/prores-profile.d.ts +1 -2
  111. package/dist/prores-profile.js +4 -4
  112. package/dist/provide-screenshot.d.ts +4 -5
  113. package/dist/provide-screenshot.js +2 -2
  114. package/dist/puppeteer-screenshot.d.ts +3 -3
  115. package/dist/puppeteer-screenshot.js +10 -33
  116. package/dist/render-frames.d.ts +13 -25
  117. package/dist/render-frames.js +34 -45
  118. package/dist/render-media.d.ts +16 -18
  119. package/dist/render-media.js +42 -52
  120. package/dist/render-still.d.ts +12 -8
  121. package/dist/render-still.js +30 -18
  122. package/dist/resolve-asset-src.js +2 -2
  123. package/dist/screenshot-dom-element.d.ts +4 -5
  124. package/dist/screenshot-dom-element.js +6 -3
  125. package/dist/screenshot-task.d.ts +2 -3
  126. package/dist/screenshot-task.js +40 -25
  127. package/dist/serve-handler/index.d.ts +1 -1
  128. package/dist/serve-handler/index.js +21 -19
  129. package/dist/serve-handler/is-path-inside.js +3 -3
  130. package/dist/serve-static.d.ts +2 -3
  131. package/dist/serve-static.js +26 -22
  132. package/dist/stitch-frames-to-video.d.ts +2 -12
  133. package/dist/stitch-frames-to-video.js +37 -46
  134. package/dist/take-frame-and-compose.d.ts +4 -5
  135. package/dist/take-frame-and-compose.js +15 -9
  136. package/dist/tmp-dir.js +7 -8
  137. package/dist/validate-concurrency.d.ts +2 -0
  138. package/dist/validate-concurrency.js +11 -5
  139. package/dist/validate-output-filename.d.ts +1 -1
  140. package/dist/validate-puppeteer-timeout.js +1 -0
  141. package/install-toolchain.mjs +36 -0
  142. package/package.json +11 -10
  143. package/types/ws/index.d.ts +5 -5
@@ -4,15 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.serveHandler = void 0;
7
- const fs_1 = require("fs");
8
- const path_1 = __importDefault(require("path"));
9
- const url_1 = __importDefault(require("url"));
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const node_url_1 = __importDefault(require("node:url"));
10
10
  const mime_types_1 = require("../mime-types");
11
11
  // Packages
12
12
  const is_path_inside_1 = require("./is-path-inside");
13
13
  const range_parser_1 = require("./range-parser");
14
14
  const getHeaders = (absolutePath, stats) => {
15
- const { base } = path_1.default.parse(absolutePath);
15
+ const { base } = node_path_1.default.parse(absolutePath);
16
16
  let defaultHeaders = {};
17
17
  if (stats) {
18
18
  defaultHeaders = {
@@ -28,19 +28,19 @@ const getHeaders = (absolutePath, stats) => {
28
28
  return defaultHeaders;
29
29
  };
30
30
  const getPossiblePaths = (relativePath, extension) => [
31
- path_1.default.join(relativePath, `index${extension}`),
31
+ node_path_1.default.join(relativePath, `index${extension}`),
32
32
  relativePath.endsWith('/')
33
33
  ? relativePath.replace(/\/$/g, extension)
34
34
  : relativePath + extension,
35
- ].filter((item) => path_1.default.basename(item) !== extension);
35
+ ].filter((item) => node_path_1.default.basename(item) !== extension);
36
36
  const findRelated = async (current, relativePath) => {
37
37
  const possible = getPossiblePaths(relativePath, '.html');
38
38
  let stats = null;
39
39
  for (let index = 0; index < possible.length; index++) {
40
40
  const related = possible[index];
41
- const absolutePath = path_1.default.join(current, related);
41
+ const absolutePath = node_path_1.default.join(current, related);
42
42
  try {
43
- stats = await fs_1.promises.lstat(absolutePath);
43
+ stats = await node_fs_1.promises.lstat(absolutePath);
44
44
  }
45
45
  catch (err) {
46
46
  if (err.code !== 'ENOENT' &&
@@ -59,10 +59,11 @@ const findRelated = async (current, relativePath) => {
59
59
  };
60
60
  const sendError = (absolutePath, response, spec) => {
61
61
  const { message, statusCode } = spec;
62
- response.statusCode = statusCode;
63
62
  const headers = getHeaders(absolutePath, null);
64
- response.writeHead(statusCode, headers);
65
- response.setHeader('content-type', 'application/json');
63
+ response.writeHead(statusCode, {
64
+ ...headers,
65
+ 'Content-Type': 'application/json',
66
+ });
66
67
  response.end(JSON.stringify({ statusCode, message }));
67
68
  };
68
69
  const internalError = (absolutePath, response) => {
@@ -74,10 +75,10 @@ const internalError = (absolutePath, response) => {
74
75
  };
75
76
  const serveHandler = async (request, response, config) => {
76
77
  const cwd = process.cwd();
77
- const current = path_1.default.resolve(cwd, config.public);
78
+ const current = node_path_1.default.resolve(cwd, config.public);
78
79
  let relativePath = null;
79
80
  try {
80
- relativePath = decodeURIComponent(url_1.default.parse(request.url).pathname);
81
+ relativePath = decodeURIComponent(node_url_1.default.parse(request.url).pathname);
81
82
  }
82
83
  catch (err) {
83
84
  return sendError('/', response, {
@@ -86,7 +87,7 @@ const serveHandler = async (request, response, config) => {
86
87
  message: 'Bad Request',
87
88
  });
88
89
  }
89
- let absolutePath = path_1.default.join(current, relativePath);
90
+ let absolutePath = node_path_1.default.join(current, relativePath);
90
91
  // Prevent path traversal vulnerabilities. We could do this
91
92
  // by ourselves, but using the package covers all the edge cases.
92
93
  if (!(0, is_path_inside_1.isPathInside)(absolutePath, current)) {
@@ -108,9 +109,9 @@ const serveHandler = async (request, response, config) => {
108
109
  // directory exists requires loading all the file paths and then checking if
109
110
  // one of them includes the path of the directory. As that's a very
110
111
  // performance-expensive thing to do, we need to ensure it's not happening if not really necessary.
111
- if (path_1.default.extname(relativePath) !== '') {
112
+ if (node_path_1.default.extname(relativePath) !== '') {
112
113
  try {
113
- stats = await fs_1.promises.lstat(absolutePath);
114
+ stats = await node_fs_1.promises.lstat(absolutePath);
114
115
  }
115
116
  catch (err) {
116
117
  if (err.code !== 'ENOENT' &&
@@ -123,7 +124,8 @@ const serveHandler = async (request, response, config) => {
123
124
  try {
124
125
  const related = await findRelated(current, relativePath);
125
126
  if (related) {
126
- ({ stats, absolutePath } = related);
127
+ stats = related.stats;
128
+ absolutePath = related.absolutePath;
127
129
  }
128
130
  }
129
131
  catch (err) {
@@ -133,7 +135,7 @@ const serveHandler = async (request, response, config) => {
133
135
  }
134
136
  }
135
137
  try {
136
- stats = await fs_1.promises.lstat(absolutePath);
138
+ stats = await node_fs_1.promises.lstat(absolutePath);
137
139
  }
138
140
  catch (err) {
139
141
  if (err.code !== 'ENOENT' &&
@@ -188,7 +190,7 @@ const serveHandler = async (request, response, config) => {
188
190
  }
189
191
  let stream = null;
190
192
  try {
191
- stream = (0, fs_1.createReadStream)(absolutePath, streamOpts !== null && streamOpts !== void 0 ? streamOpts : {});
193
+ stream = (0, node_fs_1.createReadStream)(absolutePath, streamOpts !== null && streamOpts !== void 0 ? streamOpts : {});
192
194
  }
193
195
  catch (err) {
194
196
  return internalError(absolutePath, response);
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isPathInside = void 0;
7
- const path_1 = __importDefault(require("path"));
7
+ const node_path_1 = __importDefault(require("node:path"));
8
8
  const isPathInside = function (thePath, potentialParent) {
9
9
  // For inside-directory checking, we want to allow trailing slashes, so normalize.
10
10
  thePath = stripTrailingSep(thePath);
@@ -15,12 +15,12 @@ const isPathInside = function (thePath, potentialParent) {
15
15
  potentialParent = potentialParent.toLowerCase();
16
16
  }
17
17
  return (thePath.lastIndexOf(potentialParent, 0) === 0 &&
18
- (thePath[potentialParent.length] === path_1.default.sep ||
18
+ (thePath[potentialParent.length] === node_path_1.default.sep ||
19
19
  thePath[potentialParent.length] === undefined));
20
20
  };
21
21
  exports.isPathInside = isPathInside;
22
22
  function stripTrailingSep(thePath) {
23
- if (thePath[thePath.length - 1] === path_1.default.sep) {
23
+ if (thePath[thePath.length - 1] === node_path_1.default.sep) {
24
24
  return thePath.slice(0, -1);
25
25
  }
26
26
  return thePath;
@@ -1,14 +1,13 @@
1
1
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
2
2
  import type { DownloadMap } from './assets/download-map';
3
- import type { FfmpegExecutable } from './ffmpeg-executable';
4
3
  export declare const serveStatic: (path: string | null, options: {
5
4
  port: number | null;
6
- ffmpegExecutable: FfmpegExecutable;
7
- ffprobeExecutable: FfmpegExecutable;
8
5
  onDownload: RenderMediaOnDownload;
9
6
  onError: (err: Error) => void;
10
7
  downloadMap: DownloadMap;
11
8
  remotionRoot: string;
9
+ concurrency: number;
10
+ verbose: boolean;
12
11
  }) => Promise<{
13
12
  port: number;
14
13
  close: () => Promise<void>;
@@ -4,21 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.serveStatic = void 0;
7
- const http_1 = __importDefault(require("http"));
7
+ const node_http_1 = __importDefault(require("node:http"));
8
8
  const get_port_1 = require("./get-port");
9
9
  const offthread_video_server_1 = require("./offthread-video-server");
10
10
  const serve_handler_1 = require("./serve-handler");
11
11
  const serveStatic = async (path, options) => {
12
- const offthreadRequest = (0, offthread_video_server_1.startOffthreadVideoServer)({
13
- ffmpegExecutable: options.ffmpegExecutable,
14
- ffprobeExecutable: options.ffprobeExecutable,
12
+ const { listener: offthreadRequest, close: closeCompositor } = (0, offthread_video_server_1.startOffthreadVideoServer)({
15
13
  onDownload: options.onDownload,
16
14
  onError: options.onError,
17
15
  downloadMap: options.downloadMap,
18
- remotionRoot: options.remotionRoot,
16
+ concurrency: options.concurrency,
17
+ verbose: options.verbose,
19
18
  });
20
19
  const connections = {};
21
- const server = http_1.default.createServer((request, response) => {
20
+ const server = node_http_1.default.createServer((request, response) => {
22
21
  var _a;
23
22
  if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.startsWith('/proxy')) {
24
23
  return offthreadRequest(request, response);
@@ -31,7 +30,9 @@ const serveStatic = async (path, options) => {
31
30
  (0, serve_handler_1.serveHandler)(request, response, {
32
31
  public: path,
33
32
  }).catch(() => {
34
- response.statusCode = 500;
33
+ if (!response.headersSent) {
34
+ response.writeHead(500);
35
+ }
35
36
  response.end('Error serving file');
36
37
  });
37
38
  });
@@ -65,22 +66,25 @@ const serveStatic = async (path, options) => {
65
66
  for (const key in connections)
66
67
  connections[key].destroy();
67
68
  };
68
- const close = () => {
69
- return new Promise((resolve, reject) => {
70
- destroyConnections();
71
- server.close((err) => {
72
- if (err) {
73
- if (err.code ===
74
- 'ERR_SERVER_NOT_RUNNING') {
75
- return resolve();
69
+ const close = async () => {
70
+ await Promise.all([
71
+ closeCompositor(),
72
+ new Promise((resolve, reject) => {
73
+ destroyConnections();
74
+ server.close((err) => {
75
+ if (err) {
76
+ if (err.code ===
77
+ 'ERR_SERVER_NOT_RUNNING') {
78
+ return resolve();
79
+ }
80
+ reject(err);
76
81
  }
77
- reject(err);
78
- }
79
- else {
80
- resolve();
81
- }
82
- });
83
- });
82
+ else {
83
+ resolve();
84
+ }
85
+ });
86
+ }),
87
+ ]);
84
88
  };
85
89
  return { port: selectedPort, close };
86
90
  }
@@ -1,11 +1,9 @@
1
- /// <reference types="node" />
2
1
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
3
2
  import type { RenderAssetInfo } from './assets/download-map';
4
3
  import type { AudioCodec } from './audio-codec';
5
4
  import type { Codec } from './codec';
6
- import type { FfmpegExecutable } from './ffmpeg-executable';
7
5
  import type { FfmpegOverrideFn } from './ffmpeg-override';
8
- import type { ImageFormat } from './image-format';
6
+ import type { VideoImageFormat } from './image-format';
9
7
  import type { CancelSignal } from './make-cancel-signal';
10
8
  import type { PixelFormat } from './pixel-format';
11
9
  import type { ProResProfile } from './prores-profile';
@@ -27,27 +25,19 @@ export declare type StitcherOptions = {
27
25
  onDownload?: RenderMediaOnDownload;
28
26
  proResProfile?: ProResProfile;
29
27
  verbose?: boolean;
30
- ffmpegExecutable?: FfmpegExecutable;
31
- ffprobeExecutable?: FfmpegExecutable;
32
28
  dir?: string;
33
29
  cancelSignal?: CancelSignal;
34
30
  internalOptions?: {
35
31
  preEncodedFileLocation: string | null;
36
- imageFormat: ImageFormat;
32
+ imageFormat: VideoImageFormat;
37
33
  preferLossless: boolean;
38
34
  };
39
35
  muted?: boolean;
40
36
  enforceAudioTrack?: boolean;
41
37
  ffmpegOverride?: FfmpegOverrideFn;
42
38
  };
43
- declare type ReturnType = {
44
- task: Promise<Buffer | null>;
45
- getLogs: () => string;
46
- };
47
- export declare const spawnFfmpeg: (options: StitcherOptions, remotionRoot: string) => Promise<ReturnType>;
48
39
  /**
49
40
  * @description Takes a series of images and audio information generated by renderFrames() and encodes it to a video.
50
41
  * @see [Documentation](https://www.remotion.dev/docs/renderer/stitch-frames-to-video)
51
42
  */
52
43
  export declare const stitchFramesToVideo: (options: StitcherOptions) => Promise<Buffer | null>;
53
- export {};
@@ -26,22 +26,22 @@ 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.stitchFramesToVideo = exports.spawnFfmpeg = void 0;
30
- const execa_1 = __importDefault(require("execa"));
31
- const fs_1 = __importStar(require("fs"));
32
- const path_1 = __importDefault(require("path"));
29
+ exports.stitchFramesToVideo = void 0;
30
+ const node_fs_1 = __importStar(require("node:fs"));
31
+ const node_path_1 = __importDefault(require("node:path"));
33
32
  const remotion_1 = require("remotion");
34
33
  const calculate_asset_positions_1 = require("./assets/calculate-asset-positions");
35
34
  const convert_assets_to_file_urls_1 = require("./assets/convert-assets-to-file-urls");
36
35
  const download_and_map_assets_to_file_1 = require("./assets/download-and-map-assets-to-file");
37
36
  const audio_codec_1 = require("./audio-codec");
37
+ const call_ffmpeg_1 = require("./call-ffmpeg");
38
38
  const codec_1 = require("./codec");
39
39
  const codec_supports_media_1 = require("./codec-supports-media");
40
+ const get_executable_path_1 = require("./compositor/get-executable-path");
40
41
  const convert_number_of_gif_loops_to_ffmpeg_1 = require("./convert-number-of-gif-loops-to-ffmpeg");
41
42
  const crf_1 = require("./crf");
42
43
  const delete_directory_1 = require("./delete-directory");
43
44
  const does_have_m2_bug_1 = require("./does-have-m2-bug");
44
- const ffmpeg_flags_1 = require("./ffmpeg-flags");
45
45
  const find_closest_package_json_1 = require("./find-closest-package-json");
46
46
  const get_codec_name_1 = require("./get-codec-name");
47
47
  const get_extension_from_codec_1 = require("./get-extension-from-codec");
@@ -54,13 +54,12 @@ const preprocess_audio_track_1 = require("./preprocess-audio-track");
54
54
  const prores_profile_1 = require("./prores-profile");
55
55
  const truthy_1 = require("./truthy");
56
56
  const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
57
- const validate_ffmpeg_1 = require("./validate-ffmpeg");
58
57
  const validate_videobitrate_1 = require("./validate-videobitrate");
59
- const packageJsonPath = path_1.default.join(__dirname, '..', 'package.json');
60
- const packageJson = fs_1.default.existsSync(packageJsonPath)
61
- ? JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'))
58
+ const packageJsonPath = node_path_1.default.join(__dirname, '..', 'package.json');
59
+ const packageJson = node_fs_1.default.existsSync(packageJsonPath)
60
+ ? JSON.parse(node_fs_1.default.readFileSync(packageJsonPath, 'utf-8'))
62
61
  : null;
63
- const getAssetsData = async ({ assets, onDownload, fps, expectedFrames, verbose, ffmpegExecutable, ffprobeExecutable, onProgress, downloadMap, remotionRoot, }) => {
62
+ const getAssetsData = async ({ assets, onDownload, fps, expectedFrames, verbose, onProgress, downloadMap, remotionRoot, }) => {
64
63
  const fileUrlAssets = await (0, convert_assets_to_file_urls_1.convertAssetsToFileUrls)({
65
64
  assets,
66
65
  onDownload: onDownload !== null && onDownload !== void 0 ? onDownload : (() => () => undefined),
@@ -76,24 +75,20 @@ const getAssetsData = async ({ assets, onDownload, fps, expectedFrames, verbose,
76
75
  onProgress(preprocessProgress.reduce((a, b) => a + b, 0) / assetPositions.length);
77
76
  };
78
77
  const preprocessed = (await Promise.all(assetPositions.map(async (asset, index) => {
79
- const filterFile = path_1.default.join(downloadMap.audioMixing, `${index}.wav`);
78
+ const filterFile = node_path_1.default.join(downloadMap.audioMixing, `${index}.wav`);
80
79
  const result = await (0, preprocess_audio_track_1.preprocessAudioTrack)({
81
- ffmpegExecutable: ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null,
82
- ffprobeExecutable: ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : null,
83
80
  outName: filterFile,
84
81
  asset,
85
82
  expectedFrames,
86
83
  fps,
87
84
  downloadMap,
88
- remotionRoot,
89
85
  });
90
86
  preprocessProgress[index] = 1;
91
87
  updateProgress();
92
88
  return result;
93
89
  }))).filter(truthy_1.truthy);
94
- const outName = path_1.default.join(downloadMap.audioPreprocessing, `audio.wav`);
90
+ const outName = node_path_1.default.join(downloadMap.audioPreprocessing, `audio.wav`);
95
91
  await (0, merge_audio_track_1.mergeAudioTrack)({
96
- ffmpegExecutable: ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null,
97
92
  files: preprocessed,
98
93
  outName,
99
94
  numberOfSeconds: Number((expectedFrames / fps).toFixed(3)),
@@ -108,7 +103,7 @@ const getAssetsData = async ({ assets, onDownload, fps, expectedFrames, verbose,
108
103
  return outName;
109
104
  };
110
105
  const spawnFfmpeg = async (options, remotionRoot) => {
111
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
112
107
  remotion_1.Internals.validateDimension(options.height, 'height', 'passed to `stitchFramesToVideo()`');
113
108
  remotion_1.Internals.validateDimension(options.width, 'width', 'passed to `stitchFramesToVideo()`');
114
109
  const codec = (_a = options.codec) !== null && _a !== void 0 ? _a : codec_1.DEFAULT_CODEC;
@@ -126,7 +121,6 @@ const spawnFfmpeg = async (options, remotionRoot) => {
126
121
  (0, validate_videobitrate_1.validateBitrate)(options.videoBitrate, 'videoBitrate');
127
122
  remotion_1.Internals.validateFps(options.fps, 'in `stitchFramesToVideo()`', false);
128
123
  const pixelFormat = (_b = options.pixelFormat) !== null && _b !== void 0 ? _b : pixel_format_1.DEFAULT_PIXEL_FORMAT;
129
- await (0, validate_ffmpeg_1.validateFfmpeg)((_c = options.ffmpegExecutable) !== null && _c !== void 0 ? _c : null, remotionRoot, 'ffmpeg');
130
124
  const encoderName = (0, get_codec_name_1.getCodecName)(codec);
131
125
  const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec, options.proResProfile);
132
126
  const mediaSupport = (0, codec_supports_media_1.codecSupportsMedia)(codec);
@@ -139,14 +133,14 @@ const spawnFfmpeg = async (options, remotionRoot) => {
139
133
  throw new Error('The output format has neither audio nor video. This can happen if you are rendering an audio codec and the output file has no audio or the muted flag was passed.');
140
134
  }
141
135
  // Explanation: https://github.com/remotion-dev/remotion/issues/1647
142
- const resolvedAudioCodec = ((_d = options.internalOptions) === null || _d === void 0 ? void 0 : _d.preferLossless)
136
+ const resolvedAudioCodec = ((_c = options.internalOptions) === null || _c === void 0 ? void 0 : _c.preferLossless)
143
137
  ? (0, audio_codec_1.getDefaultAudioCodec)({ codec, preferLossless: true })
144
- : (_e = options.audioCodec) !== null && _e !== void 0 ? _e : (0, audio_codec_1.getDefaultAudioCodec)({ codec, preferLossless: false });
138
+ : (_d = options.audioCodec) !== null && _d !== void 0 ? _d : (0, audio_codec_1.getDefaultAudioCodec)({ codec, preferLossless: false });
145
139
  const tempFile = options.outputLocation
146
140
  ? null
147
- : path_1.default.join(options.assetsInfo.downloadMap.stitchFrames, `out.${(0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, resolvedAudioCodec)}`);
141
+ : node_path_1.default.join(options.assetsInfo.downloadMap.stitchFrames, `out.${(0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, resolvedAudioCodec)}`);
148
142
  if (options.verbose) {
149
- console.log('[verbose] ffmpeg', (_f = options.ffmpegExecutable) !== null && _f !== void 0 ? _f : 'ffmpeg in PATH');
143
+ console.log('[verbose] ffmpeg', (0, get_executable_path_1.getExecutablePath)('ffmpeg'));
150
144
  console.log('[verbose] encoder', encoderName);
151
145
  console.log('[verbose] audioCodec', resolvedAudioCodec);
152
146
  console.log('[verbose] pixelFormat', pixelFormat);
@@ -176,9 +170,7 @@ const spawnFfmpeg = async (options, remotionRoot) => {
176
170
  onDownload: options.onDownload,
177
171
  fps: options.fps,
178
172
  expectedFrames,
179
- verbose: (_g = options.verbose) !== null && _g !== void 0 ? _g : false,
180
- ffmpegExecutable: (_h = options.ffmpegExecutable) !== null && _h !== void 0 ? _h : null,
181
- ffprobeExecutable: (_j = options.ffprobeExecutable) !== null && _j !== void 0 ? _j : null,
173
+ verbose: (_e = options.verbose) !== null && _e !== void 0 ? _e : false,
182
174
  onProgress: (prog) => updateProgress(prog, 0),
183
175
  downloadMap: options.assetsInfo.downloadMap,
184
176
  remotionRoot,
@@ -188,28 +180,28 @@ const spawnFfmpeg = async (options, remotionRoot) => {
188
180
  if (!resolvedAudioCodec) {
189
181
  throw new TypeError('exporting audio but has no audio codec name. Report this in the Remotion repo.');
190
182
  }
191
- const ffmpegTask = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)((_k = options.ffmpegExecutable) !== null && _k !== void 0 ? _k : null, remotionRoot, 'ffmpeg'), [
183
+ const ffmpegTask = (0, call_ffmpeg_1.callFf)('ffmpeg', [
192
184
  '-i',
193
185
  audio,
194
186
  '-c:a',
195
187
  (0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec),
196
188
  // Set bitrate up to 320k, for aac it might effectively be lower
197
189
  '-b:a',
198
- (_l = options.audioBitrate) !== null && _l !== void 0 ? _l : '320k',
190
+ (_f = options.audioBitrate) !== null && _f !== void 0 ? _f : '320k',
199
191
  options.force ? '-y' : null,
200
- (_m = options.outputLocation) !== null && _m !== void 0 ? _m : tempFile,
192
+ (_g = options.outputLocation) !== null && _g !== void 0 ? _g : tempFile,
201
193
  ].filter(remotion_1.Internals.truthy));
202
- (_o = options.cancelSignal) === null || _o === void 0 ? void 0 : _o.call(options, () => {
194
+ (_h = options.cancelSignal) === null || _h === void 0 ? void 0 : _h.call(options, () => {
203
195
  ffmpegTask.kill();
204
196
  });
205
197
  await ffmpegTask;
206
- (_p = options.onProgress) === null || _p === void 0 ? void 0 : _p.call(options, expectedFrames);
198
+ (_j = options.onProgress) === null || _j === void 0 ? void 0 : _j.call(options, expectedFrames);
207
199
  if (audio) {
208
- (0, delete_directory_1.deleteDirectory)(path_1.default.dirname(audio));
200
+ (0, delete_directory_1.deleteDirectory)(node_path_1.default.dirname(audio));
209
201
  }
210
202
  const file = await new Promise((resolve, reject) => {
211
203
  if (tempFile) {
212
- fs_1.promises
204
+ node_fs_1.promises
213
205
  .readFile(tempFile)
214
206
  .then((f) => {
215
207
  return resolve(f);
@@ -227,26 +219,26 @@ const spawnFfmpeg = async (options, remotionRoot) => {
227
219
  };
228
220
  }
229
221
  const ffmpegArgs = [
230
- ['-r', String(options.fps)],
231
- ...(((_q = options.internalOptions) === null || _q === void 0 ? void 0 : _q.preEncodedFileLocation)
232
- ? [['-i', (_r = options.internalOptions) === null || _r === void 0 ? void 0 : _r.preEncodedFileLocation]]
222
+ ...(((_k = options.internalOptions) === null || _k === void 0 ? void 0 : _k.preEncodedFileLocation)
223
+ ? [['-i', (_l = options.internalOptions) === null || _l === void 0 ? void 0 : _l.preEncodedFileLocation]]
233
224
  : [
225
+ ['-r', String(options.fps)],
234
226
  ['-f', 'image2'],
235
227
  ['-s', `${options.width}x${options.height}`],
236
228
  ['-start_number', String(options.assetsInfo.firstFrameIndex)],
237
229
  ['-i', options.assetsInfo.imageSequenceName],
238
230
  ]),
239
231
  audio ? ['-i', audio] : null,
240
- ((_s = options.numberOfGifLoops) !== null && _s !== void 0 ? _s : null) === null
232
+ ((_m = options.numberOfGifLoops) !== null && _m !== void 0 ? _m : null) === null
241
233
  ? null
242
234
  : [
243
235
  '-loop',
244
- (0, convert_number_of_gif_loops_to_ffmpeg_1.convertNumberOfGifLoopsToFfmpegSyntax)((_t = options.numberOfGifLoops) !== null && _t !== void 0 ? _t : null),
236
+ (0, convert_number_of_gif_loops_to_ffmpeg_1.convertNumberOfGifLoopsToFfmpegSyntax)((_o = options.numberOfGifLoops) !== null && _o !== void 0 ? _o : null),
245
237
  ],
246
238
  // -c:v is the same as -vcodec as -codec:video
247
239
  // and specified the video codec.
248
240
  ['-c:v', encoderName],
249
- ...(((_u = options.internalOptions) === null || _u === void 0 ? void 0 : _u.preEncodedFileLocation)
241
+ ...(((_p = options.internalOptions) === null || _p === void 0 ? void 0 : _p.preEncodedFileLocation)
250
242
  ? []
251
243
  : [
252
244
  proResProfileName ? ['-profile:v', proResProfileName] : null,
@@ -274,7 +266,7 @@ const spawnFfmpeg = async (options, remotionRoot) => {
274
266
  [`Made with Remotion`, packageJson ? packageJson.version : null].join(' '),
275
267
  ],
276
268
  options.force ? '-y' : null,
277
- (_v = options.outputLocation) !== null && _v !== void 0 ? _v : tempFile,
269
+ (_q = options.outputLocation) !== null && _q !== void 0 ? _q : tempFile,
278
270
  ];
279
271
  if (options.verbose) {
280
272
  console.log('Generated FFMPEG command:');
@@ -288,15 +280,15 @@ const spawnFfmpeg = async (options, remotionRoot) => {
288
280
  console.log('Generated final FFMPEG command:');
289
281
  console.log(finalFfmpegString);
290
282
  }
291
- const task = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)((_w = options.ffmpegExecutable) !== null && _w !== void 0 ? _w : null, remotionRoot, 'ffmpeg'), finalFfmpegString, {
283
+ const task = (0, call_ffmpeg_1.callFf)('ffmpeg', finalFfmpegString, {
292
284
  cwd: options.dir,
293
285
  });
294
- (_x = options.cancelSignal) === null || _x === void 0 ? void 0 : _x.call(options, () => {
286
+ (_r = options.cancelSignal) === null || _r === void 0 ? void 0 : _r.call(options, () => {
295
287
  task.kill();
296
288
  });
297
289
  let ffmpegOutput = '';
298
290
  let isFinished = false;
299
- (_y = task.stderr) === null || _y === void 0 ? void 0 : _y.on('data', (data) => {
291
+ (_s = task.stderr) === null || _s === void 0 ? void 0 : _s.on('data', (data) => {
300
292
  var _a;
301
293
  const str = data.toString();
302
294
  ffmpegOutput += str;
@@ -325,12 +317,12 @@ const spawnFfmpeg = async (options, remotionRoot) => {
325
317
  (0, delete_directory_1.deleteDirectory)(options.assetsInfo.downloadMap.stitchFrames);
326
318
  return null;
327
319
  }
328
- return fs_1.promises
320
+ return node_fs_1.promises
329
321
  .readFile(tempFile)
330
322
  .then((file) => {
331
323
  return Promise.all([
332
324
  file,
333
- (0, delete_directory_1.deleteDirectory)(path_1.default.dirname(tempFile)),
325
+ (0, delete_directory_1.deleteDirectory)(node_path_1.default.dirname(tempFile)),
334
326
  (0, delete_directory_1.deleteDirectory)(options.assetsInfo.downloadMap.stitchFrames),
335
327
  ]);
336
328
  })
@@ -339,7 +331,6 @@ const spawnFfmpeg = async (options, remotionRoot) => {
339
331
  getLogs: () => ffmpegOutput,
340
332
  };
341
333
  };
342
- exports.spawnFfmpeg = spawnFfmpeg;
343
334
  /**
344
335
  * @description Takes a series of images and audio information generated by renderFrames() and encodes it to a video.
345
336
  * @see [Documentation](https://www.remotion.dev/docs/renderer/stitch-frames-to-video)
@@ -347,7 +338,7 @@ exports.spawnFfmpeg = spawnFfmpeg;
347
338
  const stitchFramesToVideo = async (options) => {
348
339
  var _a, _b;
349
340
  const remotionRoot = (0, find_closest_package_json_1.findRemotionRoot)();
350
- const { task, getLogs } = await (0, exports.spawnFfmpeg)(options, remotionRoot);
341
+ const { task, getLogs } = await spawnFfmpeg(options, remotionRoot);
351
342
  const happyPath = task.catch(() => {
352
343
  throw new Error(getLogs());
353
344
  });
@@ -1,12 +1,11 @@
1
- /// <reference types="node" />
2
1
  import type { TAsset } from 'remotion';
3
2
  import type { DownloadMap } from './assets/download-map';
4
3
  import type { Page } from './browser/BrowserPage';
5
- import type { ImageFormat } from './image-format';
6
- export declare const takeFrameAndCompose: ({ freePage, imageFormat, quality, frame, width, height, output, scale, downloadMap, wantsBuffer, }: {
4
+ import type { StillImageFormat, VideoImageFormat } from './image-format';
5
+ export declare const takeFrameAndCompose: ({ freePage, imageFormat, jpegQuality, frame, width, height, output, scale, downloadMap, wantsBuffer, }: {
7
6
  freePage: Page;
8
- imageFormat: ImageFormat;
9
- quality: number | undefined;
7
+ imageFormat: VideoImageFormat | StillImageFormat;
8
+ jpegQuality: number | undefined;
10
9
  frame: number;
11
10
  height: number;
12
11
  width: number;
@@ -4,13 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.takeFrameAndCompose = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
9
  const compose_1 = require("./compositor/compose");
10
10
  const provide_screenshot_1 = require("./provide-screenshot");
11
11
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
12
12
  const truthy_1 = require("./truthy");
13
- const takeFrameAndCompose = async ({ freePage, imageFormat, quality, frame, width, height, output, scale, downloadMap, wantsBuffer, }) => {
13
+ const takeFrameAndCompose = async ({ freePage, imageFormat, jpegQuality, frame, width, height, output, scale, downloadMap, wantsBuffer, }) => {
14
14
  var _a;
15
15
  const [clipRegion, collectedAssets] = await Promise.all([
16
16
  (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
@@ -39,8 +39,8 @@ const takeFrameAndCompose = async ({ freePage, imageFormat, quality, frame, widt
39
39
  const needsComposing = clipRegion === null
40
40
  ? null
41
41
  : {
42
- tmpFile: path_1.default.join(downloadMap.compositingDir, `${frame}.${imageFormat}`),
43
- finalOutfie: output !== null && output !== void 0 ? output : path_1.default.join(downloadMap.compositingDir, `${frame}-final.${imageFormat}`),
42
+ tmpFile: node_path_1.default.join(downloadMap.compositingDir, `${frame}.${imageFormat}`),
43
+ finalOutFile: output !== null && output !== void 0 ? output : node_path_1.default.join(downloadMap.compositingDir, `${frame}-final.${imageFormat}`),
44
44
  clipRegion: clipRegion,
45
45
  };
46
46
  if (clipRegion !== 'hide') {
@@ -48,7 +48,7 @@ const takeFrameAndCompose = async ({ freePage, imageFormat, quality, frame, widt
48
48
  const buf = await (0, provide_screenshot_1.provideScreenshot)({
49
49
  page: freePage,
50
50
  imageFormat,
51
- quality,
51
+ jpegQuality,
52
52
  options: {
53
53
  frame,
54
54
  output: shouldMakeBuffer ? null : (_a = needsComposing === null || needsComposing === void 0 ? void 0 : needsComposing.tmpFile) !== null && _a !== void 0 ? _a : output,
@@ -62,6 +62,12 @@ const takeFrameAndCompose = async ({ freePage, imageFormat, quality, frame, widt
62
62
  }
63
63
  }
64
64
  if (needsComposing) {
65
+ if (imageFormat === 'pdf') {
66
+ throw new Error("You cannot use compositor APIs (like <Clipper>) if `imageFormat` is 'pdf'.");
67
+ }
68
+ if (imageFormat === 'webp') {
69
+ throw new Error("You cannot use compositor APIs (like <Clipper>) if `imageFormat` is 'webp'.");
70
+ }
65
71
  await (0, compose_1.compose)({
66
72
  height: height * scale,
67
73
  width: width * scale,
@@ -81,13 +87,13 @@ const takeFrameAndCompose = async ({ freePage, imageFormat, quality, frame, widt
81
87
  },
82
88
  },
83
89
  ].filter(truthy_1.truthy),
84
- output: needsComposing.finalOutfie,
90
+ output: needsComposing.finalOutFile,
85
91
  downloadMap,
86
92
  imageFormat: imageFormat === 'jpeg' ? 'Jpeg' : 'Png',
87
93
  });
88
94
  if (wantsBuffer) {
89
- const buffer = await fs_1.default.promises.readFile(needsComposing.finalOutfie);
90
- await fs_1.default.promises.unlink(needsComposing.finalOutfie);
95
+ const buffer = await node_fs_1.default.promises.readFile(needsComposing.finalOutFile);
96
+ await node_fs_1.default.promises.unlink(needsComposing.finalOutFile);
91
97
  return { buffer, collectedAssets };
92
98
  }
93
99
  }
package/dist/tmp-dir.js CHANGED
@@ -27,9 +27,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.tmpDir = void 0;
30
- const fs_1 = __importStar(require("fs"));
31
- const os_1 = __importDefault(require("os"));
32
- const path_1 = __importDefault(require("path"));
30
+ const node_fs_1 = __importStar(require("node:fs"));
31
+ const node_os_1 = __importDefault(require("node:os"));
32
+ const node_path_1 = __importDefault(require("node:path"));
33
33
  const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789';
34
34
  const randomHash = () => {
35
35
  return new Array(10)
@@ -40,15 +40,14 @@ const randomHash = () => {
40
40
  .join('');
41
41
  };
42
42
  const tmpDir = (str) => {
43
- var _a;
44
- const newDir = path_1.default.join(os_1.default.tmpdir(), str + randomHash());
45
- if (fs_1.default.existsSync(newDir)) {
46
- ((_a = fs_1.default.rmSync) !== null && _a !== void 0 ? _a : fs_1.default.rmdirSync)(newDir, {
43
+ const newDir = node_path_1.default.join(node_os_1.default.tmpdir(), str + randomHash());
44
+ if (node_fs_1.default.existsSync(newDir)) {
45
+ node_fs_1.default.rmSync(newDir, {
47
46
  recursive: true,
48
47
  force: true,
49
48
  });
50
49
  }
51
- (0, fs_1.mkdirSync)(newDir);
50
+ (0, node_fs_1.mkdirSync)(newDir);
52
51
  return newDir;
53
52
  };
54
53
  exports.tmpDir = tmpDir;