@remotion/renderer 4.0.0-alpha4 → 4.0.0-alpha6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -43
- package/dist/assets/download-and-map-assets-to-file.js +6 -6
- package/dist/assets/download-file.d.ts +3 -2
- package/dist/assets/download-file.js +18 -3
- package/dist/assets/download-map.d.ts +0 -26
- package/dist/assets/download-map.js +7 -12
- package/dist/assets/get-audio-channels.d.ts +1 -2
- package/dist/assets/get-audio-channels.js +5 -9
- package/dist/assets/read-file.d.ts +1 -1
- package/dist/assets/read-file.js +2 -2
- package/dist/assets/sanitize-filepath.js +2 -2
- package/dist/audio-codec.d.ts +4 -3
- package/dist/audio-codec.js +3 -9
- package/dist/browser/BrowserFetcher.d.ts +0 -1
- package/dist/browser/BrowserFetcher.js +14 -15
- package/dist/browser/BrowserRunner.d.ts +1 -1
- package/dist/browser/BrowserRunner.js +10 -4
- package/dist/browser/FrameManager.js +2 -3
- package/dist/browser/LaunchOptions.d.ts +1 -0
- package/dist/browser/Launcher.js +6 -5
- package/dist/browser/NodeWebSocketTransport.js +4 -4
- package/dist/browser/devtools-commands.d.ts +5 -1
- package/dist/browser/devtools-types.d.ts +78 -0
- package/dist/browser/get-download-destination.js +8 -8
- package/dist/browser/is-target-closed-err.d.ts +1 -0
- package/dist/browser/is-target-closed-err.js +9 -0
- package/dist/call-ffmpeg.d.ts +14 -0
- package/dist/call-ffmpeg.js +40 -0
- package/dist/check-apple-silicon.js +2 -45
- package/dist/client.d.ts +79 -42
- package/dist/client.js +27 -1
- package/dist/codec-supports-media.d.ts +2 -1
- package/dist/codec-supports-media.js +20 -5
- package/dist/combine-videos.d.ts +0 -3
- package/dist/combine-videos.js +9 -13
- package/dist/compositor/compose.d.ts +3 -1
- package/dist/compositor/compose.js +41 -18
- package/dist/compositor/compositor.d.ts +12 -0
- package/dist/compositor/compositor.js +204 -0
- package/dist/compositor/get-executable-path.d.ts +1 -1
- package/dist/compositor/get-executable-path.js +27 -8
- package/dist/compositor/make-nonce.d.ts +1 -0
- package/dist/compositor/make-nonce.js +8 -0
- package/dist/compositor/payloads.d.ts +34 -7
- package/dist/create-ffmpeg-complex-filter.d.ts +5 -5
- package/dist/create-ffmpeg-complex-filter.js +2 -4
- package/dist/create-ffmpeg-merge-filter.d.ts +2 -5
- package/dist/create-ffmpeg-merge-filter.js +2 -10
- package/dist/create-silent-audio.d.ts +1 -4
- package/dist/create-silent-audio.js +3 -7
- package/dist/crf.js +8 -2
- package/dist/delete-directory.js +18 -18
- package/dist/does-have-m2-bug.js +2 -2
- package/dist/ensure-output-directory.js +5 -5
- package/dist/ffmpeg-filter-file.js +7 -7
- package/dist/file-extensions.d.ts +1 -12
- package/dist/file-extensions.js +8 -14
- package/dist/find-closest-package-json.js +6 -6
- package/dist/get-compositions.d.ts +3 -5
- package/dist/get-compositions.js +8 -11
- package/dist/get-concurrency.js +3 -3
- package/dist/get-extension-from-codec.d.ts +2 -2
- package/dist/get-extension-of-filename.js +2 -2
- package/dist/get-frame-padded-index.d.ts +2 -1
- package/dist/get-local-browser-executable.js +4 -4
- package/dist/get-video-threads-flag.js +3 -3
- package/dist/guess-extension-for-media.d.ts +1 -3
- package/dist/guess-extension-for-media.js +4 -8
- package/dist/image-format.d.ts +12 -6
- package/dist/image-format.js +16 -13
- package/dist/index.d.ts +80 -61
- package/dist/index.js +15 -17
- package/dist/jpeg-quality.d.ts +1 -0
- package/dist/jpeg-quality.js +21 -0
- package/dist/merge-audio-track.d.ts +0 -2
- package/dist/merge-audio-track.js +5 -12
- package/dist/mime-types.js +2 -2
- package/dist/offthread-video-server.d.ts +9 -9
- package/dist/offthread-video-server.js +65 -58
- package/dist/open-browser.d.ts +1 -0
- package/dist/open-browser.js +7 -6
- package/dist/options/audio-bitrate.d.ts +2 -0
- package/dist/options/audio-bitrate.js +11 -0
- package/dist/options/crf.d.ts +2 -0
- package/dist/options/crf.js +11 -0
- package/dist/options/enforce-audio.d.ts +2 -0
- package/dist/options/enforce-audio.js +11 -0
- package/dist/options/jpeg-quality.d.ts +2 -0
- package/dist/options/jpeg-quality.js +11 -0
- package/dist/options/mute.d.ts +2 -0
- package/dist/options/mute.js +11 -0
- package/dist/options/option.d.ts +8 -0
- package/dist/options/option.js +2 -0
- package/dist/options/scale.d.ts +2 -0
- package/dist/options/scale.js +11 -0
- package/dist/options/video-bitrate.d.ts +2 -0
- package/dist/options/video-bitrate.js +11 -0
- package/dist/options/video-codec.d.ts +2 -0
- package/dist/options/video-codec.js +11 -0
- package/dist/perf.d.ts +1 -1
- package/dist/perf.js +9 -7
- package/dist/prepare-server.d.ts +3 -4
- package/dist/prepare-server.js +9 -9
- package/dist/preprocess-audio-track.d.ts +0 -4
- package/dist/preprocess-audio-track.js +4 -8
- package/dist/prespawn-ffmpeg.d.ts +6 -9
- package/dist/prespawn-ffmpeg.js +7 -12
- package/dist/prestitcher-memory-usage.d.ts +0 -4
- package/dist/prestitcher-memory-usage.js +4 -5
- package/dist/prores-profile.d.ts +1 -2
- package/dist/prores-profile.js +4 -4
- package/dist/provide-screenshot.d.ts +4 -5
- package/dist/provide-screenshot.js +2 -2
- package/dist/puppeteer-screenshot.d.ts +3 -3
- package/dist/puppeteer-screenshot.js +10 -33
- package/dist/render-frames.d.ts +13 -25
- package/dist/render-frames.js +34 -45
- package/dist/render-media.d.ts +16 -18
- package/dist/render-media.js +42 -52
- package/dist/render-still.d.ts +12 -8
- package/dist/render-still.js +30 -18
- package/dist/resolve-asset-src.js +2 -2
- package/dist/screenshot-dom-element.d.ts +4 -5
- package/dist/screenshot-dom-element.js +6 -3
- package/dist/screenshot-task.d.ts +2 -3
- package/dist/screenshot-task.js +40 -25
- package/dist/serve-handler/index.d.ts +1 -1
- package/dist/serve-handler/index.js +21 -19
- package/dist/serve-handler/is-path-inside.js +3 -3
- package/dist/serve-static.d.ts +2 -3
- package/dist/serve-static.js +26 -22
- package/dist/stitch-frames-to-video.d.ts +2 -12
- package/dist/stitch-frames-to-video.js +37 -46
- package/dist/take-frame-and-compose.d.ts +4 -5
- package/dist/take-frame-and-compose.js +15 -9
- package/dist/tmp-dir.js +7 -8
- package/dist/validate-concurrency.d.ts +2 -0
- package/dist/validate-concurrency.js +11 -5
- package/dist/validate-output-filename.d.ts +1 -1
- package/dist/validate-puppeteer-timeout.js +1 -0
- package/install-toolchain.mjs +36 -0
- package/package.json +11 -10
- package/types/ws/index.d.ts +5 -5
package/dist/combine-videos.js
CHANGED
|
@@ -1,27 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Combine multiple video chunks, useful for decentralized rendering
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
-
};
|
|
6
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
4
|
exports.combineVideos = void 0;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const path_1 = require("path");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
11
7
|
const audio_codec_1 = require("./audio-codec");
|
|
12
|
-
const
|
|
8
|
+
const call_ffmpeg_1 = require("./call-ffmpeg");
|
|
13
9
|
const is_audio_codec_1 = require("./is-audio-codec");
|
|
14
10
|
const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
|
|
15
11
|
const truthy_1 = require("./truthy");
|
|
16
12
|
const combineVideos = async (options) => {
|
|
17
13
|
var _a;
|
|
18
|
-
const { files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops,
|
|
14
|
+
const { files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, audioCodec, } = options;
|
|
19
15
|
const fileList = files.map((p) => `file '${p}'`).join('\n');
|
|
20
|
-
const fileListTxt = (0,
|
|
21
|
-
(0,
|
|
16
|
+
const fileListTxt = (0, node_path_1.join)(filelistDir, 'files.txt');
|
|
17
|
+
(0, node_fs_1.writeFileSync)(fileListTxt, fileList);
|
|
22
18
|
const resolvedAudioCodec = audioCodec !== null && audioCodec !== void 0 ? audioCodec : (0, audio_codec_1.getDefaultAudioCodec)({ codec, preferLossless: false });
|
|
23
19
|
try {
|
|
24
|
-
const task = (0,
|
|
20
|
+
const task = (0, call_ffmpeg_1.callFf)('ffmpeg', [
|
|
25
21
|
(0, is_audio_codec_1.isAudioCodec)(codec) ? null : '-r',
|
|
26
22
|
(0, is_audio_codec_1.isAudioCodec)(codec) ? null : String(fps),
|
|
27
23
|
'-f',
|
|
@@ -60,10 +56,10 @@ const combineVideos = async (options) => {
|
|
|
60
56
|
});
|
|
61
57
|
await task;
|
|
62
58
|
onProgress(numberOfFrames);
|
|
63
|
-
(
|
|
59
|
+
(0, node_fs_1.rmSync)(filelistDir, { recursive: true });
|
|
64
60
|
}
|
|
65
61
|
catch (err) {
|
|
66
|
-
(
|
|
62
|
+
(0, node_fs_1.rmSync)(filelistDir, { recursive: true });
|
|
67
63
|
throw err;
|
|
68
64
|
}
|
|
69
65
|
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { DownloadMap } from '../assets/download-map';
|
|
2
|
-
import type { CompositorImageFormat, Layer } from './payloads';
|
|
2
|
+
import type { CompositorCommand, CompositorCommandSerialized, CompositorImageFormat, Layer } from './payloads';
|
|
3
3
|
declare type CompositorInput = {
|
|
4
4
|
height: number;
|
|
5
5
|
width: number;
|
|
6
6
|
layers: Layer[];
|
|
7
7
|
imageFormat: CompositorImageFormat;
|
|
8
8
|
};
|
|
9
|
+
export declare const serializeCommand: <Type extends keyof CompositorCommand>(command: Type, params: CompositorCommand[Type]) => CompositorCommandSerialized<Type>;
|
|
9
10
|
export declare const compose: ({ height, width, layers, output, downloadMap, imageFormat, }: CompositorInput & {
|
|
10
11
|
downloadMap: DownloadMap;
|
|
11
12
|
output: string;
|
|
12
13
|
}) => Promise<void>;
|
|
14
|
+
export declare const callCompositor: (payload: string) => Promise<void>;
|
|
13
15
|
export {};
|
|
@@ -1,31 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.compose = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
3
|
+
exports.callCompositor = exports.compose = exports.serializeCommand = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const call_ffmpeg_1 = require("../call-ffmpeg");
|
|
7
9
|
const get_executable_path_1 = require("./get-executable-path");
|
|
10
|
+
const make_nonce_1 = require("./make-nonce");
|
|
8
11
|
const getCompositorHash = ({ ...input }) => {
|
|
9
|
-
return (0,
|
|
12
|
+
return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(input)).digest('base64');
|
|
10
13
|
};
|
|
14
|
+
const serializeCommand = (command, params) => {
|
|
15
|
+
return {
|
|
16
|
+
nonce: (0, make_nonce_1.makeNonce)(),
|
|
17
|
+
payload: {
|
|
18
|
+
type: command,
|
|
19
|
+
params,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
exports.serializeCommand = serializeCommand;
|
|
11
24
|
const compose = async ({ height, width, layers, output, downloadMap, imageFormat, }) => {
|
|
12
|
-
const bin = (0, get_executable_path_1.getExecutablePath)();
|
|
13
25
|
const hash = getCompositorHash({ height, width, layers, imageFormat });
|
|
14
26
|
if (downloadMap.compositorCache[hash]) {
|
|
15
27
|
await (0, promises_1.copyFile)(downloadMap.compositorCache[hash], output);
|
|
16
28
|
return;
|
|
17
29
|
}
|
|
18
|
-
const payload = {
|
|
19
|
-
v: 1,
|
|
30
|
+
const payload = (0, exports.serializeCommand)('Compose', {
|
|
20
31
|
height,
|
|
21
32
|
width,
|
|
22
33
|
layers,
|
|
23
34
|
output,
|
|
24
35
|
output_format: imageFormat,
|
|
25
|
-
};
|
|
26
|
-
await
|
|
27
|
-
|
|
28
|
-
|
|
36
|
+
});
|
|
37
|
+
await (0, exports.callCompositor)(JSON.stringify(payload));
|
|
38
|
+
downloadMap.compositorCache[hash] = output;
|
|
39
|
+
};
|
|
40
|
+
exports.compose = compose;
|
|
41
|
+
const callCompositor = (payload) => {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const execPath = (0, get_executable_path_1.getExecutablePath)('compositor');
|
|
44
|
+
(0, node_fs_1.chmodSync)(execPath, 0o755);
|
|
45
|
+
const child = (0, node_child_process_1.spawn)(execPath, [payload], (0, call_ffmpeg_1.dynamicLibraryPathOptions)());
|
|
46
|
+
child.stdin.write(payload);
|
|
29
47
|
child.stdin.end();
|
|
30
48
|
const stderrChunks = [];
|
|
31
49
|
child.stderr.on('data', (d) => stderrChunks.push(d));
|
|
@@ -35,13 +53,18 @@ const compose = async ({ height, width, layers, output, downloadMap, imageFormat
|
|
|
35
53
|
}
|
|
36
54
|
else {
|
|
37
55
|
const message = Buffer.concat(stderrChunks).toString('utf-8');
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
56
|
+
try {
|
|
57
|
+
// Try to see if the error is a JSON
|
|
58
|
+
const parsed = JSON.parse(message);
|
|
59
|
+
const msg = `Compositor error: ${parsed.error}`;
|
|
60
|
+
const err = new Error(`${msg}\n${parsed.backtrace}`);
|
|
61
|
+
reject(err);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
reject(new Error(`Compositor panicked: ${message}`));
|
|
65
|
+
}
|
|
42
66
|
}
|
|
43
67
|
});
|
|
44
68
|
});
|
|
45
|
-
downloadMap.compositorCache[hash] = output;
|
|
46
69
|
};
|
|
47
|
-
exports.
|
|
70
|
+
exports.callCompositor = callCompositor;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { CompositorCommand } from './payloads';
|
|
3
|
+
declare type Compositor = {
|
|
4
|
+
finishCommands: () => void;
|
|
5
|
+
executeCommand: <T extends keyof CompositorCommand>(type: T, payload: CompositorCommand[T]) => Promise<Buffer>;
|
|
6
|
+
waitForDone: () => Promise<void>;
|
|
7
|
+
pid: number | null;
|
|
8
|
+
};
|
|
9
|
+
export declare const getIdealMaximumFrameCacheItems: () => number;
|
|
10
|
+
export declare const startLongRunningCompositor: (maximumFrameCacheItems: number, verbose: boolean) => Compositor;
|
|
11
|
+
export declare const startCompositor: <T extends keyof CompositorCommand>(type: T, payload: CompositorCommand[T]) => Compositor;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
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.startCompositor = exports.startLongRunningCompositor = exports.getIdealMaximumFrameCacheItems = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
const call_ffmpeg_1 = require("../call-ffmpeg");
|
|
11
|
+
const get_concurrency_1 = require("../get-concurrency");
|
|
12
|
+
const compose_1 = require("./compose");
|
|
13
|
+
const get_executable_path_1 = require("./get-executable-path");
|
|
14
|
+
const make_nonce_1 = require("./make-nonce");
|
|
15
|
+
const getIdealMaximumFrameCacheItems = () => {
|
|
16
|
+
const freeMemory = node_os_1.default.freemem();
|
|
17
|
+
// Assuming 1 frame is approximately 6MB
|
|
18
|
+
// Assuming only half the available memory should be used
|
|
19
|
+
const max = Math.floor(freeMemory / (1024 * 1024 * 6));
|
|
20
|
+
// Never store more than 1000 frames
|
|
21
|
+
// But 100 is needed even if it's going to swap
|
|
22
|
+
return Math.max(100, Math.min(max, 1000));
|
|
23
|
+
};
|
|
24
|
+
exports.getIdealMaximumFrameCacheItems = getIdealMaximumFrameCacheItems;
|
|
25
|
+
const startLongRunningCompositor = (maximumFrameCacheItems, verbose) => {
|
|
26
|
+
return (0, exports.startCompositor)('StartLongRunningProcess', {
|
|
27
|
+
concurrency: (0, get_concurrency_1.getActualConcurrency)(null),
|
|
28
|
+
maximum_frame_cache_items: maximumFrameCacheItems,
|
|
29
|
+
verbose,
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
exports.startLongRunningCompositor = startLongRunningCompositor;
|
|
33
|
+
const startCompositor = (type, payload) => {
|
|
34
|
+
var _a;
|
|
35
|
+
const bin = (0, get_executable_path_1.getExecutablePath)('compositor');
|
|
36
|
+
(0, node_fs_1.chmodSync)(bin, 0o755);
|
|
37
|
+
const fullCommand = (0, compose_1.serializeCommand)(type, payload);
|
|
38
|
+
const child = (0, node_child_process_1.spawn)(bin, [JSON.stringify(fullCommand)], (0, call_ffmpeg_1.dynamicLibraryPathOptions)());
|
|
39
|
+
const stderrChunks = [];
|
|
40
|
+
let outputBuffer = Buffer.from('');
|
|
41
|
+
const separator = Buffer.from('remotion_buffer:');
|
|
42
|
+
const waiters = new Map();
|
|
43
|
+
const onMessage = (statusType, nonce, data) => {
|
|
44
|
+
if (nonce === '0') {
|
|
45
|
+
console.log(data.toString('utf8'));
|
|
46
|
+
}
|
|
47
|
+
if (waiters.has(nonce)) {
|
|
48
|
+
if (statusType === 'error') {
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(data.toString('utf8'));
|
|
51
|
+
waiters.get(nonce).reject(new Error(`Compositor error: ${parsed.error}\n${parsed.backtrace}`));
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
waiters.get(nonce).reject(new Error(data.toString('utf8')));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
waiters.get(nonce).resolve(data);
|
|
59
|
+
}
|
|
60
|
+
waiters.delete(nonce);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
let quit = false;
|
|
64
|
+
let missingData = null;
|
|
65
|
+
const processInput = () => {
|
|
66
|
+
let separatorIndex = outputBuffer.indexOf(separator);
|
|
67
|
+
if (separatorIndex === -1) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
separatorIndex += separator.length;
|
|
71
|
+
let nonceString = '';
|
|
72
|
+
let lengthString = '';
|
|
73
|
+
let statusString = '';
|
|
74
|
+
// Each message from Rust is prefixed with `remotion_buffer;{[nonce]}:{[length]}`
|
|
75
|
+
// Let's read the buffer to extract the nonce, and if the full length is available,
|
|
76
|
+
// we'll extract the data and pass it to the callback.
|
|
77
|
+
// eslint-disable-next-line no-constant-condition
|
|
78
|
+
while (true) {
|
|
79
|
+
const nextDigit = outputBuffer[separatorIndex];
|
|
80
|
+
// 0x3a is the character ":"
|
|
81
|
+
if (nextDigit === 0x3a) {
|
|
82
|
+
separatorIndex++;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
separatorIndex++;
|
|
86
|
+
nonceString += String.fromCharCode(nextDigit);
|
|
87
|
+
}
|
|
88
|
+
// eslint-disable-next-line no-constant-condition
|
|
89
|
+
while (true) {
|
|
90
|
+
const nextDigit = outputBuffer[separatorIndex];
|
|
91
|
+
if (nextDigit === 0x3a) {
|
|
92
|
+
separatorIndex++;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
separatorIndex++;
|
|
96
|
+
lengthString += String.fromCharCode(nextDigit);
|
|
97
|
+
}
|
|
98
|
+
// eslint-disable-next-line no-constant-condition
|
|
99
|
+
while (true) {
|
|
100
|
+
const nextDigit = outputBuffer[separatorIndex];
|
|
101
|
+
if (nextDigit === 0x3a) {
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
separatorIndex++;
|
|
105
|
+
statusString += String.fromCharCode(nextDigit);
|
|
106
|
+
}
|
|
107
|
+
const length = Number(lengthString);
|
|
108
|
+
const status = Number(statusString);
|
|
109
|
+
const dataLength = outputBuffer.length - separatorIndex - 1;
|
|
110
|
+
if (dataLength < length) {
|
|
111
|
+
missingData = {
|
|
112
|
+
dataMissing: length - dataLength,
|
|
113
|
+
};
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const data = outputBuffer.subarray(separatorIndex + 1, separatorIndex + 1 + Number(lengthString));
|
|
117
|
+
onMessage(status === 1 ? 'error' : 'success', nonceString, data);
|
|
118
|
+
missingData = null;
|
|
119
|
+
outputBuffer = outputBuffer.subarray(separatorIndex + Number(lengthString) + 1);
|
|
120
|
+
processInput();
|
|
121
|
+
};
|
|
122
|
+
let unprocessedBuffers = [];
|
|
123
|
+
child.stdout.on('data', (data) => {
|
|
124
|
+
unprocessedBuffers.push(data);
|
|
125
|
+
const separatorIndex = data.indexOf(separator);
|
|
126
|
+
if (separatorIndex === -1) {
|
|
127
|
+
if (missingData) {
|
|
128
|
+
missingData.dataMissing -= data.length;
|
|
129
|
+
}
|
|
130
|
+
if (!missingData || missingData.dataMissing > 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
unprocessedBuffers.unshift(outputBuffer);
|
|
135
|
+
outputBuffer = Buffer.concat(unprocessedBuffers);
|
|
136
|
+
unprocessedBuffers = [];
|
|
137
|
+
processInput();
|
|
138
|
+
});
|
|
139
|
+
child.stderr.on('data', (data) => {
|
|
140
|
+
stderrChunks.push(data);
|
|
141
|
+
});
|
|
142
|
+
let resolve = null;
|
|
143
|
+
let reject = null;
|
|
144
|
+
child.on('close', (code) => {
|
|
145
|
+
quit = true;
|
|
146
|
+
const waitersToKill = Array.from(waiters.values());
|
|
147
|
+
if (code === 0) {
|
|
148
|
+
resolve === null || resolve === void 0 ? void 0 : resolve();
|
|
149
|
+
for (const waiter of waitersToKill) {
|
|
150
|
+
waiter.reject(new Error(`Compositor already quit`));
|
|
151
|
+
}
|
|
152
|
+
waiters.clear();
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
const error = new Error(`Compositor panicked: ${Buffer.concat(stderrChunks).toString('utf-8')}`);
|
|
156
|
+
for (const waiter of waitersToKill) {
|
|
157
|
+
waiter.reject(error);
|
|
158
|
+
}
|
|
159
|
+
waiters.clear();
|
|
160
|
+
reject === null || reject === void 0 ? void 0 : reject(error);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
waitForDone: () => {
|
|
165
|
+
return new Promise((res, rej) => {
|
|
166
|
+
if (quit) {
|
|
167
|
+
rej(new Error('Compositor already quit'));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
resolve = res;
|
|
171
|
+
reject = rej;
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
finishCommands: () => {
|
|
175
|
+
if (quit) {
|
|
176
|
+
throw new Error('Compositor already quit');
|
|
177
|
+
}
|
|
178
|
+
child.stdin.write('EOF\n');
|
|
179
|
+
},
|
|
180
|
+
executeCommand: (command, params) => {
|
|
181
|
+
if (quit) {
|
|
182
|
+
throw new Error('Compositor already quit');
|
|
183
|
+
}
|
|
184
|
+
return new Promise((_resolve, _reject) => {
|
|
185
|
+
const nonce = (0, make_nonce_1.makeNonce)();
|
|
186
|
+
const composed = {
|
|
187
|
+
nonce,
|
|
188
|
+
payload: {
|
|
189
|
+
type: command,
|
|
190
|
+
params,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
// TODO: Should have a way to error out a single task
|
|
194
|
+
child.stdin.write(JSON.stringify(composed) + '\n');
|
|
195
|
+
waiters.set(nonce, {
|
|
196
|
+
resolve: _resolve,
|
|
197
|
+
reject: _reject,
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
pid: (_a = child.pid) !== null && _a !== void 0 ? _a : null,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
exports.startCompositor = startCompositor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const getExecutablePath: () =>
|
|
1
|
+
export declare const getExecutablePath: (type: 'compositor' | 'ffmpeg' | 'ffprobe' | 'ffmpeg-cwd') => string;
|
|
@@ -7,21 +7,40 @@ function isMusl() {
|
|
|
7
7
|
const { glibcVersionRuntime } = process.report.getReport().header;
|
|
8
8
|
return !glibcVersionRuntime;
|
|
9
9
|
}
|
|
10
|
-
const getExecutablePath = () => {
|
|
10
|
+
const getExecutablePath = (type) => {
|
|
11
|
+
if (type === 'ffmpeg' && process.env.FFMPEG_BIN_PATH) {
|
|
12
|
+
return '/opt/ffmpeg/remotion/bin/ffmpeg';
|
|
13
|
+
}
|
|
14
|
+
if (type === 'ffprobe' && process.env.FFPROBE_BIN_PATH) {
|
|
15
|
+
return '/opt/ffmpeg/remotion/bin/ffprobe';
|
|
16
|
+
}
|
|
17
|
+
if (type === 'ffmpeg-cwd' && process.env.FFMPEG_CWD) {
|
|
18
|
+
return '/opt/ffmpeg';
|
|
19
|
+
}
|
|
20
|
+
if (type === 'compositor' && process.env.COMPOSITOR_PATH) {
|
|
21
|
+
return './compositor';
|
|
22
|
+
}
|
|
23
|
+
const key = type === 'compositor'
|
|
24
|
+
? 'binaryPath'
|
|
25
|
+
: type === 'ffmpeg'
|
|
26
|
+
? 'ffmpegPath'
|
|
27
|
+
: type === 'ffprobe'
|
|
28
|
+
? 'ffprobePath'
|
|
29
|
+
: 'ffmpegCwd';
|
|
11
30
|
switch (process.platform) {
|
|
12
31
|
case 'win32':
|
|
13
32
|
switch (process.arch) {
|
|
14
33
|
case 'x64':
|
|
15
|
-
return require('@remotion/compositor-win32-x64-msvc')
|
|
34
|
+
return require('@remotion/compositor-win32-x64-msvc')[key];
|
|
16
35
|
default:
|
|
17
36
|
throw new Error(`Unsupported architecture on Windows: ${process.arch}`);
|
|
18
37
|
}
|
|
19
38
|
case 'darwin':
|
|
20
39
|
switch (process.arch) {
|
|
21
40
|
case 'x64':
|
|
22
|
-
return require('@remotion/compositor-darwin-x64')
|
|
41
|
+
return require('@remotion/compositor-darwin-x64')[key];
|
|
23
42
|
case 'arm64':
|
|
24
|
-
return require('@remotion/compositor-darwin-arm64')
|
|
43
|
+
return require('@remotion/compositor-darwin-arm64')[key];
|
|
25
44
|
default:
|
|
26
45
|
throw new Error(`Unsupported architecture on macOS: ${process.arch}`);
|
|
27
46
|
}
|
|
@@ -29,14 +48,14 @@ const getExecutablePath = () => {
|
|
|
29
48
|
switch (process.arch) {
|
|
30
49
|
case 'x64':
|
|
31
50
|
if (isMusl()) {
|
|
32
|
-
return require('@remotion/compositor-linux-x64-musl')
|
|
51
|
+
return require('@remotion/compositor-linux-x64-musl')[key];
|
|
33
52
|
}
|
|
34
|
-
return require('@remotion/compositor-linux-x64-gnu')
|
|
53
|
+
return require('@remotion/compositor-linux-x64-gnu')[key];
|
|
35
54
|
case 'arm64':
|
|
36
55
|
if (isMusl()) {
|
|
37
|
-
return require('@remotion/compositor-linux-arm64-musl')
|
|
56
|
+
return require('@remotion/compositor-linux-arm64-musl')[key];
|
|
38
57
|
}
|
|
39
|
-
return require('@remotion/compositor-linux-arm64-gnu')
|
|
58
|
+
return require('@remotion/compositor-linux-arm64-gnu')[key];
|
|
40
59
|
default:
|
|
41
60
|
throw new Error(`Unsupported architecture on Linux: ${process.arch}`);
|
|
42
61
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const makeNonce: () => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeNonce = void 0;
|
|
4
|
+
const makeNonce = () => {
|
|
5
|
+
return (Math.random().toString(36).substring(2, 15) +
|
|
6
|
+
Math.random().toString(36).substring(2, 15));
|
|
7
|
+
};
|
|
8
|
+
exports.makeNonce = makeNonce;
|
|
@@ -27,13 +27,40 @@ export declare type Layer = {
|
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
export declare type CompositorImageFormat = 'Png' | 'Jpeg';
|
|
30
|
-
export declare type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
export declare type CompositorCommand = {
|
|
31
|
+
Compose: {
|
|
32
|
+
output: string;
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
layers: Layer[];
|
|
36
|
+
output_format: CompositorImageFormat;
|
|
37
|
+
};
|
|
38
|
+
ExtractFrame: {
|
|
39
|
+
input: string;
|
|
40
|
+
time: number;
|
|
41
|
+
transparent: boolean;
|
|
42
|
+
};
|
|
43
|
+
Echo: {
|
|
44
|
+
message: string;
|
|
45
|
+
};
|
|
46
|
+
StartLongRunningProcess: {
|
|
47
|
+
concurrency: number;
|
|
48
|
+
maximum_frame_cache_items: number;
|
|
49
|
+
verbose: boolean;
|
|
50
|
+
};
|
|
51
|
+
GetOpenVideoStats: {};
|
|
52
|
+
DeliberatePanic: {};
|
|
53
|
+
CloseAllVideos: {};
|
|
54
|
+
FreeUpMemory: {
|
|
55
|
+
percent_of_memory: number;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export declare type CompositorCommandSerialized<T extends keyof CompositorCommand> = {
|
|
59
|
+
nonce: string;
|
|
60
|
+
payload: {
|
|
61
|
+
type: T;
|
|
62
|
+
params: CompositorCommand[T];
|
|
63
|
+
};
|
|
37
64
|
};
|
|
38
65
|
export declare type ErrorPayload = {
|
|
39
66
|
error: string;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { DownloadMap } from './assets/download-map';
|
|
2
|
-
import type { FfmpegExecutable } from './ffmpeg-executable';
|
|
3
2
|
import type { PreprocessedAudioTrack } from './preprocess-audio-track';
|
|
4
|
-
export declare const createFfmpegComplexFilter: ({ filters, downloadMap,
|
|
3
|
+
export declare const createFfmpegComplexFilter: ({ filters, downloadMap, }: {
|
|
5
4
|
filters: PreprocessedAudioTrack[];
|
|
6
5
|
downloadMap: DownloadMap;
|
|
7
|
-
ffmpegExecutable: FfmpegExecutable;
|
|
8
|
-
remotionRoot: string;
|
|
9
6
|
}) => Promise<{
|
|
10
|
-
complexFilterFlag: [
|
|
7
|
+
complexFilterFlag: [
|
|
8
|
+
string,
|
|
9
|
+
string
|
|
10
|
+
] | null;
|
|
11
11
|
cleanup: () => void;
|
|
12
12
|
}>;
|
|
@@ -3,14 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createFfmpegComplexFilter = void 0;
|
|
4
4
|
const create_ffmpeg_merge_filter_1 = require("./create-ffmpeg-merge-filter");
|
|
5
5
|
const ffmpeg_filter_file_1 = require("./ffmpeg-filter-file");
|
|
6
|
-
const createFfmpegComplexFilter = async ({ filters, downloadMap,
|
|
6
|
+
const createFfmpegComplexFilter = async ({ filters, downloadMap, }) => {
|
|
7
7
|
if (filters.length === 0) {
|
|
8
8
|
return { complexFilterFlag: null, cleanup: () => undefined };
|
|
9
9
|
}
|
|
10
|
-
const complexFilter =
|
|
10
|
+
const complexFilter = (0, create_ffmpeg_merge_filter_1.createFfmpegMergeFilter)({
|
|
11
11
|
inputs: filters,
|
|
12
|
-
ffmpegExecutable,
|
|
13
|
-
remotionRoot,
|
|
14
12
|
});
|
|
15
13
|
const { file, cleanup } = await (0, ffmpeg_filter_file_1.makeFfmpegFilterFileStr)(complexFilter, downloadMap);
|
|
16
14
|
return {
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import type { FfmpegExecutable } from './ffmpeg-executable';
|
|
2
1
|
import type { PreprocessedAudioTrack } from './preprocess-audio-track';
|
|
3
2
|
export declare const OUTPUT_FILTER_NAME = "outputaudio";
|
|
4
|
-
export declare const createFfmpegMergeFilter: ({ inputs,
|
|
3
|
+
export declare const createFfmpegMergeFilter: ({ inputs, }: {
|
|
5
4
|
inputs: PreprocessedAudioTrack[];
|
|
6
|
-
|
|
7
|
-
remotionRoot: string;
|
|
8
|
-
}) => Promise<string>;
|
|
5
|
+
}) => string;
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createFfmpegMergeFilter = exports.OUTPUT_FILTER_NAME = void 0;
|
|
4
|
-
const ffmpeg_flags_1 = require("./ffmpeg-flags");
|
|
5
4
|
const truthy_1 = require("./truthy");
|
|
6
5
|
exports.OUTPUT_FILTER_NAME = 'outputaudio';
|
|
7
|
-
const createFfmpegMergeFilter =
|
|
8
|
-
const ffmpegVersion = await (0, ffmpeg_flags_1.getFfmpegVersion)({
|
|
9
|
-
ffmpegExecutable,
|
|
10
|
-
remotionRoot,
|
|
11
|
-
});
|
|
12
|
-
const supportsNormalize = ffmpegVersion === null ||
|
|
13
|
-
(ffmpegVersion[0] === 4 && ffmpegVersion[1] >= 4) ||
|
|
14
|
-
ffmpegVersion[0] >= 5;
|
|
6
|
+
const createFfmpegMergeFilter = ({ inputs, }) => {
|
|
15
7
|
const pads = inputs.map((input, index) => {
|
|
16
8
|
const filters = [
|
|
17
9
|
input.filter.pad_start ? input.filter.pad_start : null,
|
|
@@ -20,7 +12,7 @@ const createFfmpegMergeFilter = async ({ inputs, ffmpegExecutable, remotionRoot,
|
|
|
20
12
|
];
|
|
21
13
|
return `[${index}:a]${filters.filter(truthy_1.truthy).join(',')}[padded${index}]`;
|
|
22
14
|
});
|
|
23
|
-
const normalize =
|
|
15
|
+
const normalize = ':normalize=0';
|
|
24
16
|
return [
|
|
25
17
|
...pads,
|
|
26
18
|
`${new Array(inputs.length)
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const createSilentAudio: ({ ffmpegExecutable, numberOfSeconds, outName, remotionRoot, }: {
|
|
3
|
-
ffmpegExecutable: FfmpegExecutable;
|
|
1
|
+
export declare const createSilentAudio: ({ numberOfSeconds, outName, }: {
|
|
4
2
|
numberOfSeconds: number;
|
|
5
3
|
outName: string;
|
|
6
|
-
remotionRoot: string;
|
|
7
4
|
}) => Promise<void>;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.createSilentAudio = void 0;
|
|
7
|
-
const
|
|
8
|
-
const ffmpeg_flags_1 = require("./ffmpeg-flags");
|
|
4
|
+
const call_ffmpeg_1 = require("./call-ffmpeg");
|
|
9
5
|
const sample_rate_1 = require("./sample-rate");
|
|
10
|
-
const createSilentAudio = async ({
|
|
11
|
-
await (0,
|
|
6
|
+
const createSilentAudio = async ({ numberOfSeconds, outName, }) => {
|
|
7
|
+
await (0, call_ffmpeg_1.callFf)('ffmpeg', [
|
|
12
8
|
'-f',
|
|
13
9
|
'lavfi',
|
|
14
10
|
'-i',
|
package/dist/crf.js
CHANGED
|
@@ -9,7 +9,7 @@ const getDefaultCrfForCodec = (codec) => {
|
|
|
9
9
|
if (codec === 'h264' || codec === 'h264-mkv') {
|
|
10
10
|
return 18; // FFMPEG default 23
|
|
11
11
|
}
|
|
12
|
-
if (codec === 'h265'
|
|
12
|
+
if (codec === 'h265') {
|
|
13
13
|
return 23; // FFMPEG default 28
|
|
14
14
|
}
|
|
15
15
|
if (codec === 'vp8') {
|
|
@@ -21,6 +21,9 @@ const getDefaultCrfForCodec = (codec) => {
|
|
|
21
21
|
if (codec === 'prores') {
|
|
22
22
|
return 0;
|
|
23
23
|
}
|
|
24
|
+
if (codec === 'gif') {
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
24
27
|
throw new TypeError(`Got unexpected codec "${codec}"`);
|
|
25
28
|
};
|
|
26
29
|
exports.getDefaultCrfForCodec = getDefaultCrfForCodec;
|
|
@@ -31,10 +34,13 @@ const getValidCrfRanges = (codec) => {
|
|
|
31
34
|
if (codec === 'prores') {
|
|
32
35
|
return [0, 0];
|
|
33
36
|
}
|
|
37
|
+
if (codec === 'gif') {
|
|
38
|
+
return [0, 0];
|
|
39
|
+
}
|
|
34
40
|
if (codec === 'h264' || codec === 'h264-mkv') {
|
|
35
41
|
return [1, 51];
|
|
36
42
|
}
|
|
37
|
-
if (codec === 'h265'
|
|
43
|
+
if (codec === 'h265') {
|
|
38
44
|
return [0, 51];
|
|
39
45
|
}
|
|
40
46
|
if (codec === 'vp8') {
|