@remotion/renderer 4.0.533 → 4.0.535
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/aac-priming.js +6 -2
- package/dist/browser/BrowserFetcher.d.ts +7 -1
- package/dist/browser/BrowserFetcher.js +33 -13
- package/dist/browser/BrowserPage.js +4 -0
- package/dist/browser/Connection.js +5 -17
- package/dist/browser/DOMWorld.js +19 -13
- package/dist/browser/devtools-commands.d.ts +13 -1
- package/dist/browser/devtools-types.d.ts +62 -0
- package/dist/browser/get-chrome-download-url.d.ts +1 -1
- package/dist/browser/get-chrome-download-url.js +19 -33
- package/dist/can-use-parallel-encoding.d.ts +0 -1
- package/dist/can-use-parallel-encoding.js +10 -10
- package/dist/client.d.ts +402 -4
- package/dist/client.js +2 -0
- package/dist/combine-chunks.d.ts +2 -1
- package/dist/combine-chunks.js +81 -52
- package/dist/combine-video-streams.js +3 -0
- package/dist/compositor/get-executable-path.js +30 -15
- package/dist/cycle-browser-tabs.js +9 -1
- package/dist/ensure-browser.d.ts +3 -0
- package/dist/ensure-browser.js +30 -6
- package/dist/esm/client.mjs +1325 -954
- package/dist/esm/index.mjs +4465 -3324
- package/dist/esm/pure.mjs +36 -10
- package/dist/file-extensions.js +4 -1
- package/dist/get-mp4-brand.d.ts +1 -0
- package/dist/get-mp4-brand.js +21 -0
- package/dist/get-video-threads-flag.js +5 -1
- package/dist/image-format.d.ts +1 -0
- package/dist/image-format.js +8 -4
- package/dist/index.d.ts +58 -2
- package/dist/index.js +4 -0
- package/dist/memory/from-macos-sysctl.d.ts +1 -0
- package/dist/memory/from-macos-sysctl.js +50 -0
- package/dist/memory/from-proc-meminfo.d.ts +1 -1
- package/dist/memory/from-proc-meminfo.js +7 -4
- package/dist/memory/get-available-memory.js +29 -21
- package/dist/mux-video-and-audio.js +11 -2
- package/dist/next-frame-to-render.d.ts +3 -7
- package/dist/next-frame-to-render.js +3 -22
- package/dist/open-browser.js +1 -0
- package/dist/options/allow-html-in-canvas.d.ts +1 -0
- package/dist/options/allow-html-in-canvas.js +2 -1
- package/dist/options/api-key.d.ts +1 -0
- package/dist/options/api-key.js +2 -1
- package/dist/options/ask-ai.d.ts +1 -0
- package/dist/options/ask-ai.js +2 -1
- package/dist/options/audio-bitrate.d.ts +1 -0
- package/dist/options/audio-bitrate.js +2 -1
- package/dist/options/audio-codec.d.ts +1 -0
- package/dist/options/audio-codec.js +13 -6
- package/dist/options/beep-on-finish.d.ts +1 -0
- package/dist/options/beep-on-finish.js +2 -1
- package/dist/options/benchmark-concurrencies.d.ts +1 -0
- package/dist/options/benchmark-concurrencies.js +2 -1
- package/dist/options/binaries-directory.d.ts +1 -0
- package/dist/options/binaries-directory.js +2 -1
- package/dist/options/browser-executable.d.ts +1 -0
- package/dist/options/browser-executable.js +2 -1
- package/dist/options/browser.d.ts +1 -0
- package/dist/options/browser.js +2 -1
- package/dist/options/bundle-cache.d.ts +1 -0
- package/dist/options/bundle-cache.js +2 -1
- package/dist/options/canvas-tabs.d.ts +1 -0
- package/dist/options/canvas-tabs.js +2 -1
- package/dist/options/chrome-mode.d.ts +1 -0
- package/dist/options/chrome-mode.js +2 -1
- package/dist/options/color-space.d.ts +1 -0
- package/dist/options/color-space.js +2 -1
- package/dist/options/concurrency.d.ts +1 -0
- package/dist/options/concurrency.js +2 -1
- package/dist/options/config.d.ts +1 -0
- package/dist/options/config.js +2 -1
- package/dist/options/crf.d.ts +1 -0
- package/dist/options/crf.js +2 -1
- package/dist/options/cross-site-isolation.d.ts +1 -0
- package/dist/options/cross-site-isolation.js +2 -1
- package/dist/options/dark-mode.d.ts +1 -0
- package/dist/options/dark-mode.js +2 -1
- package/dist/options/default-coding-agent.d.ts +1 -0
- package/dist/options/default-coding-agent.js +2 -1
- package/dist/options/default-editor.d.ts +1 -0
- package/dist/options/default-editor.js +2 -1
- package/dist/options/default-premount-in-seconds.d.ts +19 -0
- package/dist/options/default-premount-in-seconds.js +36 -0
- package/dist/options/delete-after.d.ts +1 -0
- package/dist/options/delete-after.js +2 -1
- package/dist/options/disable-git-source.d.ts +1 -0
- package/dist/options/disable-git-source.js +2 -1
- package/dist/options/disable-shared-memory-capture.d.ts +17 -0
- package/dist/options/disable-shared-memory-capture.js +30 -0
- package/dist/options/disable-web-security.d.ts +1 -0
- package/dist/options/disable-web-security.js +2 -1
- package/dist/options/disallow-parallel-encoding.d.ts +1 -0
- package/dist/options/disallow-parallel-encoding.js +2 -1
- package/dist/options/enable-cancellation.d.ts +1 -0
- package/dist/options/enable-cancellation.js +2 -1
- package/dist/options/enable-lambda-insights.d.ts +1 -0
- package/dist/options/enable-lambda-insights.js +2 -1
- package/dist/options/enable-multiprocess-on-linux.d.ts +1 -0
- package/dist/options/enable-multiprocess-on-linux.js +2 -1
- package/dist/options/encoding-buffer-size.d.ts +1 -0
- package/dist/options/encoding-buffer-size.js +2 -1
- package/dist/options/encoding-max-rate.d.ts +1 -0
- package/dist/options/encoding-max-rate.js +2 -1
- package/dist/options/enforce-audio.d.ts +1 -0
- package/dist/options/enforce-audio.js +2 -1
- package/dist/options/env-file.d.ts +1 -0
- package/dist/options/env-file.js +2 -1
- package/dist/options/every-nth-frame.d.ts +1 -0
- package/dist/options/every-nth-frame.js +2 -1
- package/dist/options/experimental-keep-audio-context-alive.d.ts +1 -0
- package/dist/options/experimental-keep-audio-context-alive.js +2 -1
- package/dist/options/experimental-sequence-activity-limit.d.ts +19 -0
- package/dist/options/experimental-sequence-activity-limit.js +40 -0
- package/dist/options/experimental-sequence-activity.d.ts +19 -0
- package/dist/options/experimental-sequence-activity.js +38 -0
- package/dist/options/experimental-tracks.d.ts +19 -0
- package/dist/options/experimental-tracks.js +43 -0
- package/dist/options/folder-expiry.d.ts +1 -0
- package/dist/options/folder-expiry.js +2 -1
- package/dist/options/for-seamless-aac-concatenation.d.ts +1 -0
- package/dist/options/for-seamless-aac-concatenation.js +2 -1
- package/dist/options/force-new-studio.d.ts +1 -0
- package/dist/options/force-new-studio.js +2 -1
- package/dist/options/frames.d.ts +1 -0
- package/dist/options/frames.js +2 -1
- package/dist/options/gl.d.ts +1 -0
- package/dist/options/gl.js +2 -1
- package/dist/options/gop-size.d.ts +1 -0
- package/dist/options/gop-size.js +2 -1
- package/dist/options/hardware-acceleration.d.ts +1 -0
- package/dist/options/hardware-acceleration.js +2 -1
- package/dist/options/headless.d.ts +1 -0
- package/dist/options/headless.js +2 -1
- package/dist/options/ignore-certificate-errors.d.ts +1 -0
- package/dist/options/ignore-certificate-errors.js +2 -1
- package/dist/options/image-sequence-pattern.d.ts +2 -1
- package/dist/options/image-sequence-pattern.js +2 -1
- package/dist/options/image-sequence.d.ts +1 -0
- package/dist/options/image-sequence.js +2 -1
- package/dist/options/index.d.ts +211 -2
- package/dist/options/index.js +12 -0
- package/dist/options/interactivity.d.ts +1 -0
- package/dist/options/interactivity.js +2 -1
- package/dist/options/ipv4.d.ts +1 -0
- package/dist/options/ipv4.js +2 -1
- package/dist/options/is-production.d.ts +1 -0
- package/dist/options/is-production.js +2 -1
- package/dist/options/jpeg-quality.d.ts +1 -0
- package/dist/options/jpeg-quality.js +6 -2
- package/dist/options/keyboard-shortcuts.d.ts +1 -0
- package/dist/options/keyboard-shortcuts.js +2 -1
- package/dist/options/latency-hint.d.ts +1 -0
- package/dist/options/latency-hint.js +2 -1
- package/dist/options/license-key.d.ts +1 -0
- package/dist/options/license-key.js +2 -1
- package/dist/options/log-level.d.ts +1 -0
- package/dist/options/log-level.js +2 -1
- package/dist/options/metadata.d.ts +1 -0
- package/dist/options/metadata.js +2 -1
- package/dist/options/mute.d.ts +1 -0
- package/dist/options/mute.js +2 -1
- package/dist/options/no-open.d.ts +1 -0
- package/dist/options/no-open.js +2 -1
- package/dist/options/number-of-gif-loops.d.ts +1 -0
- package/dist/options/number-of-gif-loops.js +2 -1
- package/dist/options/number-of-shared-audio-tags.d.ts +1 -0
- package/dist/options/number-of-shared-audio-tags.js +2 -1
- package/dist/options/offthreadvideo-cache-size.d.ts +1 -0
- package/dist/options/offthreadvideo-cache-size.js +2 -1
- package/dist/options/offthreadvideo-threads.d.ts +1 -0
- package/dist/options/offthreadvideo-threads.js +2 -1
- package/dist/options/on-browser-download.d.ts +1 -0
- package/dist/options/on-browser-download.js +2 -1
- package/dist/options/option.d.ts +1 -0
- package/dist/options/options-map.d.ts +189 -1
- package/dist/options/options-map.js +4 -0
- package/dist/options/out-dir.d.ts +1 -0
- package/dist/options/out-dir.js +2 -1
- package/dist/options/override-duration.d.ts +1 -0
- package/dist/options/override-duration.js +2 -1
- package/dist/options/override-fps.d.ts +1 -0
- package/dist/options/override-fps.js +2 -1
- package/dist/options/override-height.d.ts +1 -0
- package/dist/options/override-height.js +2 -1
- package/dist/options/override-width.d.ts +1 -0
- package/dist/options/override-width.js +2 -1
- package/dist/options/overwrite.d.ts +1 -0
- package/dist/options/overwrite.js +2 -1
- package/dist/options/package-manager.d.ts +1 -0
- package/dist/options/package-manager.js +2 -1
- package/dist/options/pixel-format.d.ts +1 -0
- package/dist/options/pixel-format.js +2 -1
- package/dist/options/port.d.ts +1 -0
- package/dist/options/port.js +2 -1
- package/dist/options/prefer-lossless.d.ts +1 -0
- package/dist/options/prefer-lossless.js +2 -1
- package/dist/options/preview-sample-rate.d.ts +1 -0
- package/dist/options/preview-sample-rate.js +2 -1
- package/dist/options/props.d.ts +1 -0
- package/dist/options/props.js +2 -1
- package/dist/options/prores-profile.d.ts +1 -0
- package/dist/options/prores-profile.js +2 -1
- package/dist/options/public-dir.d.ts +1 -0
- package/dist/options/public-dir.js +2 -1
- package/dist/options/public-license-key.d.ts +1 -0
- package/dist/options/public-license-key.js +2 -1
- package/dist/options/public-path.d.ts +1 -0
- package/dist/options/public-path.js +2 -1
- package/dist/options/repro.d.ts +1 -0
- package/dist/options/repro.js +2 -1
- package/dist/options/rspack.d.ts +2 -1
- package/dist/options/rspack.js +2 -1
- package/dist/options/runs.d.ts +1 -0
- package/dist/options/runs.js +2 -1
- package/dist/options/sample-rate.d.ts +1 -0
- package/dist/options/sample-rate.js +2 -1
- package/dist/options/scale.d.ts +1 -0
- package/dist/options/scale.js +2 -1
- package/dist/options/separate-audio.d.ts +1 -0
- package/dist/options/separate-audio.js +3 -2
- package/dist/options/show-premounting.d.ts +19 -0
- package/dist/options/show-premounting.js +33 -0
- package/dist/options/skip-skills.d.ts +1 -0
- package/dist/options/skip-skills.js +2 -1
- package/dist/options/still-frame.d.ts +1 -0
- package/dist/options/still-frame.js +2 -1
- package/dist/options/still-image-format.d.ts +1 -0
- package/dist/options/still-image-format.js +2 -1
- package/dist/options/throw-if-site-exists.d.ts +1 -0
- package/dist/options/throw-if-site-exists.js +2 -1
- package/dist/options/timeout.d.ts +1 -0
- package/dist/options/timeout.js +2 -1
- package/dist/options/user-agent.d.ts +1 -0
- package/dist/options/user-agent.js +2 -1
- package/dist/options/version-flag.d.ts +1 -0
- package/dist/options/version-flag.js +2 -1
- package/dist/options/video-bitrate.d.ts +1 -0
- package/dist/options/video-bitrate.js +2 -1
- package/dist/options/video-cache-size.d.ts +1 -0
- package/dist/options/video-cache-size.js +2 -1
- package/dist/options/video-codec.d.ts +1 -0
- package/dist/options/video-codec.js +5 -3
- package/dist/options/video-image-format.d.ts +1 -0
- package/dist/options/video-image-format.js +7 -2
- package/dist/options/webhook-custom-data.d.ts +1 -0
- package/dist/options/webhook-custom-data.js +2 -1
- package/dist/options/webpack-poll.d.ts +1 -0
- package/dist/options/webpack-poll.js +2 -1
- package/dist/options/x264-preset.d.ts +1 -0
- package/dist/options/x264-preset.js +2 -1
- package/dist/prespawn-ffmpeg.d.ts +20 -0
- package/dist/prespawn-ffmpeg.js +157 -29
- package/dist/probe-shared-memory-capture.d.ts +8 -0
- package/dist/probe-shared-memory-capture.js +111 -0
- package/dist/puppeteer-screenshot.d.ts +3 -1
- package/dist/puppeteer-screenshot.js +1 -0
- package/dist/pure.d.ts +1 -1
- package/dist/remotion-shared-memory-ffmpeg.d.ts +26 -0
- package/dist/remotion-shared-memory-ffmpeg.js +312 -0
- package/dist/remotion-shared-memory.d.ts +49 -0
- package/dist/remotion-shared-memory.js +359 -0
- package/dist/render-frame-and-retry-target-close.d.ts +5 -2
- package/dist/render-frame-and-retry-target-close.js +20 -4
- package/dist/render-frame-with-option-to-reject.d.ts +4 -1
- package/dist/render-frame-with-option-to-reject.js +206 -115
- package/dist/render-frame.d.ts +4 -5
- package/dist/render-frame.js +3 -1
- package/dist/render-frames.d.ts +3 -0
- package/dist/render-frames.js +15 -18
- package/dist/render-media.d.ts +1 -1
- package/dist/render-media.js +131 -46
- package/dist/render-still.js +1 -0
- package/dist/screenshot-background.d.ts +2 -0
- package/dist/screenshot-background.js +20 -0
- package/dist/screenshot-task.d.ts +4 -2
- package/dist/screenshot-task.js +40 -21
- package/dist/seek-to-frame.js +1 -1
- package/dist/stitch-frames-to-video.js +71 -10
- package/dist/take-frame.d.ts +11 -3
- package/dist/take-frame.js +10 -8
- package/dist/validate-output-filename.d.ts +1 -1
- package/dist/validate-output-filename.js +10 -2
- package/package.json +13 -13
|
@@ -0,0 +1,111 @@
|
|
|
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.probeSharedMemoryCapture = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const get_local_browser_executable_1 = require("./get-local-browser-executable");
|
|
11
|
+
const open_browser_1 = require("./open-browser");
|
|
12
|
+
const prespawn_ffmpeg_1 = require("./prespawn-ffmpeg");
|
|
13
|
+
const remotion_shared_memory_1 = require("./remotion-shared-memory");
|
|
14
|
+
const probes = new Map();
|
|
15
|
+
const probeSharedMemoryCapture = async ({ browserExecutable, chromeMode, chromiumOptions, binariesDirectory, logLevel, }) => {
|
|
16
|
+
// Opening the render modal should not download a browser.
|
|
17
|
+
let executablePath;
|
|
18
|
+
let executableStat;
|
|
19
|
+
try {
|
|
20
|
+
executablePath = (0, get_local_browser_executable_1.getLocalBrowserExecutable)({
|
|
21
|
+
preferredBrowserExecutable: browserExecutable,
|
|
22
|
+
chromeMode,
|
|
23
|
+
indent: false,
|
|
24
|
+
logLevel,
|
|
25
|
+
});
|
|
26
|
+
executableStat = node_fs_1.default.statSync(executablePath);
|
|
27
|
+
}
|
|
28
|
+
catch (_a) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const key = JSON.stringify({
|
|
32
|
+
executablePath,
|
|
33
|
+
mtime: executableStat.mtimeMs,
|
|
34
|
+
ctime: executableStat.ctimeMs,
|
|
35
|
+
size: executableStat.size,
|
|
36
|
+
chromeMode,
|
|
37
|
+
chromiumOptions,
|
|
38
|
+
binariesDirectory,
|
|
39
|
+
backend: (0, remotion_shared_memory_1.getPreferredRemotionSharedMemoryBackend)(),
|
|
40
|
+
});
|
|
41
|
+
const cached = probes.get(key);
|
|
42
|
+
if (cached) {
|
|
43
|
+
return cached;
|
|
44
|
+
}
|
|
45
|
+
const probe = (async () => {
|
|
46
|
+
const support = await (0, prespawn_ffmpeg_1.probeRemotionSharedMemoryFfmpegSupport)({
|
|
47
|
+
binariesDirectory,
|
|
48
|
+
indent: false,
|
|
49
|
+
logLevel,
|
|
50
|
+
});
|
|
51
|
+
if (!support.sharedMemory) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const browser = await (0, open_browser_1.openBrowser)('chrome', {
|
|
55
|
+
browserExecutable: executablePath,
|
|
56
|
+
chromeMode,
|
|
57
|
+
chromiumOptions: { ...chromiumOptions, headless: true },
|
|
58
|
+
forceDeviceScaleFactor: 1,
|
|
59
|
+
logLevel,
|
|
60
|
+
});
|
|
61
|
+
let backingDirectory = null;
|
|
62
|
+
let capture = null;
|
|
63
|
+
try {
|
|
64
|
+
backingDirectory = support.filePools
|
|
65
|
+
? node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'remotion-shm-probe-'))
|
|
66
|
+
: null;
|
|
67
|
+
capture = new remotion_shared_memory_1.RemotionSharedMemoryCapture({
|
|
68
|
+
width: 16,
|
|
69
|
+
height: 16,
|
|
70
|
+
indent: false,
|
|
71
|
+
logLevel,
|
|
72
|
+
backingDirectory,
|
|
73
|
+
});
|
|
74
|
+
const page = await browser.newPage({
|
|
75
|
+
context: () => null,
|
|
76
|
+
logLevel,
|
|
77
|
+
indent: false,
|
|
78
|
+
pageIndex: 0,
|
|
79
|
+
onBrowserLog: null,
|
|
80
|
+
onLog: () => undefined,
|
|
81
|
+
});
|
|
82
|
+
await capture.initializePages([page]);
|
|
83
|
+
return capture.isSupported();
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
try {
|
|
87
|
+
await (capture === null || capture === void 0 ? void 0 : capture.dispose());
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
try {
|
|
91
|
+
await browser.close({ silent: true });
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
if (backingDirectory !== null) {
|
|
95
|
+
node_fs_1.default.rmSync(backingDirectory, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
101
|
+
probes.set(key, probe);
|
|
102
|
+
try {
|
|
103
|
+
return await probe;
|
|
104
|
+
}
|
|
105
|
+
catch (_b) {
|
|
106
|
+
// Keep the screenshot controls if probing fails, and retry next time.
|
|
107
|
+
probes.delete(key);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
exports.probeSharedMemoryCapture = probeSharedMemoryCapture;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Page } from './browser/BrowserPage';
|
|
2
|
+
import type { CapturedFrame, RemotionSharedMemoryCapture } from './remotion-shared-memory';
|
|
2
3
|
export declare const screenshot: (options: {
|
|
3
4
|
page: Page;
|
|
4
5
|
type: "jpeg" | "pdf" | "png" | "webp";
|
|
@@ -8,4 +9,5 @@ export declare const screenshot: (options: {
|
|
|
8
9
|
width: number;
|
|
9
10
|
height: number;
|
|
10
11
|
scale: number;
|
|
11
|
-
|
|
12
|
+
remotionSharedMemory: RemotionSharedMemoryCapture | null;
|
|
13
|
+
}) => Promise<CapturedFrame>;
|
package/dist/pure.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare const NoReactAPIs: {
|
|
|
4
4
|
validateOutputFilename: <T extends "aac" | "av1" | "gif" | "h264" | "h264-mkv" | "h264-ts" | "h265" | "mp3" | "prores" | "vp8" | "vp9" | "wav">({ codec, audioCodecSetting, extension, preferLossless, separateAudioTo, }: {
|
|
5
5
|
codec: T;
|
|
6
6
|
audioCodecSetting: "aac" | "mp3" | "opus" | "pcm-16" | null;
|
|
7
|
-
extension: string;
|
|
7
|
+
extension: string | null;
|
|
8
8
|
preferLossless: boolean;
|
|
9
9
|
separateAudioTo: string | null;
|
|
10
10
|
}) => void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Readable, Writable } from 'node:stream';
|
|
2
|
+
import type { RemotionRawFrame } from './remotion-shared-memory';
|
|
3
|
+
export declare const serializeRemotionSharedMemoryPool: (frame: RemotionRawFrame) => string;
|
|
4
|
+
export declare const serializeRemotionSharedMemoryFrame: ({ frame, pts, }: {
|
|
5
|
+
frame: RemotionRawFrame;
|
|
6
|
+
pts: number;
|
|
7
|
+
}) => string;
|
|
8
|
+
export declare const serializeRemotionSharedMemoryPoolRetirement: (poolId: number) => string;
|
|
9
|
+
export declare const parseRemotionSharedMemoryAck: (line: string) => {
|
|
10
|
+
poolId: number;
|
|
11
|
+
slot: number;
|
|
12
|
+
frameId: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const createRemotionSharedMemoryFfmpegBridge: ({ control, acknowledgements, }: {
|
|
15
|
+
control: Writable;
|
|
16
|
+
acknowledgements: Readable;
|
|
17
|
+
}) => {
|
|
18
|
+
writeFrame: ({ frame, pts, }: {
|
|
19
|
+
frame: RemotionRawFrame;
|
|
20
|
+
pts: number;
|
|
21
|
+
}) => Promise<{
|
|
22
|
+
waitForAck: Promise<void>;
|
|
23
|
+
}>;
|
|
24
|
+
finish: () => Promise<void>;
|
|
25
|
+
fail: (error: Error) => void;
|
|
26
|
+
};
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRemotionSharedMemoryFfmpegBridge = exports.parseRemotionSharedMemoryAck = exports.serializeRemotionSharedMemoryPoolRetirement = exports.serializeRemotionSharedMemoryFrame = exports.serializeRemotionSharedMemoryPool = void 0;
|
|
4
|
+
const node_readline_1 = require("node:readline");
|
|
5
|
+
const write_with_backpressure_1 = require("./write-with-backpressure");
|
|
6
|
+
const pendingKey = (poolId, slot) => `${poolId}:${slot}`;
|
|
7
|
+
// The optional sixth field names the backend. It is omitted for POSIX shared
|
|
8
|
+
// memory so FFmpeg binaries that predate file-backed pools keep working.
|
|
9
|
+
const serializeRemotionSharedMemoryPool = (frame) => `P\t${frame.poolId}\t${frame.sharedMemoryName}\t${frame.slotCount}\t${frame.slotCapacity}${frame.backend === 'file' ? '\tfile' : ''}\n`;
|
|
10
|
+
exports.serializeRemotionSharedMemoryPool = serializeRemotionSharedMemoryPool;
|
|
11
|
+
const serializeRemotionSharedMemoryFrame = ({ frame, pts, }) => `F\t${frame.poolId}\t${frame.slot}\t${frame.frameId}\t${frame.width}\t${frame.height}\t${frame.stride}\t${frame.byteLength}\t${pts}\n`;
|
|
12
|
+
exports.serializeRemotionSharedMemoryFrame = serializeRemotionSharedMemoryFrame;
|
|
13
|
+
const serializeRemotionSharedMemoryPoolRetirement = (poolId) => `U\t${poolId}\n`;
|
|
14
|
+
exports.serializeRemotionSharedMemoryPoolRetirement = serializeRemotionSharedMemoryPoolRetirement;
|
|
15
|
+
const parseRemotionSharedMemoryAck = (line) => {
|
|
16
|
+
const match = /^(\d+)\t(\d+)\t(\d+)$/.exec(line);
|
|
17
|
+
if (!match) {
|
|
18
|
+
throw new Error(`Invalid Remotion shared-memory ACK: ${line}`);
|
|
19
|
+
}
|
|
20
|
+
const poolId = Number(match[1]);
|
|
21
|
+
const slot = Number(match[2]);
|
|
22
|
+
if (!Number.isSafeInteger(poolId) ||
|
|
23
|
+
poolId < 1 ||
|
|
24
|
+
!Number.isSafeInteger(slot) ||
|
|
25
|
+
slot < 0) {
|
|
26
|
+
throw new Error(`Invalid Remotion shared-memory ACK: ${line}`);
|
|
27
|
+
}
|
|
28
|
+
return { poolId, slot, frameId: match[3] };
|
|
29
|
+
};
|
|
30
|
+
exports.parseRemotionSharedMemoryAck = parseRemotionSharedMemoryAck;
|
|
31
|
+
const createRemotionSharedMemoryFfmpegBridge = ({ control, acknowledgements, }) => {
|
|
32
|
+
const registeredPools = new Map();
|
|
33
|
+
const pending = new Map();
|
|
34
|
+
let fatalError = null;
|
|
35
|
+
let finishing = false;
|
|
36
|
+
let controlEnded = false;
|
|
37
|
+
let controlWrites = Promise.resolve();
|
|
38
|
+
let finishPromise = null;
|
|
39
|
+
const toError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
40
|
+
const releaseIgnoringErrors = async (frame) => {
|
|
41
|
+
try {
|
|
42
|
+
await frame.release();
|
|
43
|
+
}
|
|
44
|
+
catch (_a) {
|
|
45
|
+
// The original bridge error is more useful. release() still abandons the
|
|
46
|
+
// local slot in a finally block if the CDP session is unavailable.
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const settleRegistration = (pool, registered) => {
|
|
50
|
+
if (pool.registrationSettled) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
pool.registrationSettled = true;
|
|
54
|
+
pool.registered = registered;
|
|
55
|
+
pool.resolveRegistration(registered);
|
|
56
|
+
};
|
|
57
|
+
const signalPoolDrained = (pool) => {
|
|
58
|
+
if (pool.pendingCount === 0) {
|
|
59
|
+
pool.drainWaiters.splice(0).forEach((waiter) => waiter());
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const removePending = (key, value) => {
|
|
63
|
+
if (pending.get(key) !== value) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
pending.delete(key);
|
|
67
|
+
value.pool.pendingCount--;
|
|
68
|
+
signalPoolDrained(value.pool);
|
|
69
|
+
return true;
|
|
70
|
+
};
|
|
71
|
+
const fail = (error) => {
|
|
72
|
+
if (fatalError) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
fatalError = error;
|
|
76
|
+
for (const pool of registeredPools.values()) {
|
|
77
|
+
settleRegistration(pool, false);
|
|
78
|
+
}
|
|
79
|
+
for (const [key, value] of [...pending.entries()]) {
|
|
80
|
+
if (removePending(key, value)) {
|
|
81
|
+
value.reject(error);
|
|
82
|
+
releaseIgnoringErrors(value.frame).catch(() => undefined);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const enqueueControlWrite = (data) => {
|
|
87
|
+
if (finishing || controlEnded) {
|
|
88
|
+
return Promise.reject(new Error('FFmpeg shared-memory input has already been finished.'));
|
|
89
|
+
}
|
|
90
|
+
const operation = controlWrites.then(async () => {
|
|
91
|
+
if (fatalError) {
|
|
92
|
+
throw fatalError;
|
|
93
|
+
}
|
|
94
|
+
await (0, write_with_backpressure_1.writeWithBackpressure)({
|
|
95
|
+
data: Buffer.from(data),
|
|
96
|
+
writable: control,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
controlWrites = operation;
|
|
100
|
+
return operation;
|
|
101
|
+
};
|
|
102
|
+
const unregisterPool = (pool) => {
|
|
103
|
+
pool.retired = true;
|
|
104
|
+
if (pool.unregistering) {
|
|
105
|
+
return pool.unregistering;
|
|
106
|
+
}
|
|
107
|
+
pool.unregistering = (async () => {
|
|
108
|
+
var _a;
|
|
109
|
+
try {
|
|
110
|
+
const wasRegistered = await pool.registration;
|
|
111
|
+
if (!wasRegistered || fatalError || finishing || controlEnded) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (pool.pendingCount > 0) {
|
|
115
|
+
await new Promise((resolve) => pool.drainWaiters.push(resolve));
|
|
116
|
+
}
|
|
117
|
+
if (fatalError || finishing || controlEnded) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
await enqueueControlWrite((0, exports.serializeRemotionSharedMemoryPoolRetirement)(pool.poolId));
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const normalizedError = toError(error);
|
|
125
|
+
fail(normalizedError);
|
|
126
|
+
throw normalizedError;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
(_a = pool.unsubscribe) === null || _a === void 0 ? void 0 : _a.call(pool);
|
|
131
|
+
pool.unsubscribe = null;
|
|
132
|
+
if (registeredPools.get(pool.poolId) === pool) {
|
|
133
|
+
registeredPools.delete(pool.poolId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
})();
|
|
137
|
+
return pool.unregistering;
|
|
138
|
+
};
|
|
139
|
+
const createRegisteredPool = (frame) => {
|
|
140
|
+
let resolveRegistration;
|
|
141
|
+
const registration = new Promise((resolve) => {
|
|
142
|
+
resolveRegistration = resolve;
|
|
143
|
+
});
|
|
144
|
+
const pool = {
|
|
145
|
+
poolId: frame.poolId,
|
|
146
|
+
sharedMemoryName: frame.sharedMemoryName,
|
|
147
|
+
poolLifetime: frame.poolLifetime,
|
|
148
|
+
registered: false,
|
|
149
|
+
registrationStarted: false,
|
|
150
|
+
registrationSettled: false,
|
|
151
|
+
registration,
|
|
152
|
+
resolveRegistration,
|
|
153
|
+
retired: false,
|
|
154
|
+
pendingCount: 0,
|
|
155
|
+
drainWaiters: [],
|
|
156
|
+
unregistering: null,
|
|
157
|
+
unsubscribe: null,
|
|
158
|
+
};
|
|
159
|
+
const unsubscribe = frame.poolLifetime.onRetired(() => unregisterPool(pool));
|
|
160
|
+
if (!unsubscribe) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
pool.unsubscribe = unsubscribe;
|
|
164
|
+
registeredPools.set(frame.poolId, pool);
|
|
165
|
+
return pool;
|
|
166
|
+
};
|
|
167
|
+
const lines = (0, node_readline_1.createInterface)({ input: acknowledgements });
|
|
168
|
+
lines.on('line', (line) => {
|
|
169
|
+
(async () => {
|
|
170
|
+
const ack = (0, exports.parseRemotionSharedMemoryAck)(line);
|
|
171
|
+
const key = pendingKey(ack.poolId, ack.slot);
|
|
172
|
+
const value = pending.get(key);
|
|
173
|
+
if (!value || value.acknowledged || value.frame.frameId !== ack.frameId) {
|
|
174
|
+
throw new Error(`Unexpected Remotion shared-memory ACK for ${ack.poolId}:${ack.slot}:${ack.frameId}.`);
|
|
175
|
+
}
|
|
176
|
+
// Keep the frame pending until Chromium releases its slot, but stop
|
|
177
|
+
// counting it as a missing ACK if FFmpeg exits during that release.
|
|
178
|
+
value.acknowledged = true;
|
|
179
|
+
try {
|
|
180
|
+
await value.frame.release();
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
const normalizedError = toError(error);
|
|
184
|
+
if (removePending(key, value)) {
|
|
185
|
+
value.reject(normalizedError);
|
|
186
|
+
fail(normalizedError);
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (removePending(key, value)) {
|
|
191
|
+
value.resolve();
|
|
192
|
+
}
|
|
193
|
+
})().catch((error) => fail(toError(error)));
|
|
194
|
+
});
|
|
195
|
+
lines.on('error', (error) => fail(toError(error)));
|
|
196
|
+
const onAcknowledgementsClosed = () => {
|
|
197
|
+
const unacknowledgedFrames = [...pending.values()].filter((frame) => !frame.acknowledged).length;
|
|
198
|
+
if (unacknowledgedFrames > 0 || !finishing) {
|
|
199
|
+
fail(new Error(`FFmpeg closed its Remotion shared-memory ACK pipe${unacknowledgedFrames > 0 ? ` with ${unacknowledgedFrames} frame(s) pending` : ' before input finished'}.`));
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
lines.on('close', onAcknowledgementsClosed);
|
|
203
|
+
acknowledgements.on('error', (error) => fail(toError(error)));
|
|
204
|
+
acknowledgements.on('close', onAcknowledgementsClosed);
|
|
205
|
+
control.on('error', (error) => fail(toError(error)));
|
|
206
|
+
return {
|
|
207
|
+
writeFrame: async ({ frame, pts, }) => {
|
|
208
|
+
if (fatalError) {
|
|
209
|
+
await releaseIgnoringErrors(frame);
|
|
210
|
+
throw fatalError;
|
|
211
|
+
}
|
|
212
|
+
if (finishing || controlEnded || frame.poolLifetime.isRetired()) {
|
|
213
|
+
await releaseIgnoringErrors(frame);
|
|
214
|
+
throw new Error(`Target closed: Remotion shared-memory pool ${frame.poolId} has already been retired.`);
|
|
215
|
+
}
|
|
216
|
+
let pool = registeredPools.get(frame.poolId);
|
|
217
|
+
if (!pool) {
|
|
218
|
+
const createdPool = createRegisteredPool(frame);
|
|
219
|
+
if (!createdPool) {
|
|
220
|
+
await releaseIgnoringErrors(frame);
|
|
221
|
+
throw new Error(`Target closed: Remotion shared-memory pool ${frame.poolId} has already been retired.`);
|
|
222
|
+
}
|
|
223
|
+
pool = createdPool;
|
|
224
|
+
}
|
|
225
|
+
else if (pool.sharedMemoryName !== frame.sharedMemoryName ||
|
|
226
|
+
pool.poolLifetime !== frame.poolLifetime) {
|
|
227
|
+
const error = new Error(`Remotion shared-memory pool ${frame.poolId} changed its identity.`);
|
|
228
|
+
await releaseIgnoringErrors(frame);
|
|
229
|
+
fail(error);
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
if (pool.retired || frame.poolLifetime.isRetired()) {
|
|
233
|
+
await releaseIgnoringErrors(frame);
|
|
234
|
+
throw new Error(`Target closed: Remotion shared-memory pool ${frame.poolId} has already been retired.`);
|
|
235
|
+
}
|
|
236
|
+
const key = pendingKey(frame.poolId, frame.slot);
|
|
237
|
+
if (pending.has(key)) {
|
|
238
|
+
const error = new Error(`Remotion shared-memory slot ${frame.poolId}:${frame.slot} was reused before its ACK.`);
|
|
239
|
+
await releaseIgnoringErrors(frame);
|
|
240
|
+
fail(error);
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
let resolveAck;
|
|
244
|
+
let rejectAck;
|
|
245
|
+
const ack = new Promise((resolve, reject) => {
|
|
246
|
+
resolveAck = resolve;
|
|
247
|
+
rejectAck = reject;
|
|
248
|
+
});
|
|
249
|
+
ack.catch(() => undefined);
|
|
250
|
+
const pendingFrame = {
|
|
251
|
+
frame,
|
|
252
|
+
pool,
|
|
253
|
+
acknowledged: false,
|
|
254
|
+
resolve: resolveAck,
|
|
255
|
+
reject: rejectAck,
|
|
256
|
+
};
|
|
257
|
+
pending.set(key, pendingFrame);
|
|
258
|
+
pool.pendingCount++;
|
|
259
|
+
const registersPool = !pool.registrationStarted;
|
|
260
|
+
if (registersPool) {
|
|
261
|
+
pool.registrationStarted = true;
|
|
262
|
+
}
|
|
263
|
+
const operation = enqueueControlWrite((registersPool ? (0, exports.serializeRemotionSharedMemoryPool)(frame) : '') +
|
|
264
|
+
(0, exports.serializeRemotionSharedMemoryFrame)({ frame, pts }));
|
|
265
|
+
if (registersPool) {
|
|
266
|
+
operation.then(() => settleRegistration(pool, true), () => settleRegistration(pool, false));
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
await operation;
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
const normalizedError = toError(error);
|
|
273
|
+
fail(normalizedError);
|
|
274
|
+
throw normalizedError;
|
|
275
|
+
}
|
|
276
|
+
return { waitForAck: ack };
|
|
277
|
+
},
|
|
278
|
+
finish: () => {
|
|
279
|
+
if (finishPromise) {
|
|
280
|
+
return finishPromise;
|
|
281
|
+
}
|
|
282
|
+
finishing = true;
|
|
283
|
+
finishPromise = (async () => {
|
|
284
|
+
try {
|
|
285
|
+
await controlWrites;
|
|
286
|
+
if (fatalError) {
|
|
287
|
+
throw fatalError;
|
|
288
|
+
}
|
|
289
|
+
await new Promise((resolve, reject) => {
|
|
290
|
+
control.end((error) => {
|
|
291
|
+
if (error) {
|
|
292
|
+
reject(error);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
resolve();
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
controlEnded = true;
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
const normalizedError = toError(error);
|
|
303
|
+
fail(normalizedError);
|
|
304
|
+
throw normalizedError;
|
|
305
|
+
}
|
|
306
|
+
})();
|
|
307
|
+
return finishPromise;
|
|
308
|
+
},
|
|
309
|
+
fail,
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
exports.createRemotionSharedMemoryFfmpegBridge = createRemotionSharedMemoryFfmpegBridge;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Page } from './browser/BrowserPage';
|
|
2
|
+
import type { RemotionRawFrame as CdpRemotionRawFrame, RemotionFramePoolBackend } from './browser/devtools-types';
|
|
3
|
+
import { type StillImageFormat } from './image-format';
|
|
4
|
+
import type { LogLevel } from './log-level';
|
|
5
|
+
import type { PixelFormat } from './pixel-format';
|
|
6
|
+
export declare const getPreferredRemotionSharedMemoryBackend: () => "auto" | RemotionFramePoolBackend;
|
|
7
|
+
export type RemotionSharedMemoryPoolLifetime = {
|
|
8
|
+
isRetired: () => boolean;
|
|
9
|
+
waitForRetirement: () => Promise<void>;
|
|
10
|
+
onRetired: (listener: () => Promise<void>) => (() => void) | null;
|
|
11
|
+
};
|
|
12
|
+
export type RemotionRawFrame = CdpRemotionRawFrame & {
|
|
13
|
+
type: 'remotion-shared-memory';
|
|
14
|
+
poolId: number;
|
|
15
|
+
sharedMemoryName: string;
|
|
16
|
+
backend: RemotionFramePoolBackend;
|
|
17
|
+
slotCount: number;
|
|
18
|
+
slotCapacity: number;
|
|
19
|
+
poolLifetime: RemotionSharedMemoryPoolLifetime;
|
|
20
|
+
release: () => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export type CapturedFrame = Buffer | RemotionRawFrame;
|
|
23
|
+
export declare class RemotionSharedMemoryCapture {
|
|
24
|
+
#private;
|
|
25
|
+
constructor(options: {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
indent: boolean;
|
|
29
|
+
logLevel: LogLevel;
|
|
30
|
+
backingDirectory: string | null;
|
|
31
|
+
});
|
|
32
|
+
isSupported(): boolean;
|
|
33
|
+
getImageFormat(imageFormat: StillImageFormat): StillImageFormat;
|
|
34
|
+
setPixelFormat(pixelFormat: PixelFormat): void;
|
|
35
|
+
initializePages(pages: Page[]): Promise<void>;
|
|
36
|
+
ensurePage(page: Page): Promise<void>;
|
|
37
|
+
acquire(page: Page): Promise<{
|
|
38
|
+
slot: number;
|
|
39
|
+
frameId: string;
|
|
40
|
+
fail: () => void;
|
|
41
|
+
discardPublished: () => Promise<void>;
|
|
42
|
+
publish: (metadata: CdpRemotionRawFrame) => Promise<RemotionRawFrame>;
|
|
43
|
+
} | null>;
|
|
44
|
+
destroy(): Promise<void>;
|
|
45
|
+
forgetPage(page: Page): Promise<void>;
|
|
46
|
+
forgetAllPages(): Promise<void>;
|
|
47
|
+
dispose(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
export declare const isRemotionRawFrame: (frame: CapturedFrame) => frame is RemotionRawFrame;
|