@remotion/renderer 4.0.0-alpha.130 → 4.0.0-alpha.179

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 (47) hide show
  1. package/dist/client.d.ts +39 -39
  2. package/dist/combine-videos.js +2 -2
  3. package/dist/delete-directory.js +1 -2
  4. package/dist/ensure-ffmpeg.d.ts +18 -0
  5. package/dist/ensure-ffmpeg.js +58 -0
  6. package/dist/extract-frame-from-video.d.ts +0 -1
  7. package/dist/ffmpeg-executable.d.ts +1 -0
  8. package/dist/ffmpeg-executable.js +2 -0
  9. package/dist/ffmpeg-filter-file.js +31 -11
  10. package/dist/ffmpeg-flags.d.ts +31 -0
  11. package/dist/ffmpeg-flags.js +245 -0
  12. package/dist/get-extension-from-codec.d.ts +2 -2
  13. package/dist/get-frame-of-video-slow.d.ts +4 -2
  14. package/dist/get-frame-to-render.js +1 -1
  15. package/dist/get-local-browser-executable.js +1 -0
  16. package/dist/index.d.ts +33 -34
  17. package/dist/index.js +2 -2
  18. package/dist/jpeg-quality.d.ts +1 -0
  19. package/dist/jpeg-quality.js +21 -0
  20. package/dist/last-frame-from-video-cache.d.ts +0 -1
  21. package/dist/legacy-webpack-config.d.ts +9 -0
  22. package/dist/legacy-webpack-config.js +13 -0
  23. package/dist/options/jpeg-quality.js +3 -3
  24. package/dist/provide-screenshot.d.ts +2 -3
  25. package/dist/provide-screenshot.js +2 -2
  26. package/dist/puppeteer-screenshot.d.ts +1 -2
  27. package/dist/puppeteer-screenshot.js +7 -7
  28. package/dist/render-frames.d.ts +5 -1
  29. package/dist/render-frames.js +9 -6
  30. package/dist/render-media.d.ts +5 -1
  31. package/dist/render-media.js +7 -4
  32. package/dist/render-still.d.ts +5 -1
  33. package/dist/render-still.js +8 -5
  34. package/dist/screenshot-dom-element.d.ts +2 -3
  35. package/dist/screenshot-dom-element.js +2 -2
  36. package/dist/screenshot-task.d.ts +2 -3
  37. package/dist/screenshot-task.js +2 -2
  38. package/dist/take-frame-and-compose.d.ts +2 -3
  39. package/dist/take-frame-and-compose.js +2 -2
  40. package/dist/tmp-dir.js +1 -2
  41. package/dist/try-to-extract-frame-of-video-fast.d.ts +0 -1
  42. package/dist/validate-ffmpeg.d.ts +7 -0
  43. package/dist/validate-ffmpeg.js +77 -0
  44. package/dist/validate-output-filename.d.ts +1 -1
  45. package/dist/warn-about-ffmpeg-version.d.ts +5 -0
  46. package/dist/warn-about-ffmpeg-version.js +37 -0
  47. package/package.json +10 -10
package/dist/client.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export declare const BrowserSafeApis: {
2
- getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">(codec: T, audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null) => import("./file-extensions").FileExtension;
2
+ getFileExtensionFromCodec: <T extends "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif">(codec: T, audioCodec: "pcm-16" | "aac" | "mp3" | "opus" | null) => import("./file-extensions").FileExtension;
3
3
  validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "gif"];
4
4
  validAudioCodecs: readonly ["pcm-16", "aac", "mp3", "opus"];
