@remotion/renderer 4.0.533 → 4.0.534
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/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 +87 -4
- package/dist/client.js +2 -0
- package/dist/cycle-browser-tabs.js +9 -1
- package/dist/ensure-browser.js +30 -6
- package/dist/esm/client.mjs +937 -796
- package/dist/esm/index.mjs +4125 -3027
- package/dist/esm/pure.mjs +33 -9
- 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/image-format.d.ts +1 -0
- package/dist/image-format.js +8 -4
- package/dist/index.d.ts +11 -1
- 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 +8 -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.js +1 -1
- package/dist/options/api-key.js +1 -1
- package/dist/options/ask-ai.js +1 -1
- package/dist/options/audio-bitrate.js +1 -1
- package/dist/options/audio-codec.js +12 -6
- package/dist/options/beep-on-finish.js +1 -1
- package/dist/options/benchmark-concurrencies.js +1 -1
- package/dist/options/binaries-directory.js +1 -1
- package/dist/options/browser-executable.js +1 -1
- package/dist/options/browser.js +1 -1
- package/dist/options/bundle-cache.js +1 -1
- package/dist/options/canvas-tabs.js +1 -1
- package/dist/options/chrome-mode.js +1 -1
- package/dist/options/color-space.js +1 -1
- package/dist/options/concurrency.js +1 -1
- package/dist/options/config.js +1 -1
- package/dist/options/crf.js +1 -1
- package/dist/options/cross-site-isolation.js +1 -1
- package/dist/options/dark-mode.js +1 -1
- package/dist/options/default-coding-agent.js +1 -1
- package/dist/options/default-editor.js +1 -1
- package/dist/options/delete-after.js +1 -1
- package/dist/options/disable-git-source.js +1 -1
- package/dist/options/disable-shared-memory-capture.d.ts +16 -0
- package/dist/options/disable-shared-memory-capture.js +29 -0
- package/dist/options/disable-web-security.js +1 -1
- package/dist/options/disallow-parallel-encoding.js +1 -1
- package/dist/options/enable-cancellation.js +1 -1
- package/dist/options/enable-lambda-insights.js +1 -1
- package/dist/options/enable-multiprocess-on-linux.js +1 -1
- package/dist/options/encoding-buffer-size.js +1 -1
- package/dist/options/encoding-max-rate.js +1 -1
- package/dist/options/enforce-audio.js +1 -1
- package/dist/options/env-file.js +1 -1
- package/dist/options/every-nth-frame.js +1 -1
- package/dist/options/experimental-keep-audio-context-alive.js +1 -1
- package/dist/options/experimental-tracks.d.ts +18 -0
- package/dist/options/experimental-tracks.js +42 -0
- package/dist/options/folder-expiry.js +1 -1
- package/dist/options/for-seamless-aac-concatenation.js +1 -1
- package/dist/options/force-new-studio.js +1 -1
- package/dist/options/frames.js +1 -1
- package/dist/options/gl.js +1 -1
- package/dist/options/gop-size.js +1 -1
- package/dist/options/hardware-acceleration.js +1 -1
- package/dist/options/headless.js +1 -1
- package/dist/options/ignore-certificate-errors.js +1 -1
- package/dist/options/image-sequence-pattern.d.ts +1 -1
- package/dist/options/image-sequence-pattern.js +1 -1
- package/dist/options/image-sequence.js +1 -1
- package/dist/options/index.d.ts +36 -2
- package/dist/options/index.js +4 -0
- package/dist/options/interactivity.js +1 -1
- package/dist/options/ipv4.js +1 -1
- package/dist/options/is-production.js +1 -1
- package/dist/options/jpeg-quality.js +5 -2
- package/dist/options/keyboard-shortcuts.js +1 -1
- package/dist/options/latency-hint.js +1 -1
- package/dist/options/license-key.js +1 -1
- package/dist/options/log-level.js +1 -1
- package/dist/options/metadata.js +1 -1
- package/dist/options/mute.js +1 -1
- package/dist/options/no-open.js +1 -1
- package/dist/options/number-of-gif-loops.js +1 -1
- package/dist/options/number-of-shared-audio-tags.js +1 -1
- package/dist/options/offthreadvideo-cache-size.js +1 -1
- package/dist/options/offthreadvideo-threads.js +1 -1
- package/dist/options/on-browser-download.js +1 -1
- package/dist/options/options-map.d.ts +49 -1
- package/dist/options/options-map.js +4 -0
- package/dist/options/out-dir.js +1 -1
- package/dist/options/override-duration.js +1 -1
- package/dist/options/override-fps.js +1 -1
- package/dist/options/override-height.js +1 -1
- package/dist/options/override-width.js +1 -1
- package/dist/options/overwrite.js +1 -1
- package/dist/options/package-manager.js +1 -1
- package/dist/options/pixel-format.js +1 -1
- package/dist/options/port.js +1 -1
- package/dist/options/prefer-lossless.js +1 -1
- package/dist/options/preview-sample-rate.js +1 -1
- package/dist/options/props.js +1 -1
- package/dist/options/prores-profile.js +1 -1
- package/dist/options/public-dir.js +1 -1
- package/dist/options/public-license-key.js +1 -1
- package/dist/options/public-path.js +1 -1
- package/dist/options/repro.js +1 -1
- package/dist/options/rspack.d.ts +1 -1
- package/dist/options/rspack.js +1 -1
- package/dist/options/runs.js +1 -1
- package/dist/options/sample-rate.js +1 -1
- package/dist/options/scale.js +1 -1
- package/dist/options/separate-audio.js +1 -1
- package/dist/options/skip-skills.js +1 -1
- package/dist/options/still-frame.js +1 -1
- package/dist/options/still-image-format.js +1 -1
- package/dist/options/throw-if-site-exists.js +1 -1
- package/dist/options/timeout.js +1 -1
- package/dist/options/user-agent.js +1 -1
- package/dist/options/version-flag.js +1 -1
- package/dist/options/video-bitrate.js +1 -1
- package/dist/options/video-cache-size.js +1 -1
- package/dist/options/video-codec.js +4 -3
- package/dist/options/video-image-format.js +6 -2
- package/dist/options/webhook-custom-data.js +1 -1
- package/dist/options/webpack-poll.js +1 -1
- package/dist/options/x264-preset.js +1 -1
- package/dist/prespawn-ffmpeg.d.ts +20 -0
- package/dist/prespawn-ffmpeg.js +152 -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,359 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isRemotionRawFrame = exports.RemotionSharedMemoryCapture = exports.getPreferredRemotionSharedMemoryBackend = void 0;
|
|
4
|
+
const flaky_errors_1 = require("./browser/flaky-errors");
|
|
5
|
+
const image_format_1 = require("./image-format");
|
|
6
|
+
const logger_1 = require("./logger");
|
|
7
|
+
const screenshot_background_1 = require("./screenshot-background");
|
|
8
|
+
const encoderPadding = 64;
|
|
9
|
+
const slotsPerPage = 1;
|
|
10
|
+
// Escape hatch for testing a specific backend, for example the file backend on
|
|
11
|
+
// a host that also has POSIX shared memory. Unset means "auto".
|
|
12
|
+
const getPreferredRemotionSharedMemoryBackend = () => {
|
|
13
|
+
const value = process.env.REMOTION_SHARED_MEMORY_BACKEND;
|
|
14
|
+
if (value === 'posix-shm' || value === 'file') {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
return 'auto';
|
|
18
|
+
};
|
|
19
|
+
exports.getPreferredRemotionSharedMemoryBackend = getPreferredRemotionSharedMemoryBackend;
|
|
20
|
+
const isExpectedCapabilityError = (error) => {
|
|
21
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22
|
+
return (message.includes("'Page.remotionCreateFramePool' wasn't found") ||
|
|
23
|
+
message.includes('Method not found') ||
|
|
24
|
+
message.includes('Raw frames require') ||
|
|
25
|
+
message.includes('Raw frames are only supported') ||
|
|
26
|
+
message.includes('Could not create Remotion shared memory') ||
|
|
27
|
+
message.includes('Could not size Remotion shared memory') ||
|
|
28
|
+
message.includes('Could not map Remotion shared memory') ||
|
|
29
|
+
message.includes('Invalid Remotion frame pool dimensions'));
|
|
30
|
+
};
|
|
31
|
+
class RemotionSharedMemoryCapture {
|
|
32
|
+
#pools = new Map();
|
|
33
|
+
#nextPoolId = 1;
|
|
34
|
+
#nextFrameId = 1;
|
|
35
|
+
#supported = null;
|
|
36
|
+
#initialization = null;
|
|
37
|
+
#pixelFormat = null;
|
|
38
|
+
#options;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.#options = options;
|
|
41
|
+
}
|
|
42
|
+
isSupported() {
|
|
43
|
+
return this.#supported === true;
|
|
44
|
+
}
|
|
45
|
+
getImageFormat(imageFormat) {
|
|
46
|
+
if (!this.isSupported() || this.#pixelFormat === null) {
|
|
47
|
+
if (this.#pixelFormat !== null && imageFormat === 'jpeg') {
|
|
48
|
+
(0, image_format_1.validateSelectedPixelFormatAndImageFormatCombination)(this.#pixelFormat, imageFormat);
|
|
49
|
+
}
|
|
50
|
+
return imageFormat;
|
|
51
|
+
}
|
|
52
|
+
return this.#pixelFormat === 'yuva420p' ||
|
|
53
|
+
this.#pixelFormat === 'yuva444p10le'
|
|
54
|
+
? 'png'
|
|
55
|
+
: 'jpeg';
|
|
56
|
+
}
|
|
57
|
+
setPixelFormat(pixelFormat) {
|
|
58
|
+
this.#pixelFormat = pixelFormat;
|
|
59
|
+
}
|
|
60
|
+
async initializePages(pages) {
|
|
61
|
+
if (this.#initialization) {
|
|
62
|
+
await this.#initialization;
|
|
63
|
+
if (this.#supported) {
|
|
64
|
+
for (const page of pages) {
|
|
65
|
+
await this.ensurePage(page);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.#initialization = (async () => {
|
|
71
|
+
try {
|
|
72
|
+
for (const page of pages) {
|
|
73
|
+
await this.#createPool(page);
|
|
74
|
+
}
|
|
75
|
+
this.#supported = true;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
await this.#destroyPools();
|
|
79
|
+
if (!isExpectedCapabilityError(error)) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
this.#supported = false;
|
|
83
|
+
logger_1.Log.verbose({ indent: this.#options.indent, logLevel: this.#options.logLevel }, `Remotion shared-memory capture is unavailable. Falling back to encoded screenshots. Reason: ${error instanceof Error ? error.message : String(error)}`);
|
|
84
|
+
}
|
|
85
|
+
})();
|
|
86
|
+
await this.#initialization;
|
|
87
|
+
}
|
|
88
|
+
async ensurePage(page) {
|
|
89
|
+
if (this.#pools.has(page) || this.#supported === false) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (this.#supported === null) {
|
|
93
|
+
await this.initializePages([page]);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
await this.#createPool(page);
|
|
97
|
+
}
|
|
98
|
+
async acquire(page) {
|
|
99
|
+
if (!this.#supported) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const pool = this.#pools.get(page);
|
|
103
|
+
if (!pool) {
|
|
104
|
+
throw new Error('No Remotion shared-memory pool exists for this page.');
|
|
105
|
+
}
|
|
106
|
+
while (pool.availableSlots.length === 0) {
|
|
107
|
+
if (pool.forgotten) {
|
|
108
|
+
throw new Error('The page owning this shared-memory pool was closed.');
|
|
109
|
+
}
|
|
110
|
+
await new Promise((resolve) => pool.waiters.push(resolve));
|
|
111
|
+
}
|
|
112
|
+
const slot = pool.availableSlots.shift();
|
|
113
|
+
if (slot === undefined) {
|
|
114
|
+
throw new Error('Expected an available Remotion shared-memory slot.');
|
|
115
|
+
}
|
|
116
|
+
if (!Number.isSafeInteger(this.#nextFrameId)) {
|
|
117
|
+
throw new Error('Remotion shared-memory frame ID exceeded the safe range.');
|
|
118
|
+
}
|
|
119
|
+
const frameId = String(this.#nextFrameId++);
|
|
120
|
+
pool.ownedSlots.set(slot, frameId);
|
|
121
|
+
let published = false;
|
|
122
|
+
let releasePromise = null;
|
|
123
|
+
const releasePublished = () => {
|
|
124
|
+
releasePromise !== null && releasePromise !== void 0 ? releasePromise : (releasePromise = (async () => {
|
|
125
|
+
try {
|
|
126
|
+
await page._client().send('Page.remotionReleaseFrame', {
|
|
127
|
+
slot,
|
|
128
|
+
frameId,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (!(0, flaky_errors_1.isTargetClosedErr)(error)) {
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
this.#returnSlot(pool, slot, frameId);
|
|
138
|
+
}
|
|
139
|
+
})());
|
|
140
|
+
return releasePromise;
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
slot,
|
|
144
|
+
frameId,
|
|
145
|
+
fail: () => {
|
|
146
|
+
if (!published) {
|
|
147
|
+
this.#returnSlot(pool, slot, frameId);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
discardPublished: async () => {
|
|
151
|
+
published = true;
|
|
152
|
+
await releasePublished();
|
|
153
|
+
},
|
|
154
|
+
publish: async (metadata) => {
|
|
155
|
+
published = true;
|
|
156
|
+
if (metadata.slot !== slot ||
|
|
157
|
+
metadata.frameId !== frameId ||
|
|
158
|
+
metadata.width !== this.#options.width ||
|
|
159
|
+
metadata.height !== this.#options.height ||
|
|
160
|
+
metadata.stride < metadata.width * 4 ||
|
|
161
|
+
metadata.byteLength > pool.slotCapacity - encoderPadding ||
|
|
162
|
+
metadata.pixelFormat !== 'bgra' ||
|
|
163
|
+
metadata.colorSpace !== 'srgb') {
|
|
164
|
+
await releasePublished();
|
|
165
|
+
throw new Error(`Chromium returned invalid Remotion shared-memory metadata: ${JSON.stringify(metadata)}`);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
...metadata,
|
|
169
|
+
type: 'remotion-shared-memory',
|
|
170
|
+
poolId: pool.poolId,
|
|
171
|
+
sharedMemoryName: pool.sharedMemoryName,
|
|
172
|
+
backend: pool.backend,
|
|
173
|
+
slotCount: pool.slotCount,
|
|
174
|
+
slotCapacity: pool.slotCapacity,
|
|
175
|
+
poolLifetime: pool.poolLifetime,
|
|
176
|
+
release: releasePublished,
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
async destroy() {
|
|
182
|
+
await this.#destroyPools();
|
|
183
|
+
}
|
|
184
|
+
async forgetPage(page) {
|
|
185
|
+
await this.#forgetPage(page, false);
|
|
186
|
+
}
|
|
187
|
+
async forgetAllPages() {
|
|
188
|
+
await Promise.all([...this.#pools.keys()].map((page) => this.#forgetPage(page, false)));
|
|
189
|
+
}
|
|
190
|
+
async dispose() {
|
|
191
|
+
await Promise.all([...this.#pools.keys()].map((page) => this.#forgetPage(page, true)));
|
|
192
|
+
this.#supported = false;
|
|
193
|
+
}
|
|
194
|
+
async #forgetPage(page, bestEffort) {
|
|
195
|
+
const pool = this.#pools.get(page);
|
|
196
|
+
if (!pool) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
this.#pools.delete(page);
|
|
200
|
+
pool.forgotten = true;
|
|
201
|
+
pool.waiters.splice(0).forEach((waiter) => waiter());
|
|
202
|
+
let cleanupError = null;
|
|
203
|
+
try {
|
|
204
|
+
await pool.poolLifetime.retire();
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
cleanupError = error;
|
|
208
|
+
}
|
|
209
|
+
if (pool.ownedSlots.size > 0) {
|
|
210
|
+
await new Promise((resolve) => pool.drainWaiters.push(resolve));
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
await (0, screenshot_background_1.setScreenshotBackground)(page, false);
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (!bestEffort && !(0, flaky_errors_1.isTargetClosedErr)(error) && !cleanupError) {
|
|
217
|
+
cleanupError = error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
await page._client().send('Page.remotionDestroyFramePool');
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (!bestEffort && !(0, flaky_errors_1.isTargetClosedErr)(error) && !cleanupError) {
|
|
225
|
+
cleanupError = error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (cleanupError && !bestEffort) {
|
|
229
|
+
throw cleanupError;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async #createPool(page) {
|
|
233
|
+
var _a;
|
|
234
|
+
if (this.#pools.has(page)) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const slotCapacity = this.#options.width * this.#options.height * 4 + encoderPadding;
|
|
238
|
+
if (!Number.isSafeInteger(slotCapacity)) {
|
|
239
|
+
throw new Error('Remotion shared-memory frame pool size is not a safe integer.');
|
|
240
|
+
}
|
|
241
|
+
const preferredBackend = (0, exports.getPreferredRemotionSharedMemoryBackend)();
|
|
242
|
+
const { backingDirectory } = this.#options;
|
|
243
|
+
if (preferredBackend === 'file' && backingDirectory === null) {
|
|
244
|
+
throw new Error('REMOTION_SHARED_MEMORY_BACKEND=file requires an FFmpeg binary that supports file-backed pools (-pool_dir).');
|
|
245
|
+
}
|
|
246
|
+
const { value } = await page._client().send('Page.remotionCreateFramePool', {
|
|
247
|
+
slotCount: slotsPerPage,
|
|
248
|
+
slotCapacity,
|
|
249
|
+
...(backingDirectory === null ? {} : { backingDirectory }),
|
|
250
|
+
...(preferredBackend === 'auto' ? {} : { preferredBackend }),
|
|
251
|
+
});
|
|
252
|
+
// Chromium builds before v3 of the patch only know POSIX shared memory and
|
|
253
|
+
// omit the backend field.
|
|
254
|
+
const backend = (_a = value.backend) !== null && _a !== void 0 ? _a : 'posix-shm';
|
|
255
|
+
if (!value.sharedMemoryName ||
|
|
256
|
+
value.slotCount !== slotsPerPage ||
|
|
257
|
+
value.slotCapacity !== slotCapacity ||
|
|
258
|
+
(backend !== 'posix-shm' && backend !== 'file') ||
|
|
259
|
+
(backend === 'posix-shm' &&
|
|
260
|
+
!/^\/rmshm-[A-Za-z0-9._-]+$/.test(value.sharedMemoryName)) ||
|
|
261
|
+
(backend === 'file' &&
|
|
262
|
+
(backingDirectory === null ||
|
|
263
|
+
!value.sharedMemoryName.startsWith(`${backingDirectory}/rmshm-`)))) {
|
|
264
|
+
throw new Error(`Chromium returned invalid Remotion frame pool metadata: ${JSON.stringify(value)}`);
|
|
265
|
+
}
|
|
266
|
+
if (this.#pools.size === 0) {
|
|
267
|
+
logger_1.Log.verbose({ indent: this.#options.indent, logLevel: this.#options.logLevel }, `Remotion shared-memory capture uses the ${backend === 'file' ? `file backend in ${backingDirectory}` : 'POSIX shared-memory backend'}.`);
|
|
268
|
+
}
|
|
269
|
+
let retired = false;
|
|
270
|
+
let retirement = null;
|
|
271
|
+
let notifyRetirement;
|
|
272
|
+
const retirementSignal = new Promise((resolve) => {
|
|
273
|
+
notifyRetirement = resolve;
|
|
274
|
+
});
|
|
275
|
+
const retirementListeners = new Set();
|
|
276
|
+
const poolLifetime = {
|
|
277
|
+
isRetired: () => retired,
|
|
278
|
+
waitForRetirement: () => retirementSignal,
|
|
279
|
+
onRetired: (listener) => {
|
|
280
|
+
if (retired) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
retirementListeners.add(listener);
|
|
284
|
+
return () => retirementListeners.delete(listener);
|
|
285
|
+
},
|
|
286
|
+
retire: () => {
|
|
287
|
+
if (!retirement) {
|
|
288
|
+
retired = true;
|
|
289
|
+
notifyRetirement();
|
|
290
|
+
retirement = (async () => {
|
|
291
|
+
await Promise.all([...retirementListeners].map((listener) => listener()));
|
|
292
|
+
})();
|
|
293
|
+
}
|
|
294
|
+
return retirement;
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
this.#pools.set(page, {
|
|
298
|
+
page,
|
|
299
|
+
poolId: this.#nextPoolId++,
|
|
300
|
+
sharedMemoryName: value.sharedMemoryName,
|
|
301
|
+
backend,
|
|
302
|
+
slotCount: value.slotCount,
|
|
303
|
+
slotCapacity: value.slotCapacity,
|
|
304
|
+
availableSlots: Array.from({ length: value.slotCount }, (_, index) => index),
|
|
305
|
+
waiters: [],
|
|
306
|
+
drainWaiters: [],
|
|
307
|
+
ownedSlots: new Map(),
|
|
308
|
+
forgotten: false,
|
|
309
|
+
poolLifetime,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
#returnSlot(pool, slot, frameId) {
|
|
313
|
+
var _a;
|
|
314
|
+
if (pool.ownedSlots.get(slot) !== frameId) {
|
|
315
|
+
throw new Error(`Remotion shared-memory slot ${pool.poolId}:${slot} is not owned by frame ${frameId}.`);
|
|
316
|
+
}
|
|
317
|
+
pool.ownedSlots.delete(slot);
|
|
318
|
+
if (pool.forgotten) {
|
|
319
|
+
if (pool.ownedSlots.size === 0) {
|
|
320
|
+
pool.drainWaiters.splice(0).forEach((waiter) => waiter());
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
pool.availableSlots.push(slot);
|
|
325
|
+
(_a = pool.waiters.shift()) === null || _a === void 0 ? void 0 : _a();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async #destroyPools() {
|
|
329
|
+
let cleanupError = null;
|
|
330
|
+
for (const pool of this.#pools.values()) {
|
|
331
|
+
if (pool.ownedSlots.size > 0) {
|
|
332
|
+
throw new Error(`Cannot destroy Remotion shared-memory pool ${pool.poolId} while it owns ${pool.ownedSlots.size} frame(s).`);
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
await (0, screenshot_background_1.setScreenshotBackground)(pool.page, false);
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
if (!(0, flaky_errors_1.isTargetClosedErr)(error) && !cleanupError) {
|
|
339
|
+
cleanupError = error;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
try {
|
|
343
|
+
await pool.page._client().send('Page.remotionDestroyFramePool');
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
if (!(0, flaky_errors_1.isTargetClosedErr)(error) && !cleanupError) {
|
|
347
|
+
cleanupError = error;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
this.#pools.clear();
|
|
352
|
+
if (cleanupError) {
|
|
353
|
+
throw cleanupError;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
exports.RemotionSharedMemoryCapture = RemotionSharedMemoryCapture;
|
|
358
|
+
const isRemotionRawFrame = (frame) => !Buffer.isBuffer(frame);
|
|
359
|
+
exports.isRemotionRawFrame = isRemotionRawFrame;
|
|
@@ -6,9 +6,10 @@ import type { Page } from './browser/BrowserPage';
|
|
|
6
6
|
import type { CountType } from './get-frame-padded-index';
|
|
7
7
|
import type { CancelSignal } from './make-cancel-signal';
|
|
8
8
|
import type { Pool } from './pool';
|
|
9
|
+
import type { CapturedFrame, RemotionSharedMemoryCapture } from './remotion-shared-memory';
|
|
9
10
|
import type { AssetIndex, FrameAndAssets, OnArtifact } from './render-frames';
|
|
10
11
|
import type { BrowserReplacer } from './replace-browser';
|
|
11
|
-
export declare const renderFrameAndRetryTargetClose: ({ retriesLeft, attempt, assets, assetIndex, imageFormat, binariesDirectory, cancelSignal, composition, countType, downloadMap, frameDir, framesToRender, jpegQuality, onArtifact, onDownload, onError, outputDir, poolPromise, scale, stoppedSignal, timeoutInMilliseconds, indent, logLevel, makeBrowser, makeNewPage, browserReplacer, concurrencyOrFramesToRender, framesRenderedObj, lastFrame, onFrameBuffer, onFrameUpdate, nextFrameToRender, imageSequencePattern, trimLeftOffset, trimRightOffset, allFramesAndExtraFrames, }: {
|
|
12
|
+
export declare const renderFrameAndRetryTargetClose: ({ retriesLeft, attempt, assets, assetIndex, imageFormat, binariesDirectory, cancelSignal, composition, countType, downloadMap, frameDir, framesToRender, jpegQuality, onArtifact, onDownload, onError, outputDir, poolPromise, scale, stoppedSignal, timeoutInMilliseconds, indent, logLevel, makeBrowser, makeNewPage, browserReplacer, concurrencyOrFramesToRender, framesRenderedObj, lastFrame, onFrameBuffer, onFrame, remotionSharedMemory, onFrameUpdate, nextFrameToRender, imageSequencePattern, trimLeftOffset, trimRightOffset, allFramesAndExtraFrames, }: {
|
|
12
13
|
retriesLeft: number;
|
|
13
14
|
attempt: number;
|
|
14
15
|
imageFormat: "jpeg" | "none" | "png";
|
|
@@ -43,9 +44,11 @@ export declare const renderFrameAndRetryTargetClose: ({ retriesLeft, attempt, as
|
|
|
43
44
|
count: number;
|
|
44
45
|
};
|
|
45
46
|
onFrameBuffer: ((buffer: Buffer, frame: number) => void | Promise<void>) | null | undefined;
|
|
47
|
+
onFrame: ((frame: CapturedFrame, frameNumber: number) => void | Promise<void>) | null;
|
|
48
|
+
remotionSharedMemory: RemotionSharedMemoryCapture | null;
|
|
46
49
|
onFrameUpdate: ((framesRendered: number, frameIndex: number, timeToRenderInMilliseconds: number) => void) | null;
|
|
47
50
|
nextFrameToRender: {
|
|
48
|
-
getNextFrame: (
|
|
51
|
+
getNextFrame: () => number;
|
|
49
52
|
returnFrame: (frame: number) => void;
|
|
50
53
|
};
|
|
51
54
|
imageSequencePattern: string | null;
|
|
@@ -7,14 +7,14 @@ const is_delay_render_error_with_retry_1 = require("./is-delay-render-error-with
|
|
|
7
7
|
const logger_1 = require("./logger");
|
|
8
8
|
const make_cancel_signal_1 = require("./make-cancel-signal");
|
|
9
9
|
const render_frame_1 = require("./render-frame");
|
|
10
|
-
const renderFrameAndRetryTargetClose = async ({ retriesLeft, attempt, assets, assetIndex, imageFormat, binariesDirectory, cancelSignal, composition, countType, downloadMap, frameDir, framesToRender, jpegQuality, onArtifact, onDownload, onError, outputDir, poolPromise, scale, stoppedSignal, timeoutInMilliseconds, indent, logLevel, makeBrowser, makeNewPage, browserReplacer, concurrencyOrFramesToRender, framesRenderedObj, lastFrame, onFrameBuffer, onFrameUpdate, nextFrameToRender, imageSequencePattern, trimLeftOffset, trimRightOffset, allFramesAndExtraFrames, }) => {
|
|
10
|
+
const renderFrameAndRetryTargetClose = async ({ retriesLeft, attempt, assets, assetIndex, imageFormat, binariesDirectory, cancelSignal, composition, countType, downloadMap, frameDir, framesToRender, jpegQuality, onArtifact, onDownload, onError, outputDir, poolPromise, scale, stoppedSignal, timeoutInMilliseconds, indent, logLevel, makeBrowser, makeNewPage, browserReplacer, concurrencyOrFramesToRender, framesRenderedObj, lastFrame, onFrameBuffer, onFrame, remotionSharedMemory, onFrameUpdate, nextFrameToRender, imageSequencePattern, trimLeftOffset, trimRightOffset, allFramesAndExtraFrames, }) => {
|
|
11
11
|
var _a;
|
|
12
12
|
const currentPool = await poolPromise;
|
|
13
13
|
if (stoppedSignal.stopped) {
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
const freePage = await currentPool.acquire();
|
|
17
|
-
const frame = nextFrameToRender.getNextFrame(
|
|
17
|
+
const frame = nextFrameToRender.getNextFrame();
|
|
18
18
|
try {
|
|
19
19
|
await Promise.race([
|
|
20
20
|
(0, render_frame_1.renderFrame)({
|
|
@@ -42,11 +42,12 @@ const renderFrameAndRetryTargetClose = async ({ retriesLeft, attempt, assets, as
|
|
|
42
42
|
lastFrame,
|
|
43
43
|
onError,
|
|
44
44
|
onFrameBuffer,
|
|
45
|
+
onFrame,
|
|
46
|
+
remotionSharedMemory,
|
|
45
47
|
onFrameUpdate,
|
|
46
48
|
outputDir,
|
|
47
49
|
stoppedSignal,
|
|
48
50
|
timeoutInMilliseconds,
|
|
49
|
-
nextFrameToRender,
|
|
50
51
|
frame,
|
|
51
52
|
page: freePage,
|
|
52
53
|
imageSequencePattern,
|
|
@@ -81,7 +82,17 @@ const renderFrameAndRetryTargetClose = async ({ retriesLeft, attempt, assets, as
|
|
|
81
82
|
}
|
|
82
83
|
if (shouldRetryError) {
|
|
83
84
|
const pool = await poolPromise;
|
|
84
|
-
//
|
|
85
|
+
// Retire shared-memory pools before closing the timed-out page.
|
|
86
|
+
await (remotionSharedMemory === null || remotionSharedMemory === void 0 ? void 0 : remotionSharedMemory.forgetPage(freePage));
|
|
87
|
+
// Close the timed-out page before creating another main tab at index 0.
|
|
88
|
+
try {
|
|
89
|
+
await freePage.close();
|
|
90
|
+
}
|
|
91
|
+
catch (closeError) {
|
|
92
|
+
if (!(closeError instanceof Error) || !(0, flaky_errors_1.isTargetClosedErr)(closeError)) {
|
|
93
|
+
throw closeError;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
85
96
|
const newPage = await makeNewPage(frame, freePage.pageIndex);
|
|
86
97
|
pool.release(newPage);
|
|
87
98
|
logger_1.Log.warn({ indent, logLevel }, `delayRender() timed out while rendering frame ${frame}: ${err.message}`);
|
|
@@ -118,6 +129,8 @@ const renderFrameAndRetryTargetClose = async ({ retriesLeft, attempt, assets, as
|
|
|
118
129
|
framesRenderedObj,
|
|
119
130
|
lastFrame,
|
|
120
131
|
onFrameBuffer,
|
|
132
|
+
onFrame,
|
|
133
|
+
remotionSharedMemory,
|
|
121
134
|
onFrameUpdate,
|
|
122
135
|
nextFrameToRender,
|
|
123
136
|
imageSequencePattern,
|
|
@@ -128,6 +141,7 @@ const renderFrameAndRetryTargetClose = async ({ retriesLeft, attempt, assets, as
|
|
|
128
141
|
}
|
|
129
142
|
logger_1.Log.warn({ indent, logLevel }, `The browser crashed while rendering frame ${frame}, retrying ${retriesLeft} more times. Learn more about this error under https://www.remotion.dev/docs/target-closed`);
|
|
130
143
|
// Replace the entire browser
|
|
144
|
+
await (remotionSharedMemory === null || remotionSharedMemory === void 0 ? void 0 : remotionSharedMemory.forgetAllPages());
|
|
131
145
|
await browserReplacer.replaceBrowser(makeBrowser, async () => {
|
|
132
146
|
const pages = new Array(concurrencyOrFramesToRender)
|
|
133
147
|
.fill(true)
|
|
@@ -170,6 +184,8 @@ const renderFrameAndRetryTargetClose = async ({ retriesLeft, attempt, assets, as
|
|
|
170
184
|
framesRenderedObj,
|
|
171
185
|
lastFrame,
|
|
172
186
|
onFrameBuffer,
|
|
187
|
+
onFrame,
|
|
188
|
+
remotionSharedMemory,
|
|
173
189
|
onFrameUpdate,
|
|
174
190
|
nextFrameToRender,
|
|
175
191
|
imageSequencePattern,
|
|
@@ -3,8 +3,9 @@ import type { DownloadMap } from './assets/download-map';
|
|
|
3
3
|
import type { Page } from './browser/BrowserPage';
|
|
4
4
|
import type { CountType } from './get-frame-padded-index';
|
|
5
5
|
import type { CancelSignal } from './make-cancel-signal';
|
|
6
|
+
import type { CapturedFrame, RemotionSharedMemoryCapture } from './remotion-shared-memory';
|
|
6
7
|
import type { AssetIndex, FrameAndAssets, OnArtifact } from './render-frames';
|
|
7
|
-
export declare const renderFrameWithOptionToReject: ({ reject, width, height, compId, attempt, stoppedSignal, indent, logLevel, timeoutInMilliseconds, outputDir, onFrameBuffer, imageFormat, onError, lastFrame, jpegQuality, frameDir, scale, countType, assets, assetIndex, framesToRender, onArtifact, onDownload, downloadMap, binariesDirectory, cancelSignal, framesRenderedObj, onFrameUpdate, frame, page, imageSequencePattern, fps, trimLeftOffset, trimRightOffset, allFramesAndExtraFrames, }: {
|
|
8
|
+
export declare const renderFrameWithOptionToReject: ({ reject, width, height, compId, attempt, stoppedSignal, indent, logLevel, timeoutInMilliseconds, outputDir, onFrameBuffer, onFrame, remotionSharedMemory, imageFormat, onError, lastFrame, jpegQuality, frameDir, scale, countType, assets, assetIndex, framesToRender, onArtifact, onDownload, downloadMap, binariesDirectory, cancelSignal, framesRenderedObj, onFrameUpdate, frame, page, imageSequencePattern, fps, trimLeftOffset, trimRightOffset, allFramesAndExtraFrames, }: {
|
|
8
9
|
reject: (err: Error) => void;
|
|
9
10
|
width: number;
|
|
10
11
|
height: number;
|
|
@@ -18,6 +19,8 @@ export declare const renderFrameWithOptionToReject: ({ reject, width, height, co
|
|
|
18
19
|
logLevel: "error" | "info" | "trace" | "verbose" | "warn";
|
|
19
20
|
outputDir: string | null;
|
|
20
21
|
onFrameBuffer: ((buffer: Buffer, frame: number) => void | Promise<void>) | null | undefined;
|
|
22
|
+
onFrame: ((frame: CapturedFrame, frameNumber: number) => void | Promise<void>) | null;
|
|
23
|
+
remotionSharedMemory: RemotionSharedMemoryCapture | null;
|
|
21
24
|
imageFormat: "jpeg" | "none" | "png";
|
|
22
25
|
onError: (err: Error) => void;
|
|
23
26
|
lastFrame: number;
|