@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.
- package/dist/client.d.ts +39 -39
- package/dist/combine-videos.js +2 -2
- package/dist/delete-directory.js +1 -2
- package/dist/ensure-ffmpeg.d.ts +18 -0
- package/dist/ensure-ffmpeg.js +58 -0
- package/dist/extract-frame-from-video.d.ts +0 -1
- package/dist/ffmpeg-executable.d.ts +1 -0
- package/dist/ffmpeg-executable.js +2 -0
- package/dist/ffmpeg-filter-file.js +31 -11
- package/dist/ffmpeg-flags.d.ts +31 -0
- package/dist/ffmpeg-flags.js +245 -0
- package/dist/get-extension-from-codec.d.ts +2 -2
- package/dist/get-frame-of-video-slow.d.ts +4 -2
- package/dist/get-frame-to-render.js +1 -1
- package/dist/get-local-browser-executable.js +1 -0
- package/dist/index.d.ts +33 -34
- package/dist/index.js +2 -2
- package/dist/jpeg-quality.d.ts +1 -0
- package/dist/jpeg-quality.js +21 -0
- package/dist/last-frame-from-video-cache.d.ts +0 -1
- package/dist/legacy-webpack-config.d.ts +9 -0
- package/dist/legacy-webpack-config.js +13 -0
- package/dist/options/jpeg-quality.js +3 -3
- package/dist/provide-screenshot.d.ts +2 -3
- package/dist/provide-screenshot.js +2 -2
- package/dist/puppeteer-screenshot.d.ts +1 -2
- package/dist/puppeteer-screenshot.js +7 -7
- package/dist/render-frames.d.ts +5 -1
- package/dist/render-frames.js +9 -6
- package/dist/render-media.d.ts +5 -1
- package/dist/render-media.js +7 -4
- package/dist/render-still.d.ts +5 -1
- package/dist/render-still.js +8 -5
- package/dist/screenshot-dom-element.d.ts +2 -3
- package/dist/screenshot-dom-element.js +2 -2
- package/dist/screenshot-task.d.ts +2 -3
- package/dist/screenshot-task.js +2 -2
- package/dist/take-frame-and-compose.d.ts +2 -3
- package/dist/take-frame-and-compose.js +2 -2
- package/dist/tmp-dir.js +1 -2
- package/dist/try-to-extract-frame-of-video-fast.d.ts +0 -1
- package/dist/validate-ffmpeg.d.ts +7 -0
- package/dist/validate-ffmpeg.js +77 -0
- package/dist/validate-output-filename.d.ts +1 -1
- package/dist/warn-about-ffmpeg-version.d.ts +5 -0
- package/dist/warn-about-ffmpeg-version.js +37 -0
- 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 "
|
|
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: "
|
|
6
|
-
getValidCrfRanges: (codec: "
|
|
7
|
-
isAudioCodec: (codec: "
|
|
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
|
-
|
|
24
|
+
aac: {
|
|
25
25
|
default: import("./file-extensions").FileExtension;
|
|
26
26
|
forAudioCodec: {
|
|
27
|
-
|
|
27
|
+
"pcm-16": {
|
|
28
28
|
possible: import("./file-extensions").FileExtension[];
|
|
29
29
|
default: import("./file-extensions").FileExtension;
|
|
30
30
|
};
|
|
31
|
-
|
|
31
|
+
aac: {
|
|
32
32
|
possible: import("./file-extensions").FileExtension[];
|
|
33
33
|
default: import("./file-extensions").FileExtension;
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
36
|
};
|
|
37
|
-
|
|
37
|
+
mp3: {
|
|
38
38
|
default: import("./file-extensions").FileExtension;
|
|
39
39
|
forAudioCodec: {
|
|
40
|
-
|
|
40
|
+
"pcm-16": {
|
|
41
41
|
possible: import("./file-extensions").FileExtension[];
|
|
42
42
|
default: import("./file-extensions").FileExtension;
|
|
43
43
|
};
|
|
44
|
-
|
|
44
|
+
mp3: {
|
|
45
45
|
possible: import("./file-extensions").FileExtension[];
|
|
46
46
|
default: import("./file-extensions").FileExtension;
|
|
47
47
|
};
|
|
48
48
|
};
|
|
49
49
|
};
|
|
50
|
-
|
|
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
|
-
|
|
57
|
+
aac: {
|
|
58
58
|
possible: import("./file-extensions").FileExtension[];
|
|
59
59
|
default: import("./file-extensions").FileExtension;
|
|
60
60
|
};
|
|
61
61
|
};
|
|
62
62
|
};
|
|
63
|
-
|
|
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
|
-
|
|
70
|
+
aac: {
|
|
71
71
|
possible: import("./file-extensions").FileExtension[];
|
|
72
72
|
default: import("./file-extensions").FileExtension;
|
|
73
73
|
};
|
|
74
74
|
};
|
|
75
75
|
};
|
|
76
|
-
|
|
76
|
+
vp8: {
|
|
77
77
|
default: import("./file-extensions").FileExtension;
|
|
78
78
|
forAudioCodec: {
|
|
79
|
-
|
|
79
|
+
"pcm-16": {
|
|
80
80
|
possible: import("./file-extensions").FileExtension[];
|
|
81
81
|
default: import("./file-extensions").FileExtension;
|
|
82
82
|
};
|
|
83
|
-
|
|
83
|
+
opus: {
|
|
84
84
|
possible: import("./file-extensions").FileExtension[];
|
|
85
85
|
default: import("./file-extensions").FileExtension;
|
|
86
86
|
};
|
|
87
87
|
};
|
|
88
88
|
};
|
|
89
|
-
|
|
89
|
+
vp9: {
|
|
90
90
|
default: import("./file-extensions").FileExtension;
|
|
91
91
|
forAudioCodec: {
|
|
92
|
-
|
|
92
|
+
"pcm-16": {
|
|
93
93
|
possible: import("./file-extensions").FileExtension[];
|
|
94
94
|
default: import("./file-extensions").FileExtension;
|
|
95
95
|
};
|
|
96
|
-
|
|
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
|
-
|
|
114
|
+
"pcm-16": {
|
|
115
115
|
possible: import("./file-extensions").FileExtension[];
|
|
116
116
|
default: import("./file-extensions").FileExtension;
|
|
117
117
|
};
|
|
118
|
-
|
|
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: "
|
|
146
|
-
lossless: "
|
|
153
|
+
compressed: "pcm-16" | "aac" | null;
|
|
154
|
+
lossless: "pcm-16" | "aac" | null;
|
|
147
155
|
};
|
|
148
156
|
h265: {
|
|
149
|
-
compressed: "
|
|
150
|
-
lossless: "
|
|
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: "
|
|
174
|
-
lossless: "
|
|
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, "
|
|
186
|
-
validateOutputFilename: <T_1 extends "
|
|
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: "
|
|
188
|
+
audioCodec: "pcm-16" | "aac" | "mp3" | "opus" | null;
|
|
189
189
|
extension: string;
|
|
190
190
|
preferLossless: boolean;
|
|
191
191
|
}) => void;
|
package/dist/combine-videos.js
CHANGED
|
@@ -56,10 +56,10 @@ const combineVideos = async (options) => {
|
|
|
56
56
|
});
|
|
57
57
|
await task;
|
|
58
58
|
onProgress(numberOfFrames);
|
|
59
|
-
(
|
|
59
|
+
(0, fs_1.rmSync)(filelistDir, { recursive: true });
|
|
60
60
|
}
|
|
61
61
|
catch (err) {
|
|
62
|
-
(
|
|
62
|
+
(0, fs_1.rmSync)(filelistDir, { recursive: true });
|
|
63
63
|
throw err;
|
|
64
64
|
}
|
|
65
65
|
};
|
package/dist/delete-directory.js
CHANGED
|
@@ -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
|
-
|
|
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;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare type FfmpegExecutable = string | null;
|
|
@@ -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 =
|
|
32
|
+
const fs_1 = __importStar(require("fs"));
|
|
10
33
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const makeFfmpegFilterFile =
|
|
12
|
-
|
|
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 "
|
|
5
|
-
export declare const makeFileExtensionMap: () => Record<string, ("
|
|
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>;
|