5
- getDefaultCrfForCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => number;
6
- getValidCrfRanges: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => [number, number];
7
- isAudioCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif" | undefined) => boolean;
5
+ getDefaultCrfForCodec: (codec: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif") => number;
6
+ getValidCrfRanges: (codec: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif") => [number, number];
7
+ isAudioCodec: (codec: "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif" | undefined) => boolean;
8
8
  proResProfileOptions: readonly ["4444-xq", "4444", "hq", "standard", "light", "proxy"];
9
9
  validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
10
10
  DEFAULT_PIXEL_FORMAT: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
@@ -21,79 +21,79 @@ export declare const BrowserSafeApis: {
21
21
  readonly wav: readonly ["pcm-16"];
22
22
  };
23
23
  defaultFileExtensionMap: {
24
- h264: {
24
+ aac: {
25
25
  default: import("./file-extensions").FileExtension;
26
26
  forAudioCodec: {
27
- aac: {
27
+ "pcm-16": {
28
28
  possible: import("./file-extensions").FileExtension[];
29
29
  default: import("./file-extensions").FileExtension;
30
30
  };
31
- "pcm-16": {
31
+ aac: {
32
32
  possible: import("./file-extensions").FileExtension[];
33
33
  default: import("./file-extensions").FileExtension;
34
34
  };
35
35
  };
36
36
  };
37
- h265: {
37
+ mp3: {
38
38
  default: import("./file-extensions").FileExtension;
39
39
  forAudioCodec: {
40
- aac: {
40
+ "pcm-16": {
41
41
  possible: import("./file-extensions").FileExtension[];
42
42
  default: import("./file-extensions").FileExtension;
43
43
  };
44
- "pcm-16": {
44
+ mp3: {
45
45
  possible: import("./file-extensions").FileExtension[];
46
46
  default: import("./file-extensions").FileExtension;
47
47
  };
48
48
  };
49
49
  };
50
- vp8: {
50
+ h264: {
51
51
  default: import("./file-extensions").FileExtension;
52
52
  forAudioCodec: {
53
53
  "pcm-16": {
54
54
  possible: import("./file-extensions").FileExtension[];
55
55
  default: import("./file-extensions").FileExtension;
56
56
  };
57
- opus: {
57
+ aac: {
58
58
  possible: import("./file-extensions").FileExtension[];
59
59
  default: import("./file-extensions").FileExtension;
60
60
  };
61
61
  };
62
62
  };
63
- vp9: {
63
+ h265: {
64
64
  default: import("./file-extensions").FileExtension;
65
65
  forAudioCodec: {
66
66
  "pcm-16": {
67
67
  possible: import("./file-extensions").FileExtension[];
68
68
  default: import("./file-extensions").FileExtension;
69
69
  };
70
- opus: {
70
+ aac: {
71
71
  possible: import("./file-extensions").FileExtension[];
72
72
  default: import("./file-extensions").FileExtension;
73
73
  };
74
74
  };
75
75
  };
76
- mp3: {
76
+ vp8: {
77
77
  default: import("./file-extensions").FileExtension;
78
78
  forAudioCodec: {
79
- mp3: {
79
+ "pcm-16": {
80
80
  possible: import("./file-extensions").FileExtension[];
81
81
  default: import("./file-extensions").FileExtension;
82
82
  };
83
- "pcm-16": {
83
+ opus: {
84
84
  possible: import("./file-extensions").FileExtension[];
85
85
  default: import("./file-extensions").FileExtension;
86
86
  };
87
87
  };
88
88
  };
89
- aac: {
89
+ vp9: {
90
90
  default: import("./file-extensions").FileExtension;
91
91
  forAudioCodec: {
92
- aac: {
92
+ "pcm-16": {
93
93
  possible: import("./file-extensions").FileExtension[];
94
94
  default: import("./file-extensions").FileExtension;
95
95
  };
96
- "pcm-16": {
96
+ opus: {
97
97
  possible: import("./file-extensions").FileExtension[];
98
98
  default: import("./file-extensions").FileExtension;
99
99
  };
@@ -111,11 +111,11 @@ export declare const BrowserSafeApis: {
111
111
  prores: {
112
112
  default: import("./file-extensions").FileExtension;
113
113
  forAudioCodec: {
114
- aac: {
114
+ "pcm-16": {
115
115
  possible: import("./file-extensions").FileExtension[];
116
116
  default: import("./file-extensions").FileExtension;
117
117
  };
118
- "pcm-16": {
118
+ aac: {
119
119
  possible: import("./file-extensions").FileExtension[];
120
120
  default: import("./file-extensions").FileExtension;
121
121
  };
@@ -141,13 +141,21 @@ export declare const BrowserSafeApis: {
141
141
  };
142
142
  };
143
143
  defaultAudioCodecs: {
144
+ aac: {
145
+ compressed: "pcm-16" | "aac" | null;
146
+ lossless: "pcm-16" | "aac" | null;
147
+ };
148
+ mp3: {
149
+ compressed: "pcm-16" | "mp3" | null;
150
+ lossless: "pcm-16" | "mp3" | null;
151
+ };
144
152
  h264: {
145
- compressed: "aac" | "pcm-16" | null;
146
- lossless: "aac" | "pcm-16" | null;
153
+ compressed: "pcm-16" | "aac" | null;
154
+ lossless: "pcm-16" | "aac" | null;
147
155
  };
148
156
  h265: {
149
- compressed: "aac" | "pcm-16" | null;
150
- lossless: "aac" | "pcm-16" | null;
157
+ compressed: "pcm-16" | "aac" | null;
158
+ lossless: "pcm-16" | "aac" | null;
151
159
  };
152
160
  vp8: {
153
161
  compressed: "pcm-16" | "opus" | null;
@@ -157,21 +165,13 @@ export declare const BrowserSafeApis: {
157
165
  compressed: "pcm-16" | "opus" | null;
158
166
  lossless: "pcm-16" | "opus" | null;
159
167
  };
160
- mp3: {
161
- compressed: "mp3" | "pcm-16" | null;
162
- lossless: "mp3" | "pcm-16" | null;
163
- };
164
- aac: {
165
- compressed: "aac" | "pcm-16" | null;
166
- lossless: "aac" | "pcm-16" | null;
167
- };
168
168
  wav: {
169
169
  compressed: "pcm-16" | null;
170
170
  lossless: "pcm-16" | null;
171
171
  };
172
172
  prores: {
173
- compressed: "aac" | "pcm-16" | null;
174
- lossless: "aac" | "pcm-16" | null;
173
+ compressed: "pcm-16" | "aac" | null;
174
+ lossless: "pcm-16" | "aac" | null;
175
175
  };
176
176
  "h264-mkv": {
177
177
  compressed: "pcm-16" | null;
@@ -182,10 +182,10 @@ export declare const BrowserSafeApis: {
182
182
  lossless: any;
183
183
  };
184
184
  };
185
- defaultCodecsForFileExtension: Record<import("./file-extensions").FileExtension, "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">;
186
- validateOutputFilename: <T_1 extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">({ codec, audioCodec, extension, preferLossless, }: {
185
+ defaultCodecsForFileExtension: Record<import("./file-extensions").FileExtension, "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif">;
186
+ validateOutputFilename: <T_1 extends "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif">({ codec, audioCodec, extension, preferLossless, }: {
187
187
  codec: T_1;
188
- audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null;
188
+ audioCodec: "pcm-16" | "aac" | "mp3" | "opus" | null;
189
189
  extension: string;
190
190
  preferLossless: boolean;
191
191
  }) => void;
@@ -56,10 +56,10 @@ const combineVideos = async (options) => {
56
56
  });
57
57
  await task;
58
58
  onProgress(numberOfFrames);
59
- (fs_1.rmSync !== null && fs_1.rmSync !== void 0 ? fs_1.rmSync : fs_1.rmdirSync)(filelistDir, { recursive: true });
59
+ (0, fs_1.rmSync)(filelistDir, { recursive: true });
60
60
  }
61
61
  catch (err) {
62
- (fs_1.rmSync !== null && fs_1.rmSync !== void 0 ? fs_1.rmSync : fs_1.rmdirSync)(filelistDir, { recursive: true });
62
+ (0, fs_1.rmSync)(filelistDir, { recursive: true });
63
63
  throw err;
64
64
  }
65
65
  };
@@ -31,7 +31,6 @@ const execa_1 = __importDefault(require("execa"));
31
31
  const fs_1 = __importStar(require("fs"));
32
32
  const is_serve_url_1 = require("./is-serve-url");
33
33
  const deleteDirectory = (directory) => {
34
- var _a;
35
34
  if ((0, is_serve_url_1.isServeUrl)(directory)) {
36
35
  return;
37
36
  }
@@ -50,7 +49,7 @@ const deleteDirectory = (directory) => {
50
49
  }
51
50
  }
52
51
  else {
53
- ((_a = fs_1.default.rmSync) !== null && _a !== void 0 ? _a : fs_1.default.rmdirSync)(directory, {
52
+ fs_1.default.rmSync(directory, {
54
53
  recursive: true,
55
54
  });
56
55
  }
@@ -0,0 +1,18 @@
1
+ export declare type EnsureFfmpegOptions = {
2
+ remotionRoot?: string;
3
+ };
4
+ declare type Result = {
5
+ result: 'found-in-path' | 'found-in-node-modules' | 'installed';
6
+ wasAlreadyInstalled: boolean;
7
+ };
8
+ /**
9
+ * @description Checks if the ffmpeg binary is installed and if it is not, downloads it and puts it into your node_modules folder.
10
+ * @see [Documentation](https://www.remotion.dev/docs/renderer/ensure-ffmpeg)
11
+ */
12
+ export declare const ensureFfmpeg: (options?: EnsureFfmpegOptions) => Promise<Result>;
13
+ /**
14
+ * @description Checks if the ffprobe binary is installed and if it is not, downloads it and puts it into your node_modules folder.
15
+ * @see [Documentation](https://www.remotion.dev/docs/renderer/ensure-ffprobe)
16
+ */
17
+ export declare const ensureFfprobe: (options?: EnsureFfmpegOptions) => Promise<Result>;
18
+ export {};
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ensureFfprobe = exports.ensureFfmpeg = void 0;
7
+ const fs_1 = require("fs");
8
+ const os_1 = __importDefault(require("os"));
9
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
10
+ const validate_ffmpeg_1 = require("./validate-ffmpeg");
11
+ const ensureFfmpegOrFfprobe = async (binary, options) => {
12
+ var _a;
13
+ const exists = (0, validate_ffmpeg_1.binaryExists)(binary);
14
+ const remotionRoot = (_a = options === null || options === void 0 ? void 0 : options.remotionRoot) !== null && _a !== void 0 ? _a : process.cwd();
15
+ if (exists) {
16
+ return {
17
+ wasAlreadyInstalled: true,
18
+ result: 'found-in-path',
19
+ };
20
+ }
21
+ if (process.platform === 'linux' && (0, fs_1.existsSync)(ffmpeg_flags_1.lambdaFfmpegPaths[binary])) {
22
+ return {
23
+ wasAlreadyInstalled: true,
24
+ result: 'found-in-path',
25
+ };
26
+ }
27
+ if ((0, ffmpeg_flags_1.ffmpegInNodeModules)(remotionRoot, binary)) {
28
+ return {
29
+ result: 'found-in-node-modules',
30
+ wasAlreadyInstalled: true,
31
+ };
32
+ }
33
+ const binaryUrl = (0, ffmpeg_flags_1.getBinaryDownloadUrl)(binary);
34
+ if (binaryUrl) {
35
+ await (0, ffmpeg_flags_1.downloadBinary)(remotionRoot, binaryUrl.url, binary);
36
+ return {
37
+ result: 'installed',
38
+ wasAlreadyInstalled: false,
39
+ };
40
+ }
41
+ throw new Error(`${binary} could not be installed automatically. Your architecture and OS combination (os = ${os_1.default.platform()}, arch = ${process.arch}) is not supported. Please install ${binary} manually and add "${binary}" to your PATH.`);
42
+ };
43
+ /**
44
+ * @description Checks if the ffmpeg binary is installed and if it is not, downloads it and puts it into your node_modules folder.
45
+ * @see [Documentation](https://www.remotion.dev/docs/renderer/ensure-ffmpeg)
46
+ */
47
+ const ensureFfmpeg = (options) => {
48
+ return ensureFfmpegOrFfprobe('ffmpeg', options);
49
+ };
50
+ exports.ensureFfmpeg = ensureFfmpeg;
51
+ /**
52
+ * @description Checks if the ffprobe binary is installed and if it is not, downloads it and puts it into your node_modules folder.
53
+ * @see [Documentation](https://www.remotion.dev/docs/renderer/ensure-ffprobe)
54
+ */
55
+ const ensureFfprobe = (options) => {
56
+ return ensureFfmpegOrFfprobe('ffprobe', options);
57
+ };
58
+ exports.ensureFfprobe = ensureFfprobe;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { OffthreadVideoImageFormat } from 'remotion';
3
2
  import type { DownloadMap } from './assets/download-map';
4
3
  import type { LastFrameOptions } from './last-frame-from-video-cache';
@@ -0,0 +1 @@
1
+ export declare type FfmpegExecutable = string | null;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,28 +1,48 @@
1
1
  "use strict";
2
2
  // While an FFMPEG filter can be passed directly, if it's too long
3
3
  // we run into Windows command length limits.
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || function (mod) {
21
+ if (mod && mod.__esModule) return mod;
22
+ var result = {};
23
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
24
+ __setModuleDefault(result, mod);
25
+ return result;
26
+ };
4
27
  var __importDefault = (this && this.__importDefault) || function (mod) {
5
28
  return (mod && mod.__esModule) ? mod : { "default": mod };
6
29
  };
7
30
  Object.defineProperty(exports, "__esModule", { value: true });
8
31
  exports.makeFfmpegFilterFileStr = exports.makeFfmpegFilterFile = void 0;
9
- const fs_1 = __importDefault(require("fs"));
32
+ const fs_1 = __importStar(require("fs"));
10
33
  const path_1 = __importDefault(require("path"));
11
- const makeFfmpegFilterFile = async (complexFilter, downloadMap) => {
12
- const random = Math.random().toString().replace('.', '');
13
- const filterFile = path_1.default.join(downloadMap.complexFilter, 'complex-filter-' + random + '.txt');
14
- await fs_1.default.promises.writeFile(filterFile, complexFilter.filter);
15
- return {
16
- file: filterFile,
17
- cleanup: () => {
18
- fs_1.default.unlinkSync(filterFile);
19
- },
20
- };
34
+ const makeFfmpegFilterFile = (complexFilter, downloadMap) => {
35
+ return (0, exports.makeFfmpegFilterFileStr)(complexFilter.filter, downloadMap);
21
36
  };
22
37
  exports.makeFfmpegFilterFile = makeFfmpegFilterFile;
23
38
  const makeFfmpegFilterFileStr = async (complexFilter, downloadMap) => {
24
39
  const random = Math.random().toString().replace('.', '');
25
40
  const filterFile = path_1.default.join(downloadMap.complexFilter, 'complex-filter-' + random + '.txt');
41
+ // Race condition: Sometimes the download map is deleted before the file is written.
42
+ // Can remove this once the original bug has been fixed
43
+ if (!(0, fs_1.existsSync)(downloadMap.complexFilter)) {
44
+ fs_1.default.mkdirSync(downloadMap.complexFilter, { recursive: true });
45
+ }
26
46
  await fs_1.default.promises.writeFile(filterFile, complexFilter);
27
47
  return {
28
48
  file: filterFile,
@@ -0,0 +1,31 @@
1
+ import type { FfmpegExecutable } from './ffmpeg-executable';
2
+ export declare type FfmpegVersion = [number, number, number] | null;
3
+ export declare const getFfmpegBuildInfo: (options: {
4
+ ffmpegExecutable: string | null;
5
+ remotionRoot: string;
6
+ }) => Promise<string>;
7
+ export declare const ffmpegInNodeModules: (remotionRoot: string, binary: 'ffmpeg' | 'ffprobe') => string | null;
8
+ export declare const ffmpegHasFeature: ({ ffmpegExecutable, feature, remotionRoot, }: {
9
+ ffmpegExecutable: string | null;
10
+ feature: 'enable-gpl' | 'enable-libx265' | 'enable-libvpx';
11
+ remotionRoot: string;
12
+ }) => Promise<boolean>;
13
+ export declare const parseFfmpegVersion: (buildconf: string) => FfmpegVersion;
14
+ export declare const getFfmpegVersion: (options: {
15
+ ffmpegExecutable: string | null;
16
+ remotionRoot: string;
17
+ }) => Promise<FfmpegVersion>;
18
+ export declare const downloadBinary: (remotionRoot: string, url: string, binary: 'ffmpeg' | 'ffprobe') => Promise<string>;
19
+ export declare const lambdaFfmpegPaths: {
20
+ readonly ffmpeg: "/opt/bin/ffmpeg";
21
+ readonly ffprobe: "/opt/bin/ffprobe";
22
+ };
23
+ export declare const getExecutableBinary: (ffmpegExecutable: FfmpegExecutable, remotionRoot: string, binary: 'ffmpeg' | 'ffprobe') => string | Promise<string>;
24
+ export declare const getBinaryDownloadUrl: (binary: 'ffmpeg' | 'ffprobe') => {
25
+ url: string;
26
+ contentLength: number;
27
+ } | null;
28
+ export declare const warnAboutFfmpegVersion: ({ ffmpegVersion, buildConf, }: {
29
+ ffmpegVersion: FfmpegVersion;
30
+ buildConf: string | null;
31
+ }) => null | undefined;
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.warnAboutFfmpegVersion = exports.getBinaryDownloadUrl = exports.getExecutableBinary = exports.lambdaFfmpegPaths = exports.downloadBinary = exports.getFfmpegVersion = exports.parseFfmpegVersion = exports.ffmpegHasFeature = exports.ffmpegInNodeModules = exports.getFfmpegBuildInfo = void 0;
7
+ const execa_1 = __importDefault(require("execa"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const BrowserFetcher_1 = require("./browser/BrowserFetcher");
12
+ const validate_ffmpeg_1 = require("./validate-ffmpeg");
13
+ let buildConfig = null;
14
+ const listeners = {};
15
+ const isDownloading = {};
16
+ const getFfmpegBuildInfo = async (options) => {
17
+ if (buildConfig !== null) {
18
+ return buildConfig;
19
+ }
20
+ const data = await (0, execa_1.default)(await (0, exports.getExecutableBinary)(options.ffmpegExecutable, options.remotionRoot, 'ffmpeg'), ['-buildconf'], {
21
+ reject: false,
22
+ });
23
+ buildConfig = data.stderr;
24
+ return buildConfig;
25
+ };
26
+ exports.getFfmpegBuildInfo = getFfmpegBuildInfo;
27
+ const getFfmpegFolderName = (remotionRoot) => {
28
+ return path_1.default.resolve(remotionRoot, 'node_modules/.ffmpeg');
29
+ };
30
+ const binaryPrefix = { ffmpeg: 'ffmpeg-', ffprobe: 'ffprobe-' };
31
+ const randomFfmpegRuntimeId = String(Math.random()).replace('0.', '');
32
+ const ffmpegInNodeModules = (remotionRoot, binary) => {
33
+ const folderName = getFfmpegFolderName(remotionRoot);
34
+ if (!fs_1.default.existsSync(folderName)) {
35
+ fs_1.default.mkdirSync(folderName, {
36
+ recursive: true,
37
+ });
38
+ }
39
+ // Check if a version of FFMPEG is already installed.
40
+ // To qualify, it must have the expected file size
41
+ // to avoid finding binaries that are still being downloaded
42
+ // A random ID is being assigned to the download to avoid conflicts when multiple Remotion processes are running
43
+ const ffmpegInstalled = fs_1.default.readdirSync(folderName).find((filename) => {
44
+ if (!filename.startsWith(binaryPrefix[binary])) {
45
+ return false;
46
+ }
47
+ const dlUrl = (0, exports.getBinaryDownloadUrl)(binary);
48
+ if (!dlUrl) {
49
+ return false;
50
+ }
51
+ const expectedLength = dlUrl.contentLength;
52
+ if (fs_1.default.statSync(path_1.default.join(folderName, filename)).size === expectedLength) {
53
+ return true;
54
+ }
55
+ return false;
56
+ });
57
+ if (ffmpegInstalled) {
58
+ return path_1.default.join(folderName, ffmpegInstalled);
59
+ }
60
+ return null;
61
+ };
62
+ exports.ffmpegInNodeModules = ffmpegInNodeModules;
63
+ const getFfmpegAbsolutePath = (remotionRoot, binary) => {
64
+ const folderName = getFfmpegFolderName(remotionRoot);
65
+ if (!fs_1.default.existsSync(folderName)) {
66
+ fs_1.default.mkdirSync(folderName);
67
+ }
68
+ if (os_1.default.platform() === 'win32') {
69
+ return path_1.default.resolve(folderName, `${binaryPrefix[binary]}${randomFfmpegRuntimeId}.exe`);
70
+ }
71
+ return path_1.default.resolve(folderName, `${binaryPrefix[binary]}${randomFfmpegRuntimeId}`);
72
+ };
73
+ const ffmpegHasFeature = async ({ ffmpegExecutable, feature, remotionRoot, }) => {
74
+ if (ffmpegExecutable && !(0, validate_ffmpeg_1.customExecutableExists)(ffmpegExecutable)) {
75
+ return false;
76
+ }
77
+ if (!(0, validate_ffmpeg_1.binaryExists)('ffmpeg')) {
78
+ return false;
79
+ }
80
+ const config = await (0, exports.getFfmpegBuildInfo)({ ffmpegExecutable, remotionRoot });
81
+ return config.includes(feature);
82
+ };
83
+ exports.ffmpegHasFeature = ffmpegHasFeature;
84
+ const parseFfmpegVersion = (buildconf) => {
85
+ var _a;
86
+ const match = buildconf.match(/ffmpeg version ([0-9]+).([0-9]+)(?:.([0-9]+))?/);
87
+ if (!match) {
88
+ return null;
89
+ }
90
+ return [Number(match[1]), Number(match[2]), Number((_a = match[3]) !== null && _a !== void 0 ? _a : 0)];
91
+ };
92
+ exports.parseFfmpegVersion = parseFfmpegVersion;
93
+ const getFfmpegVersion = async (options) => {
94
+ const buildInfo = await (0, exports.getFfmpegBuildInfo)({
95
+ ffmpegExecutable: options.ffmpegExecutable,
96
+ remotionRoot: options.remotionRoot,
97
+ });
98
+ return (0, exports.parseFfmpegVersion)(buildInfo);
99
+ };
100
+ exports.getFfmpegVersion = getFfmpegVersion;
101
+ const waitForFfmpegToBeDownloaded = (url) => {
102
+ return new Promise((resolve) => {
103
+ if (!listeners[url]) {
104
+ listeners[url] = [];
105
+ }
106
+ listeners[url].push((src) => resolve(src));
107
+ });
108
+ };
109
+ const onProgress = (downloadedBytes, totalBytesToDownload, binary) => {
110
+ console.log('Downloading ', binary, `${toMegabytes(downloadedBytes)}/${toMegabytes(totalBytesToDownload)}`);
111
+ };
112
+ const downloadBinary = async (remotionRoot, url, binary) => {
113
+ const destinationPath = getFfmpegAbsolutePath(remotionRoot, binary);
114
+ const onProgressCallback = (downloadedBytes, _totalBytes) => {
115
+ onProgress(downloadedBytes, _totalBytes, binary);
116
+ };
117
+ isDownloading[url] = true;
118
+ const totalBytes = await (0, BrowserFetcher_1._downloadFile)(url, destinationPath, onProgressCallback);
119
+ onProgress(totalBytes, totalBytes, binary);
120
+ if (os_1.default.platform() !== 'win32') {
121
+ fs_1.default.chmodSync(destinationPath, '777');
122
+ }
123
+ isDownloading[url] = false;
124
+ if (!listeners[url]) {
125
+ listeners[url] = [];
126
+ }
127
+ listeners[url].forEach((listener) => listener(destinationPath));
128
+ listeners[url] = [];
129
+ return destinationPath;
130
+ };
131
+ exports.downloadBinary = downloadBinary;
132
+ exports.lambdaFfmpegPaths = {
133
+ ffmpeg: '/opt/bin/ffmpeg',
134
+ ffprobe: '/opt/bin/ffprobe',
135
+ };
136
+ const getExecutableBinary = (ffmpegExecutable, remotionRoot, binary) => {
137
+ if (fs_1.default.existsSync(exports.lambdaFfmpegPaths[binary])) {
138
+ return exports.lambdaFfmpegPaths[binary];
139
+ }
140
+ if (ffmpegExecutable && (0, validate_ffmpeg_1.customExecutableExists)(ffmpegExecutable)) {
141
+ return ffmpegExecutable;
142
+ }
143
+ if ((0, validate_ffmpeg_1.binaryExists)(binary)) {
144
+ return binary;
145
+ }
146
+ const dlUrl = (0, exports.getBinaryDownloadUrl)(binary);
147
+ if (dlUrl && isDownloading[dlUrl.url]) {
148
+ return waitForFfmpegToBeDownloaded(dlUrl.url);
149
+ }
150
+ const inNodeMod = (0, exports.ffmpegInNodeModules)(remotionRoot, binary);
151
+ if (inNodeMod) {
152
+ return inNodeMod;
153
+ }
154
+ if (!dlUrl) {
155
+ throw new Error(`${binary} could not be installed automatically. Your architecture and OS combination (os = ${os_1.default.platform()}, arch = ${process.arch}) is not supported. Please install ${binary} manually and add "${binary}" to your PATH.`);
156
+ }
157
+ return (0, exports.downloadBinary)(remotionRoot, dlUrl.url, binary);
158
+ };
159
+ exports.getExecutableBinary = getExecutableBinary;
160
+ function toMegabytes(bytes) {
161
+ const mb = bytes / 1024 / 1024;
162
+ return `${Math.round(mb * 10) / 10} Mb`;
163
+ }
164
+ const getBinaryDownloadUrl = (binary) => {
165
+ if (os_1.default.platform() === 'win32' && process.arch === 'x64') {
166
+ return binary === 'ffmpeg'
167
+ ? {
168
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffmpeg-win-x86.exe',
169
+ contentLength: 127531008,
170
+ }
171
+ : {
172
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffprobe-win-x86.exe',
173
+ contentLength: 127425536,
174
+ };
175
+ }
176
+ if (os_1.default.platform() === 'darwin' && process.arch === 'arm64') {
177
+ return binary === 'ffmpeg'
178
+ ? {
179
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffmpeg-macos-arm64',
180
+ contentLength: 42093320,
181
+ }
182
+ : {
183
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffprobe-macos-arm64-v2',
184
+ contentLength: 46690008,
185
+ };
186
+ }
187
+ if (os_1.default.platform() === 'darwin' && process.arch === 'x64') {
188
+ return binary === 'ffmpeg'
189
+ ? {
190
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffmpeg-macos-x86',
191
+ contentLength: 78380700,
192
+ }
193
+ : {
194
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffprobe-macos-x86',
195
+ contentLength: 77364284,
196
+ };
197
+ }
198
+ if (os_1.default.platform() === 'linux' && process.arch === 'x64') {
199
+ return binary === 'ffmpeg'
200
+ ? {
201
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffmpeg-linux-amd64',
202
+ contentLength: 78502560,
203
+ }
204
+ : {
205
+ url: 'https://remotion-ffmpeg-binaries.s3.eu-central-1.amazonaws.com/ffprobe-linux-amd64',
206
+ contentLength: 78400704,
207
+ };
208
+ }
209
+ return null;
210
+ };
211
+ exports.getBinaryDownloadUrl = getBinaryDownloadUrl;
212
+ const printMessage = (ffmpegVersion) => {
213
+ console.warn('⚠️Old FFMPEG version detected: ' + ffmpegVersion.join('.'));
214
+ console.warn(' You need at least version 4.1.0.');
215
+ console.warn(' Upgrade FFMPEG to get rid of this warning.');
216
+ };
217
+ const printBuildConfMessage = () => {
218
+ console.error('⚠️ Unsupported FFMPEG version detected.');
219
+ console.error(" Your version doesn't support the -buildconf flag");
220
+ console.error(' Audio will not be supported and you may experience other issues.');
221
+ console.error(' Upgrade FFMPEG to at least v4.1.0 to get rid of this warning.');
222
+ };
223
+ const warnAboutFfmpegVersion = ({ ffmpegVersion, buildConf, }) => {
224
+ if (buildConf === null) {
225
+ printBuildConfMessage();
226
+ return;
227
+ }
228
+ if (ffmpegVersion === null) {
229
+ return null;
230
+ }
231
+ const [major, minor] = ffmpegVersion;
232
+ // 3.x and below definitely is too old
233
+ if (major < 4) {
234
+ printMessage(ffmpegVersion);
235
+ return;
236
+ }
237
+ // 5.x will be all good
238
+ if (major > 4) {
239
+ return;
240
+ }
241
+ if (minor < 1) {
242
+ printMessage(ffmpegVersion);
243
+ }
244
+ };
245
+ exports.warnAboutFfmpegVersion = warnAboutFfmpegVersion;
@@ -1,6 +1,6 @@
1
1
  import type { AudioCodec } from './audio-codec';
2
2
  import type { Codec } from './codec';
3
3
  import type { FileExtension } from './file-extensions';
4
- export declare const getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">(codec: T, audioCodec: AudioCodec | null) => FileExtension;
5
- export declare const makeFileExtensionMap: () => Record<string, ("h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif")[]>;
4
+ export declare const getFileExtensionFromCodec: <T extends "aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif">(codec: T, audioCodec: AudioCodec | null) => FileExtension;
5
+ export declare const makeFileExtensionMap: () => Record<string, ("aac" | "mp3" | "h264" | "h265" | "vp8" | "vp9" | "wav" | "prores" | "h264-mkv" | "gif")[]>;
6
6
  export declare const defaultCodecsForFileExtension: Record<FileExtension, Codec>;