@remotion/renderer 3.2.31 → 3.2.33
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/check-apple-silicon.d.ts +1 -1
- package/dist/check-apple-silicon.js +9 -5
- package/dist/crf.d.ts +5 -1
- package/dist/crf.js +33 -6
- package/dist/extract-frame-from-video.d.ts +1 -0
- package/dist/ffmpeg-args-hook.d.ts +4 -0
- package/dist/ffmpeg-args-hook.js +2 -0
- package/dist/ffmpeg-flags.d.ts +4 -0
- package/dist/ffmpeg-flags.js +36 -2
- package/dist/get-compositions.js +6 -4
- package/dist/index.d.ts +16 -14
- package/dist/index.js +5 -5
- package/dist/last-frame-from-video-cache.d.ts +1 -0
- package/dist/make-assets-download-dir.d.ts +1 -0
- package/dist/make-assets-download-dir.js +13 -0
- package/dist/prespawn-ffmpeg.d.ts +2 -1
- package/dist/prespawn-ffmpeg.js +12 -11
- package/dist/render-frames.js +2 -1
- package/dist/render-media.d.ts +4 -1
- package/dist/render-media.js +11 -5
- package/dist/stitch-frames-to-video.d.ts +2 -0
- package/dist/stitch-frames-to-video.js +21 -16
- package/dist/validate-ffmpeg-args-hook.d.ts +2 -0
- package/dist/validate-ffmpeg-args-hook.js +12 -0
- package/dist/validate-ffmpeg-override-fn.d.ts +2 -0
- package/dist/validate-ffmpeg-override-fn.js +12 -0
- package/dist/validate-ffmpeg.d.ts +4 -1
- package/dist/validate-ffmpeg.js +20 -7
- package/dist/validate-videobitrate.d.ts +1 -0
- package/dist/validate-videobitrate.js +20 -0
- package/dist/warn-about-ffmpeg-version.d.ts +5 -0
- package/dist/warn-about-ffmpeg-version.js +37 -0
- package/package.json +4 -4
- package/dist/find-closest-package-json.d.ts +0 -2
- package/dist/find-closest-package-json.js +0 -34
- package/vitest.config.ts +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const checkNodeVersionAndWarnAboutRosetta: () => void;
|
|
@@ -23,17 +23,21 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
26
|
+
exports.checkNodeVersionAndWarnAboutRosetta = void 0;
|
|
27
27
|
const os = __importStar(require("os"));
|
|
28
|
-
const
|
|
28
|
+
const checkNodeVersionAndWarnAboutRosetta = () => {
|
|
29
29
|
// see https://github.com/nodejs/node/issues/41900#issuecomment-1113511254
|
|
30
30
|
const cpus = os.cpus();
|
|
31
31
|
const isAppleSilicon = cpus[0].model.includes('Apple');
|
|
32
32
|
const isArm64 = os.arch() === 'arm64';
|
|
33
|
+
const version = process.version.replace('v', '').split('.');
|
|
34
|
+
const majorVersion = Number(version[0]);
|
|
35
|
+
const requiredNodeVersion = 14;
|
|
36
|
+
if (majorVersion < 13) {
|
|
37
|
+
throw new Error(`Remotion requires at least Node ${requiredNodeVersion}. You currently have ${process.version}. Update your node version to ${requiredNodeVersion} to use Remotion.`);
|
|
38
|
+
}
|
|
33
39
|
if (isAppleSilicon && !isArm64) {
|
|
34
40
|
const recommendedNodeVersion = 16;
|
|
35
|
-
const version = process.version.replace('v', '').split('.');
|
|
36
|
-
const majorVersion = Number(version[0]);
|
|
37
41
|
const recommendNodeUpgrade = majorVersion < recommendedNodeVersion;
|
|
38
42
|
console.warn([
|
|
39
43
|
`⚠️ Apple Silicon detected but Node.JS running under Rosetta. This will cause performance issues.\n`,
|
|
@@ -48,4 +52,4 @@ const warnIfAppleSiliconIsNotUsingArm64Architecture = () => {
|
|
|
48
52
|
.join('\n'));
|
|
49
53
|
}
|
|
50
54
|
};
|
|
51
|
-
exports.
|
|
55
|
+
exports.checkNodeVersionAndWarnAboutRosetta = checkNodeVersionAndWarnAboutRosetta;
|
package/dist/crf.d.ts
CHANGED
|
@@ -2,4 +2,8 @@ import type { Codec } from './codec';
|
|
|
2
2
|
export declare type Crf = number | undefined;
|
|
3
3
|
export declare const getDefaultCrfForCodec: (codec: Codec) => number;
|
|
4
4
|
export declare const getValidCrfRanges: (codec: Codec) => [number, number];
|
|
5
|
-
export declare const
|
|
5
|
+
export declare const validateQualitySettings: ({ codec, crf, videoBitrate, }: {
|
|
6
|
+
crf: unknown;
|
|
7
|
+
codec: Codec;
|
|
8
|
+
videoBitrate: string | null | undefined;
|
|
9
|
+
}) => string[];
|
package/dist/crf.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.validateQualitySettings = exports.getValidCrfRanges = exports.getDefaultCrfForCodec = void 0;
|
|
4
4
|
const is_audio_codec_1 = require("./is-audio-codec");
|
|
5
5
|
const getDefaultCrfForCodec = (codec) => {
|
|
6
6
|
if ((0, is_audio_codec_1.isAudioCodec)(codec)) {
|
|
@@ -46,19 +46,46 @@ const getValidCrfRanges = (codec) => {
|
|
|
46
46
|
throw new TypeError(`Got unexpected codec "${codec}"`);
|
|
47
47
|
};
|
|
48
48
|
exports.getValidCrfRanges = getValidCrfRanges;
|
|
49
|
-
const
|
|
50
|
-
if (crf
|
|
51
|
-
|
|
49
|
+
const validateQualitySettings = ({ codec, crf, videoBitrate, }) => {
|
|
50
|
+
if (crf && videoBitrate) {
|
|
51
|
+
throw new Error('"crf" and "videoBitrate" can not both be set. Choose one of either.');
|
|
52
|
+
}
|
|
53
|
+
if (videoBitrate) {
|
|
54
|
+
if (codec === 'prores') {
|
|
55
|
+
console.warn('ProRes does not support videoBitrate. Ignoring.');
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
if ((0, is_audio_codec_1.isAudioCodec)(codec)) {
|
|
59
|
+
console.warn(`${codec} does not support videoBitrate. Ignoring.`);
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return ['-b:v', videoBitrate];
|
|
63
|
+
}
|
|
64
|
+
if (crf === null || typeof crf === 'undefined') {
|
|
65
|
+
const actualCrf = (0, exports.getDefaultCrfForCodec)(codec);
|
|
66
|
+
return ['-crf', String(actualCrf)];
|
|
52
67
|
}
|
|
53
68
|
if (typeof crf !== 'number') {
|
|
54
69
|
throw new TypeError('Expected CRF to be a number, but is ' + JSON.stringify(crf));
|
|
55
70
|
}
|
|
56
71
|
const range = (0, exports.getValidCrfRanges)(codec);
|
|
57
72
|
if (crf === 0 && (codec === 'h264' || codec === 'h264-mkv')) {
|
|
58
|
-
throw new TypeError("Setting the CRF to 0 with a H264 codec is not supported anymore because of it's inconsistencies between platforms. Videos with CRF 0 cannot be played on iOS/macOS. 0 is a extreme value with inefficient settings which you probably want. Set CRF to a higher value to fix this error.");
|
|
73
|
+
throw new TypeError("Setting the CRF to 0 with a H264 codec is not supported anymore because of it's inconsistencies between platforms. Videos with CRF 0 cannot be played on iOS/macOS. 0 is a extreme value with inefficient settings which you probably do not want. Set CRF to a higher value to fix this error.");
|
|
59
74
|
}
|
|
60
75
|
if (crf < range[0] || crf > range[1]) {
|
|
76
|
+
if (range[0] === 0 && range[1] === 0) {
|
|
77
|
+
throw new TypeError(`The "${codec}" codec does not support the --crf option.`);
|
|
78
|
+
}
|
|
61
79
|
throw new TypeError(`CRF must be between ${range[0]} and ${range[1]} for codec ${codec}. Passed: ${crf}`);
|
|
62
80
|
}
|
|
81
|
+
if (codec === 'prores') {
|
|
82
|
+
console.warn('ProRes does not support the "crf" option. Ignoring.');
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
if ((0, is_audio_codec_1.isAudioCodec)(codec)) {
|
|
86
|
+
console.warn(`${codec} does not support the "crf" option. Ignoring.`);
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
return ['-crf', String(crf)];
|
|
63
90
|
};
|
|
64
|
-
exports.
|
|
91
|
+
exports.validateQualitySettings = validateQualitySettings;
|
package/dist/ffmpeg-flags.d.ts
CHANGED
|
@@ -10,3 +10,7 @@ export declare const parseFfmpegVersion: (buildconf: string) => FfmpegVersion;
|
|
|
10
10
|
export declare const getFfmpegVersion: (options: {
|
|
11
11
|
ffmpegExecutable: string | null;
|
|
12
12
|
}) => Promise<FfmpegVersion>;
|
|
13
|
+
export declare const warnAboutFfmpegVersion: ({ ffmpegVersion, buildConf, }: {
|
|
14
|
+
ffmpegVersion: FfmpegVersion;
|
|
15
|
+
buildConf: string | null;
|
|
16
|
+
}) => null | undefined;
|
package/dist/ffmpeg-flags.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getFfmpegVersion = exports.parseFfmpegVersion = exports.ffmpegHasFeature = exports.getFfmpegBuildInfo = void 0;
|
|
6
|
+
exports.warnAboutFfmpegVersion = exports.getFfmpegVersion = exports.parseFfmpegVersion = exports.ffmpegHasFeature = exports.getFfmpegBuildInfo = void 0;
|
|
7
7
|
const execa_1 = __importDefault(require("execa"));
|
|
8
8
|
const validate_ffmpeg_1 = require("./validate-ffmpeg");
|
|
9
9
|
let buildConfig = null;
|
|
@@ -20,7 +20,7 @@ const getFfmpegBuildInfo = async (options) => {
|
|
|
20
20
|
};
|
|
21
21
|
exports.getFfmpegBuildInfo = getFfmpegBuildInfo;
|
|
22
22
|
const ffmpegHasFeature = async ({ ffmpegExecutable, feature, }) => {
|
|
23
|
-
if (!(
|
|
23
|
+
if (!(0, validate_ffmpeg_1.binaryExists)('ffmpeg', ffmpegExecutable)) {
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
const config = await (0, exports.getFfmpegBuildInfo)({ ffmpegExecutable });
|
|
@@ -43,3 +43,37 @@ const getFfmpegVersion = async (options) => {
|
|
|
43
43
|
return (0, exports.parseFfmpegVersion)(buildInfo);
|
|
44
44
|
};
|
|
45
45
|
exports.getFfmpegVersion = getFfmpegVersion;
|
|
46
|
+
const printMessage = (ffmpegVersion) => {
|
|
47
|
+
console.warn('⚠️Old FFMPEG version detected: ' + ffmpegVersion.join('.'));
|
|
48
|
+
console.warn(' For audio support, you need at least version 4.1.0.');
|
|
49
|
+
console.warn(' Upgrade FFMPEG to get rid of this warning.');
|
|
50
|
+
};
|
|
51
|
+
const printBuildConfMessage = () => {
|
|
52
|
+
console.error('⚠️ Unsupported FFMPEG version detected.');
|
|
53
|
+
console.error(" Your version doesn't support the -buildconf flag");
|
|
54
|
+
console.error(' Audio will not be supported and you may experience other issues.');
|
|
55
|
+
console.error(' Upgrade FFMPEG to at least v4.1.0 to get rid of this warning.');
|
|
56
|
+
};
|
|
57
|
+
const warnAboutFfmpegVersion = ({ ffmpegVersion, buildConf, }) => {
|
|
58
|
+
if (buildConf === null) {
|
|
59
|
+
printBuildConfMessage();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (ffmpegVersion === null) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const [major, minor] = ffmpegVersion;
|
|
66
|
+
// 3.x and below definitely is too old
|
|
67
|
+
if (major < 4) {
|
|
68
|
+
printMessage(ffmpegVersion);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// 5.x will be all good
|
|
72
|
+
if (major > 4) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (minor < 1) {
|
|
76
|
+
printMessage(ffmpegVersion);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
exports.warnAboutFfmpegVersion = warnAboutFfmpegVersion;
|
package/dist/get-compositions.js
CHANGED
|
@@ -7,6 +7,7 @@ const get_browser_instance_1 = require("./get-browser-instance");
|
|
|
7
7
|
const prepare_server_1 = require("./prepare-server");
|
|
8
8
|
const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
|
|
9
9
|
const set_props_and_env_1 = require("./set-props-and-env");
|
|
10
|
+
const validate_ffmpeg_1 = require("./validate-ffmpeg");
|
|
10
11
|
const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
|
|
11
12
|
const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
|
|
12
13
|
if (config === null || config === void 0 ? void 0 : config.onBrowserLog) {
|
|
@@ -54,12 +55,13 @@ const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
|
|
|
54
55
|
return result;
|
|
55
56
|
};
|
|
56
57
|
const getCompositions = async (serveUrlOrWebpackUrl, config) => {
|
|
57
|
-
var _a, _b, _c;
|
|
58
|
-
|
|
58
|
+
var _a, _b, _c, _d;
|
|
59
|
+
await (0, validate_ffmpeg_1.validateFfmpeg)((_a = config === null || config === void 0 ? void 0 : config.ffmpegExecutable) !== null && _a !== void 0 ? _a : null);
|
|
60
|
+
const downloadMap = (_b = config === null || config === void 0 ? void 0 : config.downloadMap) !== null && _b !== void 0 ? _b : (0, download_map_1.makeDownloadMap)();
|
|
59
61
|
const { page, cleanup } = await (0, get_browser_instance_1.getPageAndCleanupFn)({
|
|
60
62
|
passedInInstance: config === null || config === void 0 ? void 0 : config.puppeteerInstance,
|
|
61
|
-
browserExecutable: (
|
|
62
|
-
chromiumOptions: (
|
|
63
|
+
browserExecutable: (_c = config === null || config === void 0 ? void 0 : config.browserExecutable) !== null && _c !== void 0 ? _c : null,
|
|
64
|
+
chromiumOptions: (_d = config === null || config === void 0 ? void 0 : config.chromiumOptions) !== null && _d !== void 0 ? _d : {},
|
|
63
65
|
});
|
|
64
66
|
return new Promise((resolve, reject) => {
|
|
65
67
|
var _a, _b, _c;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import execa from 'execa';
|
|
2
3
|
import { SymbolicateableError } from './error-handling/symbolicateable-error';
|
|
3
4
|
import { mimeContentType, mimeLookup } from './mime-types';
|
|
@@ -38,14 +39,8 @@ export declare const RenderInternals: {
|
|
|
38
39
|
feature: "enable-gpl" | "enable-libx265" | "enable-libvpx";
|
|
39
40
|
}) => Promise<boolean>;
|
|
40
41
|
getActualConcurrency: (userPreference: number | null) => number;
|
|
41
|
-
getFfmpegVersion: (options: {
|
|
42
|
-
ffmpegExecutable: string | null;
|
|
43
|
-
}) => Promise<import("./ffmpeg-flags").FfmpegVersion>;
|
|
44
42
|
validateFfmpeg: (customFfmpegBinary: string | null) => Promise<void>;
|
|
45
|
-
binaryExists: (name: "ffmpeg" | "brew", localFFmpeg: string | null) =>
|
|
46
|
-
getFfmpegBuildInfo: (options: {
|
|
47
|
-
ffmpegExecutable: string | null;
|
|
48
|
-
}) => Promise<string>;
|
|
43
|
+
binaryExists: (name: "ffmpeg" | "brew", localFFmpeg: string | null) => boolean;
|
|
49
44
|
serveStatic: (path: string | null, options: {
|
|
50
45
|
port: number | null;
|
|
51
46
|
ffmpegExecutable: import("./ffmpeg-executable").FfmpegExecutable;
|
|
@@ -68,7 +63,7 @@ export declare const RenderInternals: {
|
|
|
68
63
|
task: Promise<Buffer | null>;
|
|
69
64
|
getLogs: () => string;
|
|
70
65
|
}>;
|
|
71
|
-
getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "gif" | "
|
|
66
|
+
getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "gif" | "webm" | "mp4" | "mov" | "mkv";
|
|
72
67
|
tmpDir: (str: string) => string;
|
|
73
68
|
deleteDirectory: (directory: string) => Promise<void>;
|
|
74
69
|
isServeUrl: (potentialUrl: string) => boolean;
|
|
@@ -123,10 +118,13 @@ export declare const RenderInternals: {
|
|
|
123
118
|
validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
|
|
124
119
|
DEFAULT_BROWSER: import("./browser").Browser;
|
|
125
120
|
validateFrameRange: (frameRange: import("./frame-range").FrameRange | null) => void;
|
|
126
|
-
DEFAULT_OPENGL_RENDERER: "
|
|
127
|
-
validateOpenGlRenderer: (option: "
|
|
128
|
-
|
|
129
|
-
|
|
121
|
+
DEFAULT_OPENGL_RENDERER: "angle" | "swangle" | "egl" | "swiftshader" | null;
|
|
122
|
+
validateOpenGlRenderer: (option: "angle" | "swangle" | "egl" | "swiftshader" | null) => "angle" | "swangle" | "egl" | "swiftshader" | null;
|
|
123
|
+
validateQualitySettings: ({ codec, crf, videoBitrate, }: {
|
|
124
|
+
crf: unknown;
|
|
125
|
+
codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
|
|
126
|
+
videoBitrate: string | null | undefined;
|
|
127
|
+
}) => string[];
|
|
130
128
|
validImageFormats: readonly ["png", "jpeg", "none"];
|
|
131
129
|
validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "gif"];
|
|
132
130
|
DEFAULT_PIXEL_FORMAT: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
|
|
@@ -137,9 +135,9 @@ export declare const RenderInternals: {
|
|
|
137
135
|
validateSelectedPixelFormatAndCodecCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => void;
|
|
138
136
|
validateSelectedCodecAndProResCombination: ({ codec, proResProfile, }: {
|
|
139
137
|
codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
|
|
140
|
-
proResProfile: "4444-xq" | "4444" | "hq" | "standard" | "light" |
|
|
138
|
+
proResProfile: "proxy" | "4444-xq" | "4444" | "hq" | "standard" | "light" | undefined;
|
|
141
139
|
}) => void;
|
|
142
|
-
validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "
|
|
140
|
+
validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "jpeg" | "png" | "none") => "none" | "valid";
|
|
143
141
|
DEFAULT_CODEC: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
|
|
144
142
|
isAudioCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif" | undefined) => boolean;
|
|
145
143
|
logLevels: readonly ["verbose", "info", "warn", "error"];
|
|
@@ -153,4 +151,8 @@ export declare const RenderInternals: {
|
|
|
153
151
|
frame: number;
|
|
154
152
|
durationInFrames: number;
|
|
155
153
|
}) => number;
|
|
154
|
+
validateBitrate: (bitrate: unknown, name: string) => void;
|
|
155
|
+
getFfmpegVersion: (options: {
|
|
156
|
+
ffmpegExecutable: string | null;
|
|
157
|
+
}) => Promise<import("./ffmpeg-flags").FfmpegVersion>;
|
|
156
158
|
};
|
package/dist/index.js
CHANGED
|
@@ -74,6 +74,7 @@ const validate_frame_1 = require("./validate-frame");
|
|
|
74
74
|
const validate_opengl_renderer_1 = require("./validate-opengl-renderer");
|
|
75
75
|
const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
|
|
76
76
|
const validate_scale_1 = require("./validate-scale");
|
|
77
|
+
const validate_videobitrate_1 = require("./validate-videobitrate");
|
|
77
78
|
const wait_for_symbolication_error_to_be_done_1 = require("./wait-for-symbolication-error-to-be-done");
|
|
78
79
|
var combine_videos_1 = require("./combine-videos");
|
|
79
80
|
Object.defineProperty(exports, "combineVideos", { enumerable: true, get: function () { return combine_videos_1.combineVideos; } });
|
|
@@ -102,10 +103,8 @@ exports.RenderInternals = {
|
|
|
102
103
|
ensureLocalBrowser: get_local_browser_executable_1.ensureLocalBrowser,
|
|
103
104
|
ffmpegHasFeature: ffmpeg_flags_1.ffmpegHasFeature,
|
|
104
105
|
getActualConcurrency: get_concurrency_1.getActualConcurrency,
|
|
105
|
-
getFfmpegVersion: ffmpeg_flags_1.getFfmpegVersion,
|
|
106
106
|
validateFfmpeg: validate_ffmpeg_1.validateFfmpeg,
|
|
107
107
|
binaryExists: validate_ffmpeg_1.binaryExists,
|
|
108
|
-
getFfmpegBuildInfo: ffmpeg_flags_1.getFfmpegBuildInfo,
|
|
109
108
|
serveStatic: serve_static_1.serveStatic,
|
|
110
109
|
validateEvenDimensionsWithCodec: validate_even_dimensions_with_codec_1.validateEvenDimensionsWithCodec,
|
|
111
110
|
normalizeServeUrl: normalize_serve_url_1.normalizeServeUrl,
|
|
@@ -139,8 +138,7 @@ exports.RenderInternals = {
|
|
|
139
138
|
validateFrameRange: frame_range_1.validateFrameRange,
|
|
140
139
|
DEFAULT_OPENGL_RENDERER: validate_opengl_renderer_1.DEFAULT_OPENGL_RENDERER,
|
|
141
140
|
validateOpenGlRenderer: validate_opengl_renderer_1.validateOpenGlRenderer,
|
|
142
|
-
|
|
143
|
-
validateSelectedCrfAndCodecCombination: crf_1.validateSelectedCrfAndCodecCombination,
|
|
141
|
+
validateQualitySettings: crf_1.validateQualitySettings,
|
|
144
142
|
validImageFormats: image_format_1.validImageFormats,
|
|
145
143
|
validCodecs: codec_1.validCodecs,
|
|
146
144
|
DEFAULT_PIXEL_FORMAT: pixel_format_1.DEFAULT_PIXEL_FORMAT,
|
|
@@ -161,6 +159,8 @@ exports.RenderInternals = {
|
|
|
161
159
|
makeDownloadMap: download_map_1.makeDownloadMap,
|
|
162
160
|
cleanDownloadMap: download_map_1.cleanDownloadMap,
|
|
163
161
|
convertToPositiveFrameIndex: convert_to_positive_frame_index_1.convertToPositiveFrameIndex,
|
|
162
|
+
validateBitrate: validate_videobitrate_1.validateBitrate,
|
|
163
|
+
getFfmpegVersion: ffmpeg_flags_1.getFfmpegVersion,
|
|
164
164
|
};
|
|
165
165
|
// Warn of potential performance issues with Apple Silicon (M1 chip under Rosetta)
|
|
166
|
-
(0, check_apple_silicon_1.
|
|
166
|
+
(0, check_apple_silicon_1.checkNodeVersionAndWarnAboutRosetta)();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const makeAssetsDownloadTmpDir: () => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeAssetsDownloadTmpDir = void 0;
|
|
4
|
+
const tmp_dir_1 = require("./tmp-dir");
|
|
5
|
+
let dir = null;
|
|
6
|
+
const makeAssetsDownloadTmpDir = () => {
|
|
7
|
+
if (dir) {
|
|
8
|
+
return dir;
|
|
9
|
+
}
|
|
10
|
+
dir = (0, tmp_dir_1.tmpDir)('remotion-assets-dir');
|
|
11
|
+
return dir;
|
|
12
|
+
};
|
|
13
|
+
exports.makeAssetsDownloadTmpDir = makeAssetsDownloadTmpDir;
|
|
@@ -19,8 +19,9 @@ declare type PreSticherOptions = {
|
|
|
19
19
|
verbose: boolean;
|
|
20
20
|
ffmpegExecutable: FfmpegExecutable | undefined;
|
|
21
21
|
imageFormat: ImageFormat;
|
|
22
|
-
ffmpegOverride
|
|
22
|
+
ffmpegOverride: FfmpegOverrideFn;
|
|
23
23
|
signal: CancelSignal;
|
|
24
|
+
videoBitrate: string | null;
|
|
24
25
|
};
|
|
25
26
|
export declare const prespawnFfmpeg: (options: PreSticherOptions) => Promise<{
|
|
26
27
|
task: execa.ExecaChildProcess<string>;
|
package/dist/prespawn-ffmpeg.js
CHANGED
|
@@ -15,7 +15,7 @@ const pixel_format_1 = require("./pixel-format");
|
|
|
15
15
|
const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
|
|
16
16
|
const validate_ffmpeg_1 = require("./validate-ffmpeg");
|
|
17
17
|
const prespawnFfmpeg = async (options) => {
|
|
18
|
-
var _a, _b, _c, _d, _e, _f
|
|
18
|
+
var _a, _b, _c, _d, _e, _f;
|
|
19
19
|
remotion_1.Internals.validateDimension(options.height, 'height', 'passed to `stitchFramesToVideo()`');
|
|
20
20
|
remotion_1.Internals.validateDimension(options.width, 'width', 'passed to `stitchFramesToVideo()`');
|
|
21
21
|
const codec = (_a = options.codec) !== null && _a !== void 0 ? _a : codec_1.DEFAULT_CODEC;
|
|
@@ -26,9 +26,8 @@ const prespawnFfmpeg = async (options) => {
|
|
|
26
26
|
codec,
|
|
27
27
|
scale: 1,
|
|
28
28
|
});
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
await (0, validate_ffmpeg_1.validateFfmpeg)((_d = options.ffmpegExecutable) !== null && _d !== void 0 ? _d : null);
|
|
29
|
+
const pixelFormat = (_b = options.pixelFormat) !== null && _b !== void 0 ? _b : pixel_format_1.DEFAULT_PIXEL_FORMAT;
|
|
30
|
+
await (0, validate_ffmpeg_1.validateFfmpeg)((_c = options.ffmpegExecutable) !== null && _c !== void 0 ? _c : null);
|
|
32
31
|
const encoderName = (0, get_codec_name_1.getCodecName)(codec);
|
|
33
32
|
const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec, options.proResProfile);
|
|
34
33
|
if (encoderName === null) {
|
|
@@ -36,16 +35,15 @@ const prespawnFfmpeg = async (options) => {
|
|
|
36
35
|
}
|
|
37
36
|
const supportsCrf = codec !== 'prores';
|
|
38
37
|
if (options.verbose) {
|
|
39
|
-
console.log('[verbose] ffmpeg', (
|
|
38
|
+
console.log('[verbose] ffmpeg', (_d = options.ffmpegExecutable) !== null && _d !== void 0 ? _d : 'ffmpeg in PATH');
|
|
40
39
|
console.log('[verbose] encoder', encoderName);
|
|
41
40
|
console.log('[verbose] pixelFormat', pixelFormat);
|
|
42
41
|
if (supportsCrf) {
|
|
43
|
-
console.log('[verbose] crf', crf);
|
|
42
|
+
console.log('[verbose] crf', options.crf);
|
|
44
43
|
}
|
|
45
44
|
console.log('[verbose] codec', codec);
|
|
46
45
|
console.log('[verbose] proResProfileName', proResProfileName);
|
|
47
46
|
}
|
|
48
|
-
(0, crf_1.validateSelectedCrfAndCodecCombination)(crf, codec);
|
|
49
47
|
(0, pixel_format_1.validateSelectedPixelFormatAndCodecCombination)(pixelFormat, codec);
|
|
50
48
|
const ffmpegArgs = [
|
|
51
49
|
['-r', options.fps.toFixed(2)],
|
|
@@ -61,12 +59,15 @@ const prespawnFfmpeg = async (options) => {
|
|
|
61
59
|
// and specified the video codec.
|
|
62
60
|
['-c:v', encoderName],
|
|
63
61
|
proResProfileName ? ['-profile:v', proResProfileName] : null,
|
|
64
|
-
supportsCrf ? ['-crf', String(crf)] : null,
|
|
65
62
|
['-pix_fmt', pixelFormat],
|
|
66
63
|
// Without explicitly disabling auto-alt-ref,
|
|
67
64
|
// transparent WebM generation doesn't work
|
|
68
65
|
pixelFormat === 'yuva420p' ? ['-auto-alt-ref', '0'] : null,
|
|
69
|
-
|
|
66
|
+
...(0, crf_1.validateQualitySettings)({
|
|
67
|
+
crf: options.crf,
|
|
68
|
+
videoBitrate: options.videoBitrate,
|
|
69
|
+
codec,
|
|
70
|
+
}),
|
|
70
71
|
'-y',
|
|
71
72
|
options.outputLocation,
|
|
72
73
|
];
|
|
@@ -78,12 +79,12 @@ const prespawnFfmpeg = async (options) => {
|
|
|
78
79
|
const finalFfmpegString = options.ffmpegOverride
|
|
79
80
|
? options.ffmpegOverride({ type: 'pre-stitcher', args: ffmpegString })
|
|
80
81
|
: ffmpegString;
|
|
81
|
-
const task = (0, execa_1.default)((
|
|
82
|
+
const task = (0, execa_1.default)((_e = options.ffmpegExecutable) !== null && _e !== void 0 ? _e : 'ffmpeg', finalFfmpegString);
|
|
82
83
|
options.signal(() => {
|
|
83
84
|
task.kill();
|
|
84
85
|
});
|
|
85
86
|
let ffmpegOutput = '';
|
|
86
|
-
(
|
|
87
|
+
(_f = task.stderr) === null || _f === void 0 ? void 0 : _f.on('data', (data) => {
|
|
87
88
|
const str = data.toString();
|
|
88
89
|
ffmpegOutput += str;
|
|
89
90
|
if (options.onProgress) {
|
package/dist/render-frames.js
CHANGED
|
@@ -227,11 +227,12 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
|
|
|
227
227
|
return compressedAssets;
|
|
228
228
|
}));
|
|
229
229
|
const happyPath = progress.then(() => {
|
|
230
|
+
const firstFrameIndex = countType === 'from-zero' ? 0 : framesToRender[0];
|
|
230
231
|
const returnValue = {
|
|
231
232
|
assetsInfo: {
|
|
232
233
|
assets,
|
|
233
234
|
imageSequenceName: `element-%0${filePadLength}d.${imageFormat}`,
|
|
234
|
-
firstFrameIndex
|
|
235
|
+
firstFrameIndex,
|
|
235
236
|
downloadMap,
|
|
236
237
|
},
|
|
237
238
|
frameCount: framesToRender.length,
|
package/dist/render-media.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import type { SmallTCompMetadata } from 'remotion';
|
|
2
3
|
import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
3
4
|
import type { DownloadMap } from './assets/download-map';
|
|
@@ -65,6 +66,8 @@ export declare type RenderMediaOptions = {
|
|
|
65
66
|
muted?: boolean;
|
|
66
67
|
enforceAudioTrack?: boolean;
|
|
67
68
|
ffmpegOverride?: FfmpegOverrideFn;
|
|
69
|
+
audioBitrate?: string | null;
|
|
70
|
+
videoBitrate?: string | null;
|
|
68
71
|
onSlowestFrames?: OnSlowestFrames;
|
|
69
72
|
disallowParallelEncoding?: boolean;
|
|
70
73
|
} & ServeUrlOrWebpackBundle & ConcurrencyOrParallelism;
|
|
@@ -81,5 +84,5 @@ declare type ConcurrencyOrParallelism = {
|
|
|
81
84
|
* @description Render a video from a composition
|
|
82
85
|
* @link https://www.remotion.dev/docs/renderer/render-media
|
|
83
86
|
*/
|
|
84
|
-
export declare const renderMedia: ({ proResProfile, crf, composition, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, onSlowestFrames, ...options }: RenderMediaOptions) => Promise<Buffer | null>;
|
|
87
|
+
export declare const renderMedia: ({ proResProfile, crf, composition, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, onSlowestFrames, ...options }: RenderMediaOptions) => Promise<Buffer | null>;
|
|
85
88
|
export {};
|
package/dist/render-media.js
CHANGED
|
@@ -31,9 +31,11 @@ const quality_1 = require("./quality");
|
|
|
31
31
|
const render_frames_1 = require("./render-frames");
|
|
32
32
|
const stitch_frames_to_video_1 = require("./stitch-frames-to-video");
|
|
33
33
|
const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
|
|
34
|
+
const validate_ffmpeg_1 = require("./validate-ffmpeg");
|
|
34
35
|
const validate_ffmpeg_override_1 = require("./validate-ffmpeg-override");
|
|
35
36
|
const validate_output_filename_1 = require("./validate-output-filename");
|
|
36
37
|
const validate_scale_1 = require("./validate-scale");
|
|
38
|
+
const validate_videobitrate_1 = require("./validate-videobitrate");
|
|
37
39
|
const SLOWEST_FRAME_COUNT = 10;
|
|
38
40
|
const getConcurrency = (others) => {
|
|
39
41
|
if ('concurrency' in others) {
|
|
@@ -49,12 +51,13 @@ const getConcurrency = (others) => {
|
|
|
49
51
|
* @description Render a video from a composition
|
|
50
52
|
* @link https://www.remotion.dev/docs/renderer/render-media
|
|
51
53
|
*/
|
|
52
|
-
const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, onSlowestFrames, ...options }) => {
|
|
54
|
+
const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, onSlowestFrames, ...options }) => {
|
|
53
55
|
var _a, _b, _c, _d;
|
|
56
|
+
(0, validate_ffmpeg_1.validateFfmpeg)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null);
|
|
54
57
|
(0, quality_1.validateQuality)(options.quality);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
(0, crf_1.validateQualitySettings)({ crf, codec, videoBitrate });
|
|
59
|
+
(0, validate_videobitrate_1.validateBitrate)(audioBitrate, 'audioBitrate');
|
|
60
|
+
(0, validate_videobitrate_1.validateBitrate)(videoBitrate, 'videoBitrate');
|
|
58
61
|
(0, prores_profile_1.validateSelectedCodecAndProResCombination)({
|
|
59
62
|
codec,
|
|
60
63
|
proResProfile,
|
|
@@ -157,7 +160,8 @@ const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprob
|
|
|
157
160
|
ffmpegExecutable,
|
|
158
161
|
imageFormat,
|
|
159
162
|
signal: cancelPrestitcher.cancelSignal,
|
|
160
|
-
ffmpegOverride,
|
|
163
|
+
ffmpegOverride: ffmpegOverride !== null && ffmpegOverride !== void 0 ? ffmpegOverride : (({ args }) => args),
|
|
164
|
+
videoBitrate: videoBitrate !== null && videoBitrate !== void 0 ? videoBitrate : null,
|
|
161
165
|
});
|
|
162
166
|
stitcherFfmpeg = preStitcher.task;
|
|
163
167
|
}
|
|
@@ -295,6 +299,8 @@ const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprob
|
|
|
295
299
|
muted: disableAudio,
|
|
296
300
|
enforceAudioTrack,
|
|
297
301
|
ffmpegOverride,
|
|
302
|
+
audioBitrate,
|
|
303
|
+
videoBitrate,
|
|
298
304
|
}),
|
|
299
305
|
stitchStart,
|
|
300
306
|
]);
|
|
@@ -9,6 +9,8 @@ import type { CancelSignal } from './make-cancel-signal';
|
|
|
9
9
|
import type { PixelFormat } from './pixel-format';
|
|
10
10
|
import type { ProResProfile } from './prores-profile';
|
|
11
11
|
export declare type StitcherOptions = {
|
|
12
|
+
audioBitrate?: string | null;
|
|
13
|
+
videoBitrate?: string | null;
|
|
12
14
|
fps: number;
|
|
13
15
|
width: number;
|
|
14
16
|
height: number;
|
|
@@ -29,6 +29,7 @@ const prores_profile_1 = require("./prores-profile");
|
|
|
29
29
|
const truthy_1 = require("./truthy");
|
|
30
30
|
const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
|
|
31
31
|
const validate_ffmpeg_1 = require("./validate-ffmpeg");
|
|
32
|
+
const validate_videobitrate_1 = require("./validate-videobitrate");
|
|
32
33
|
const packageJsonPath = path_1.default.join(__dirname, '..', 'package.json');
|
|
33
34
|
const packageJson = fs_1.default.existsSync(packageJsonPath)
|
|
34
35
|
? JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'))
|
|
@@ -93,15 +94,15 @@ const spawnFfmpeg = async (options) => {
|
|
|
93
94
|
codec,
|
|
94
95
|
proResProfile: options.proResProfile,
|
|
95
96
|
});
|
|
97
|
+
(0, validate_videobitrate_1.validateBitrate)(options.audioBitrate, 'audioBitrate');
|
|
98
|
+
(0, validate_videobitrate_1.validateBitrate)(options.videoBitrate, 'videoBitrate');
|
|
96
99
|
remotion_1.Internals.validateFps(options.fps, 'in `stitchFramesToVideo()`', false);
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
await (0, validate_ffmpeg_1.validateFfmpeg)((_d = options.ffmpegExecutable) !== null && _d !== void 0 ? _d : null);
|
|
100
|
+
const pixelFormat = (_b = options.pixelFormat) !== null && _b !== void 0 ? _b : pixel_format_1.DEFAULT_PIXEL_FORMAT;
|
|
101
|
+
await (0, validate_ffmpeg_1.validateFfmpeg)((_c = options.ffmpegExecutable) !== null && _c !== void 0 ? _c : null);
|
|
100
102
|
const encoderName = (0, get_codec_name_1.getCodecName)(codec);
|
|
101
103
|
const audioCodecName = (0, get_audio_codec_name_1.getAudioCodecName)(codec);
|
|
102
104
|
const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec, options.proResProfile);
|
|
103
105
|
const mediaSupport = (0, codec_supports_media_1.codecSupportsMedia)(codec);
|
|
104
|
-
const supportsCrf = (0, codec_supports_media_1.codecSupportsCrf)(codec);
|
|
105
106
|
const tempFile = options.outputLocation
|
|
106
107
|
? null
|
|
107
108
|
: path_1.default.join(options.assetsInfo.downloadMap.stitchFrames, `out.${(0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, 'final')}`);
|
|
@@ -114,13 +115,10 @@ const spawnFfmpeg = async (options) => {
|
|
|
114
115
|
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.');
|
|
115
116
|
}
|
|
116
117
|
if (options.verbose) {
|
|
117
|
-
console.log('[verbose] ffmpeg', (
|
|
118
|
+
console.log('[verbose] ffmpeg', (_d = options.ffmpegExecutable) !== null && _d !== void 0 ? _d : 'ffmpeg in PATH');
|
|
118
119
|
console.log('[verbose] encoder', encoderName);
|
|
119
120
|
console.log('[verbose] audioCodec', audioCodecName);
|
|
120
121
|
console.log('[verbose] pixelFormat', pixelFormat);
|
|
121
|
-
if (supportsCrf) {
|
|
122
|
-
console.log('[verbose] crf', crf);
|
|
123
|
-
}
|
|
124
122
|
if (options.ffmpegOverride) {
|
|
125
123
|
console.log('[verbose] ffmpegOverride', options.ffmpegOverride);
|
|
126
124
|
}
|
|
@@ -129,7 +127,11 @@ const spawnFfmpeg = async (options) => {
|
|
|
129
127
|
console.log('[verbose] shouldRenderVideo', shouldRenderVideo);
|
|
130
128
|
console.log('[verbose] proResProfileName', proResProfileName);
|
|
131
129
|
}
|
|
132
|
-
(0, crf_1.
|
|
130
|
+
(0, crf_1.validateQualitySettings)({
|
|
131
|
+
crf: options.crf,
|
|
132
|
+
codec,
|
|
133
|
+
videoBitrate: options.videoBitrate,
|
|
134
|
+
});
|
|
133
135
|
(0, pixel_format_1.validateSelectedPixelFormatAndCodecCombination)(pixelFormat, codec);
|
|
134
136
|
const expectedFrames = options.assetsInfo.assets.length;
|
|
135
137
|
const updateProgress = (preStitchProgress, muxProgress) => {
|
|
@@ -143,9 +145,9 @@ const spawnFfmpeg = async (options) => {
|
|
|
143
145
|
onDownload: options.onDownload,
|
|
144
146
|
fps: options.fps,
|
|
145
147
|
expectedFrames,
|
|
146
|
-
verbose: (
|
|
147
|
-
ffmpegExecutable: (
|
|
148
|
-
ffprobeExecutable: (
|
|
148
|
+
verbose: (_e = options.verbose) !== null && _e !== void 0 ? _e : false,
|
|
149
|
+
ffmpegExecutable: (_f = options.ffmpegExecutable) !== null && _f !== void 0 ? _f : null,
|
|
150
|
+
ffprobeExecutable: (_g = options.ffprobeExecutable) !== null && _g !== void 0 ? _g : null,
|
|
149
151
|
onProgress: (prog) => updateProgress(prog, 0),
|
|
150
152
|
downloadMap: options.assetsInfo.downloadMap,
|
|
151
153
|
})
|
|
@@ -161,7 +163,7 @@ const spawnFfmpeg = async (options) => {
|
|
|
161
163
|
audioCodecName,
|
|
162
164
|
// Set bitrate up to 320k, for aac it might effectively be lower
|
|
163
165
|
'-b:a',
|
|
164
|
-
'320k',
|
|
166
|
+
(_h = options.audioBitrate) !== null && _h !== void 0 ? _h : '320k',
|
|
165
167
|
options.force ? '-y' : null,
|
|
166
168
|
(_j = options.outputLocation) !== null && _j !== void 0 ? _j : tempFile,
|
|
167
169
|
].filter(remotion_1.Internals.truthy));
|
|
@@ -215,17 +217,20 @@ const spawnFfmpeg = async (options) => {
|
|
|
215
217
|
? []
|
|
216
218
|
: [
|
|
217
219
|
proResProfileName ? ['-profile:v', proResProfileName] : null,
|
|
218
|
-
supportsCrf ? ['-crf', String(crf)] : null,
|
|
219
220
|
['-pix_fmt', pixelFormat],
|
|
220
221
|
// Without explicitly disabling auto-alt-ref,
|
|
221
222
|
// transparent WebM generation doesn't work
|
|
222
223
|
pixelFormat === 'yuva420p' ? ['-auto-alt-ref', '0'] : null,
|
|
223
|
-
|
|
224
|
+
...(0, crf_1.validateQualitySettings)({
|
|
225
|
+
crf: options.crf,
|
|
226
|
+
videoBitrate: options.videoBitrate,
|
|
227
|
+
codec,
|
|
228
|
+
}),
|
|
224
229
|
]),
|
|
225
230
|
codec === 'h264' ? ['-movflags', 'faststart'] : null,
|
|
226
231
|
audioCodecName ? ['-c:a', audioCodecName] : null,
|
|
227
232
|
// Set max bitrate up to 1024kbps, will choose lower if that's too much
|
|
228
|
-
audioCodecName ? ['-b:a', '512K'] : null,
|
|
233
|
+
audioCodecName ? ['-b:a', options.audioBitrate || '512K'] : null,
|
|
229
234
|
// Ignore metadata that may come from remote media
|
|
230
235
|
['-map_metadata', '-1'],
|
|
231
236
|
[
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateFfmpegArgsHook = void 0;
|
|
4
|
+
const validateFfmpegArgsHook = (ffmpegArgsHook) => {
|
|
5
|
+
if (typeof ffmpegArgsHook === 'undefined') {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (ffmpegArgsHook && typeof ffmpegArgsHook !== 'function') {
|
|
9
|
+
throw new TypeError(`Argument passed for "ffmpegArgsHook" is not a function: ${ffmpegArgsHook}`);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
exports.validateFfmpegArgsHook = validateFfmpegArgsHook;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateFfmpegOverride = void 0;
|
|
4
|
+
const validateFfmpegOverride = (ffmpegArgsHook) => {
|
|
5
|
+
if (typeof ffmpegArgsHook === 'undefined') {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (ffmpegArgsHook && typeof ffmpegArgsHook !== 'function') {
|
|
9
|
+
throw new TypeError(`Argument passed for "ffmpegArgsHook" is not a function: ${ffmpegArgsHook}`);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
exports.validateFfmpegOverride = validateFfmpegOverride;
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
export declare const binaryExists: (name: 'ffmpeg' | 'brew', localFFmpeg: string | null) =>
|
|
1
|
+
export declare const binaryExists: (name: 'ffmpeg' | 'brew', localFFmpeg: string | null) => boolean;
|
|
2
|
+
export declare const checkAndValidateFfmpegVersion: (options: {
|
|
3
|
+
ffmpegExecutable: string | null;
|
|
4
|
+
}) => Promise<void>;
|
|
2
5
|
export declare const validateFfmpeg: (customFfmpegBinary: string | null) => Promise<void>;
|
package/dist/validate-ffmpeg.js
CHANGED
|
@@ -3,12 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.validateFfmpeg = exports.binaryExists = void 0;
|
|
6
|
+
exports.validateFfmpeg = exports.checkAndValidateFfmpegVersion = exports.binaryExists = void 0;
|
|
7
7
|
const execa_1 = __importDefault(require("execa"));
|
|
8
8
|
const fs_1 = require("fs");
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const ffmpeg_flags_1 = require("./ffmpeg-flags");
|
|
11
|
+
const warn_about_ffmpeg_version_1 = require("./warn-about-ffmpeg-version");
|
|
10
12
|
const existsMap = {};
|
|
11
|
-
const binaryExists =
|
|
13
|
+
const binaryExists = (name, localFFmpeg) => {
|
|
12
14
|
if (typeof existsMap[name] !== 'undefined') {
|
|
13
15
|
return existsMap[name];
|
|
14
16
|
}
|
|
@@ -25,7 +27,7 @@ const binaryExists = async (name, localFFmpeg) => {
|
|
|
25
27
|
const isWin = os_1.default.platform() === 'win32';
|
|
26
28
|
const where = isWin ? 'where' : 'which';
|
|
27
29
|
try {
|
|
28
|
-
|
|
30
|
+
execa_1.default.sync(where, [name]);
|
|
29
31
|
existsMap[name] = true;
|
|
30
32
|
return true;
|
|
31
33
|
}
|
|
@@ -38,16 +40,26 @@ exports.binaryExists = binaryExists;
|
|
|
38
40
|
const isHomebrewInstalled = () => {
|
|
39
41
|
return (0, exports.binaryExists)('brew', null);
|
|
40
42
|
};
|
|
43
|
+
const checkAndValidateFfmpegVersion = async (options) => {
|
|
44
|
+
const ffmpegVersion = await (0, ffmpeg_flags_1.getFfmpegVersion)({
|
|
45
|
+
ffmpegExecutable: options.ffmpegExecutable,
|
|
46
|
+
});
|
|
47
|
+
const buildConf = await (0, ffmpeg_flags_1.getFfmpegBuildInfo)({
|
|
48
|
+
ffmpegExecutable: options.ffmpegExecutable,
|
|
49
|
+
});
|
|
50
|
+
(0, warn_about_ffmpeg_version_1.warnAboutFfmpegVersion)({ ffmpegVersion, buildConf });
|
|
51
|
+
};
|
|
52
|
+
exports.checkAndValidateFfmpegVersion = checkAndValidateFfmpegVersion;
|
|
41
53
|
const validateFfmpeg = async (customFfmpegBinary) => {
|
|
42
|
-
const ffmpegExists =
|
|
54
|
+
const ffmpegExists = (0, exports.binaryExists)('ffmpeg', customFfmpegBinary);
|
|
43
55
|
if (!ffmpegExists) {
|
|
44
56
|
if (customFfmpegBinary) {
|
|
45
57
|
console.error('FFmpeg executable not found:');
|
|
46
58
|
console.error(customFfmpegBinary);
|
|
47
|
-
|
|
59
|
+
throw new Error('FFmpeg not found');
|
|
48
60
|
}
|
|
49
61
|
console.error('It looks like FFMPEG is not installed');
|
|
50
|
-
if (os_1.default.platform() === 'darwin' &&
|
|
62
|
+
if (os_1.default.platform() === 'darwin' && isHomebrewInstalled()) {
|
|
51
63
|
console.error('Run `brew install ffmpeg` to install ffmpeg');
|
|
52
64
|
}
|
|
53
65
|
else if (os_1.default.platform() === 'win32') {
|
|
@@ -66,7 +78,8 @@ const validateFfmpeg = async (customFfmpegBinary) => {
|
|
|
66
78
|
else {
|
|
67
79
|
console.error('See https://github.com/adaptlearning/adapt_authoring/wiki/Installing-FFmpeg on how to install FFMPEG.');
|
|
68
80
|
}
|
|
69
|
-
|
|
81
|
+
throw new Error('FFmpeg not found');
|
|
70
82
|
}
|
|
83
|
+
await (0, exports.checkAndValidateFfmpegVersion)({ ffmpegExecutable: customFfmpegBinary });
|
|
71
84
|
};
|
|
72
85
|
exports.validateFfmpeg = validateFfmpeg;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const validateBitrate: (bitrate: unknown, name: string) => void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateBitrate = void 0;
|
|
4
|
+
const validateBitrate = (bitrate, name) => {
|
|
5
|
+
if (bitrate === null || typeof bitrate === 'undefined') {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (typeof bitrate === 'number') {
|
|
9
|
+
throw new TypeError(`"${name}" must be a string ending in "K" or "M". Got a number: ${bitrate}`);
|
|
10
|
+
}
|
|
11
|
+
if (typeof bitrate !== 'string') {
|
|
12
|
+
throw new TypeError(`"${name}" must be a string or null, but got ${JSON.stringify(bitrate)}`);
|
|
13
|
+
}
|
|
14
|
+
if (!bitrate.endsWith('K') &&
|
|
15
|
+
!bitrate.endsWith('k') &&
|
|
16
|
+
!bitrate.endsWith('M')) {
|
|
17
|
+
throw new TypeError(`"${name}" must end in "K", "k" or "M", but got ${JSON.stringify(bitrate)}`);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
exports.validateBitrate = validateBitrate;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.warnAboutFfmpegVersion = void 0;
|
|
4
|
+
const printMessage = (ffmpegVersion) => {
|
|
5
|
+
console.warn('⚠️Old FFMPEG version detected: ' + ffmpegVersion.join('.'));
|
|
6
|
+
console.warn(' For audio support, you need at least version 4.1.0.');
|
|
7
|
+
console.warn(' Upgrade FFMPEG to get rid of this warning.');
|
|
8
|
+
};
|
|
9
|
+
const printBuildConfMessage = () => {
|
|
10
|
+
console.error('⚠️ Unsupported FFMPEG version detected.');
|
|
11
|
+
console.error(" Your version doesn't support the -buildconf flag");
|
|
12
|
+
console.error(' Audio will not be supported and you may experience other issues.');
|
|
13
|
+
console.error(' Upgrade FFMPEG to at least v4.1.0 to get rid of this warning.');
|
|
14
|
+
};
|
|
15
|
+
const warnAboutFfmpegVersion = ({ ffmpegVersion, buildConf, }) => {
|
|
16
|
+
if (buildConf === null) {
|
|
17
|
+
printBuildConfMessage();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (ffmpegVersion === null) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const [major, minor] = ffmpegVersion;
|
|
24
|
+
// 3.x and below definitely is too old
|
|
25
|
+
if (major < 4) {
|
|
26
|
+
printMessage(ffmpegVersion);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// 5.x will be all good
|
|
30
|
+
if (major > 4) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (minor < 1) {
|
|
34
|
+
printMessage(ffmpegVersion);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
exports.warnAboutFfmpegVersion = warnAboutFfmpegVersion;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/renderer",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.33",
|
|
4
4
|
"description": "Renderer for Remotion",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"execa": "5.1.1",
|
|
24
24
|
"extract-zip": "2.0.1",
|
|
25
|
-
"remotion": "3.2.
|
|
25
|
+
"remotion": "3.2.33",
|
|
26
26
|
"source-map": "^0.8.0-beta.0",
|
|
27
27
|
"ws": "8.7.0"
|
|
28
28
|
},
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"react": "18.0.0",
|
|
45
45
|
"react-dom": "18.0.0",
|
|
46
46
|
"typescript": "^4.7.0",
|
|
47
|
-
"vitest": "
|
|
47
|
+
"vitest": "0.24.3"
|
|
48
48
|
},
|
|
49
49
|
"keywords": [
|
|
50
50
|
"remotion",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "3c864e5ab73870674d028a1199005ddbabaede12"
|
|
61
61
|
}
|
|
@@ -1,34 +0,0 @@
|
|
|
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.findRemotionRoot = exports.findClosestPackageJson = void 0;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const recursionLimit = 5;
|
|
10
|
-
const findClosestPackageJson = () => {
|
|
11
|
-
let currentDir = process.cwd();
|
|
12
|
-
let possiblePackageJson = '';
|
|
13
|
-
for (let i = 0; i < recursionLimit; i++) {
|
|
14
|
-
possiblePackageJson = path_1.default.join(currentDir, 'package.json');
|
|
15
|
-
const exists = fs_1.default.existsSync(possiblePackageJson);
|
|
16
|
-
if (exists) {
|
|
17
|
-
return possiblePackageJson;
|
|
18
|
-
}
|
|
19
|
-
currentDir = path_1.default.dirname(currentDir);
|
|
20
|
-
}
|
|
21
|
-
return null;
|
|
22
|
-
};
|
|
23
|
-
exports.findClosestPackageJson = findClosestPackageJson;
|
|
24
|
-
const findRemotionRoot = () => {
|
|
25
|
-
const closestPackageJson = (0, exports.findClosestPackageJson)();
|
|
26
|
-
if (closestPackageJson === null) {
|
|
27
|
-
console.error('Could not find a package.json in the current directory or any of the ' +
|
|
28
|
-
recursionLimit +
|
|
29
|
-
' parent directories. Is this a Remotion project?');
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
return path_1.default.dirname(closestPackageJson);
|
|
33
|
-
};
|
|
34
|
-
exports.findRemotionRoot = findRemotionRoot;
|