@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.
Files changed (174) hide show
  1. package/dist/aac-priming.js +6 -2
  2. package/dist/browser/BrowserFetcher.d.ts +7 -1
  3. package/dist/browser/BrowserFetcher.js +33 -13
  4. package/dist/browser/Connection.js +5 -17
  5. package/dist/browser/DOMWorld.js +19 -13
  6. package/dist/browser/devtools-commands.d.ts +13 -1
  7. package/dist/browser/devtools-types.d.ts +62 -0
  8. package/dist/browser/get-chrome-download-url.d.ts +1 -1
  9. package/dist/browser/get-chrome-download-url.js +19 -33
  10. package/dist/can-use-parallel-encoding.d.ts +0 -1
  11. package/dist/can-use-parallel-encoding.js +10 -10
  12. package/dist/client.d.ts +87 -4
  13. package/dist/client.js +2 -0
  14. package/dist/cycle-browser-tabs.js +9 -1
  15. package/dist/ensure-browser.js +30 -6
  16. package/dist/esm/client.mjs +937 -796
  17. package/dist/esm/index.mjs +4125 -3027
  18. package/dist/esm/pure.mjs +33 -9
  19. package/dist/file-extensions.js +4 -1
  20. package/dist/get-mp4-brand.d.ts +1 -0
  21. package/dist/get-mp4-brand.js +21 -0
  22. package/dist/image-format.d.ts +1 -0
  23. package/dist/image-format.js +8 -4
  24. package/dist/index.d.ts +11 -1
  25. package/dist/index.js +4 -0
  26. package/dist/memory/from-macos-sysctl.d.ts +1 -0
  27. package/dist/memory/from-macos-sysctl.js +50 -0
  28. package/dist/memory/from-proc-meminfo.d.ts +1 -1
  29. package/dist/memory/from-proc-meminfo.js +7 -4
  30. package/dist/memory/get-available-memory.js +29 -21
  31. package/dist/mux-video-and-audio.js +8 -2
  32. package/dist/next-frame-to-render.d.ts +3 -7
  33. package/dist/next-frame-to-render.js +3 -22
  34. package/dist/open-browser.js +1 -0
  35. package/dist/options/allow-html-in-canvas.js +1 -1
  36. package/dist/options/api-key.js +1 -1
  37. package/dist/options/ask-ai.js +1 -1
  38. package/dist/options/audio-bitrate.js +1 -1
  39. package/dist/options/audio-codec.js +12 -6
  40. package/dist/options/beep-on-finish.js +1 -1
  41. package/dist/options/benchmark-concurrencies.js +1 -1
  42. package/dist/options/binaries-directory.js +1 -1
  43. package/dist/options/browser-executable.js +1 -1
  44. package/dist/options/browser.js +1 -1
  45. package/dist/options/bundle-cache.js +1 -1
  46. package/dist/options/canvas-tabs.js +1 -1
  47. package/dist/options/chrome-mode.js +1 -1
  48. package/dist/options/color-space.js +1 -1
  49. package/dist/options/concurrency.js +1 -1
  50. package/dist/options/config.js +1 -1
  51. package/dist/options/crf.js +1 -1
  52. package/dist/options/cross-site-isolation.js +1 -1
  53. package/dist/options/dark-mode.js +1 -1
  54. package/dist/options/default-coding-agent.js +1 -1
  55. package/dist/options/default-editor.js +1 -1
  56. package/dist/options/delete-after.js +1 -1
  57. package/dist/options/disable-git-source.js +1 -1
  58. package/dist/options/disable-shared-memory-capture.d.ts +16 -0
  59. package/dist/options/disable-shared-memory-capture.js +29 -0
  60. package/dist/options/disable-web-security.js +1 -1
  61. package/dist/options/disallow-parallel-encoding.js +1 -1
  62. package/dist/options/enable-cancellation.js +1 -1
  63. package/dist/options/enable-lambda-insights.js +1 -1
  64. package/dist/options/enable-multiprocess-on-linux.js +1 -1
  65. package/dist/options/encoding-buffer-size.js +1 -1
  66. package/dist/options/encoding-max-rate.js +1 -1
  67. package/dist/options/enforce-audio.js +1 -1
  68. package/dist/options/env-file.js +1 -1
  69. package/dist/options/every-nth-frame.js +1 -1
  70. package/dist/options/experimental-keep-audio-context-alive.js +1 -1
  71. package/dist/options/experimental-tracks.d.ts +18 -0
  72. package/dist/options/experimental-tracks.js +42 -0
  73. package/dist/options/folder-expiry.js +1 -1
  74. package/dist/options/for-seamless-aac-concatenation.js +1 -1
  75. package/dist/options/force-new-studio.js +1 -1
  76. package/dist/options/frames.js +1 -1
  77. package/dist/options/gl.js +1 -1
  78. package/dist/options/gop-size.js +1 -1
  79. package/dist/options/hardware-acceleration.js +1 -1
  80. package/dist/options/headless.js +1 -1
  81. package/dist/options/ignore-certificate-errors.js +1 -1
  82. package/dist/options/image-sequence-pattern.d.ts +1 -1
  83. package/dist/options/image-sequence-pattern.js +1 -1
  84. package/dist/options/image-sequence.js +1 -1
  85. package/dist/options/index.d.ts +36 -2
  86. package/dist/options/index.js +4 -0
  87. package/dist/options/interactivity.js +1 -1
  88. package/dist/options/ipv4.js +1 -1
  89. package/dist/options/is-production.js +1 -1
  90. package/dist/options/jpeg-quality.js +5 -2
  91. package/dist/options/keyboard-shortcuts.js +1 -1
  92. package/dist/options/latency-hint.js +1 -1
  93. package/dist/options/license-key.js +1 -1
  94. package/dist/options/log-level.js +1 -1
  95. package/dist/options/metadata.js +1 -1
  96. package/dist/options/mute.js +1 -1
  97. package/dist/options/no-open.js +1 -1
  98. package/dist/options/number-of-gif-loops.js +1 -1
  99. package/dist/options/number-of-shared-audio-tags.js +1 -1
  100. package/dist/options/offthreadvideo-cache-size.js +1 -1
  101. package/dist/options/offthreadvideo-threads.js +1 -1
  102. package/dist/options/on-browser-download.js +1 -1
  103. package/dist/options/options-map.d.ts +49 -1
  104. package/dist/options/options-map.js +4 -0
  105. package/dist/options/out-dir.js +1 -1
  106. package/dist/options/override-duration.js +1 -1
  107. package/dist/options/override-fps.js +1 -1
  108. package/dist/options/override-height.js +1 -1
  109. package/dist/options/override-width.js +1 -1
  110. package/dist/options/overwrite.js +1 -1
  111. package/dist/options/package-manager.js +1 -1
  112. package/dist/options/pixel-format.js +1 -1
  113. package/dist/options/port.js +1 -1
  114. package/dist/options/prefer-lossless.js +1 -1
  115. package/dist/options/preview-sample-rate.js +1 -1
  116. package/dist/options/props.js +1 -1
  117. package/dist/options/prores-profile.js +1 -1
  118. package/dist/options/public-dir.js +1 -1
  119. package/dist/options/public-license-key.js +1 -1
  120. package/dist/options/public-path.js +1 -1
  121. package/dist/options/repro.js +1 -1
  122. package/dist/options/rspack.d.ts +1 -1
  123. package/dist/options/rspack.js +1 -1
  124. package/dist/options/runs.js +1 -1
  125. package/dist/options/sample-rate.js +1 -1
  126. package/dist/options/scale.js +1 -1
  127. package/dist/options/separate-audio.js +1 -1
  128. package/dist/options/skip-skills.js +1 -1
  129. package/dist/options/still-frame.js +1 -1
  130. package/dist/options/still-image-format.js +1 -1
  131. package/dist/options/throw-if-site-exists.js +1 -1
  132. package/dist/options/timeout.js +1 -1
  133. package/dist/options/user-agent.js +1 -1
  134. package/dist/options/version-flag.js +1 -1
  135. package/dist/options/video-bitrate.js +1 -1
  136. package/dist/options/video-cache-size.js +1 -1
  137. package/dist/options/video-codec.js +4 -3
  138. package/dist/options/video-image-format.js +6 -2
  139. package/dist/options/webhook-custom-data.js +1 -1
  140. package/dist/options/webpack-poll.js +1 -1
  141. package/dist/options/x264-preset.js +1 -1
  142. package/dist/prespawn-ffmpeg.d.ts +20 -0
  143. package/dist/prespawn-ffmpeg.js +152 -29
  144. package/dist/probe-shared-memory-capture.d.ts +8 -0
  145. package/dist/probe-shared-memory-capture.js +111 -0
  146. package/dist/puppeteer-screenshot.d.ts +3 -1
  147. package/dist/puppeteer-screenshot.js +1 -0
  148. package/dist/pure.d.ts +1 -1
  149. package/dist/remotion-shared-memory-ffmpeg.d.ts +26 -0
  150. package/dist/remotion-shared-memory-ffmpeg.js +312 -0
  151. package/dist/remotion-shared-memory.d.ts +49 -0
  152. package/dist/remotion-shared-memory.js +359 -0
  153. package/dist/render-frame-and-retry-target-close.d.ts +5 -2
  154. package/dist/render-frame-and-retry-target-close.js +20 -4
  155. package/dist/render-frame-with-option-to-reject.d.ts +4 -1
  156. package/dist/render-frame-with-option-to-reject.js +206 -115
  157. package/dist/render-frame.d.ts +4 -5
  158. package/dist/render-frame.js +3 -1
  159. package/dist/render-frames.d.ts +3 -0
  160. package/dist/render-frames.js +15 -18
  161. package/dist/render-media.d.ts +1 -1
  162. package/dist/render-media.js +131 -46
  163. package/dist/render-still.js +1 -0
  164. package/dist/screenshot-background.d.ts +2 -0
  165. package/dist/screenshot-background.js +20 -0
  166. package/dist/screenshot-task.d.ts +4 -2
  167. package/dist/screenshot-task.js +40 -21
  168. package/dist/seek-to-frame.js +1 -1
  169. package/dist/stitch-frames-to-video.js +71 -10
  170. package/dist/take-frame.d.ts +11 -3
  171. package/dist/take-frame.js +10 -8
  172. package/dist/validate-output-filename.d.ts +1 -1
  173. package/dist/validate-output-filename.js +10 -2
  174. 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: (_pageIndex: number) => number;
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(freePage.pageIndex);
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
- // Replace the closed page
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;