@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
@@ -39,8 +39,8 @@ const perf_1 = require("./perf");
39
39
  const pixel_format_1 = require("./pixel-format");
40
40
  const prepare_server_1 = require("./prepare-server");
41
41
  const prespawn_ffmpeg_1 = require("./prespawn-ffmpeg");
42
- const prestitcher_memory_usage_1 = require("./prestitcher-memory-usage");
43
42
  const prores_profile_1 = require("./prores-profile");
43
+ const remotion_shared_memory_1 = require("./remotion-shared-memory");
44
44
  const render_frames_1 = require("./render-frames");
45
45
  const repro_1 = require("./repro");
46
46
  const stitch_frames_to_video_1 = require("./stitch-frames-to-video");
@@ -54,10 +54,9 @@ const validate_output_filename_1 = require("./validate-output-filename");
54
54
  const validate_scale_1 = require("./validate-scale");
55
55
  const validate_videobitrate_1 = require("./validate-videobitrate");
56
56
  const wrap_with_error_handling_1 = require("./wrap-with-error-handling");
57
- const write_with_backpressure_1 = require("./write-with-backpressure");
58
57
  const SLOWEST_FRAME_COUNT = 10;
59
58
  const MAX_RECENT_FRAME_TIMINGS = 150;
60
- const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, composition: compositionWithPossibleUnevenDimensions, serializedInputPropsWithCustomSchema, pixelFormat: userPixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, concurrency, disallowParallelEncoding, everyNthFrame, imageFormat: provisionalImageFormat, indent, jpegQuality, numberOfGifLoops, onCtrlCExit, preferLossless, serveUrl, server: reusedServer, logLevel, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, compositionStart, onBrowserDownload, onArtifact, metadata, hardwareAcceleration, chromeMode, offthreadVideoThreads, mediaCacheSizeInBytes, onLog, licenseKey, isProduction, sampleRate, }) => {
59
+ const internalRenderMediaRaw = async ({ proResProfile, x264Preset, gopSize, crf, composition: compositionWithPossibleUnevenDimensions, serializedInputPropsWithCustomSchema, pixelFormat: userPixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, concurrency, disallowParallelEncoding, disableSharedMemoryCapture, everyNthFrame, imageFormat: provisionalImageFormat, indent, jpegQuality, numberOfGifLoops, onCtrlCExit, preferLossless, serveUrl, server: reusedServer, logLevel, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, compositionStart, onBrowserDownload, onArtifact, metadata, hardwareAcceleration, chromeMode, offthreadVideoThreads, mediaCacheSizeInBytes, onLog, licenseKey, isProduction, sampleRate, }) => {
61
60
  var _a, _b;
62
61
  const pixelFormat = (_a = userPixelFormat !== null && userPixelFormat !== void 0 ? userPixelFormat : compositionWithPossibleUnevenDimensions.defaultPixelFormat) !== null && _a !== void 0 ? _a : pixel_format_1.DEFAULT_PIXEL_FORMAT;
63
62
  if (repro) {
@@ -123,19 +122,7 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
123
122
  let renderEstimatedTime = 0;
124
123
  const recentFrameTimings = [];
125
124
  const renderStart = Date.now();
126
- const { estimatedUsage, freeMemory, hasEnoughMemory } = (0, prestitcher_memory_usage_1.shouldUseParallelEncoding)({
127
- height: compositionWithPossibleUnevenDimensions.height,
128
- width: compositionWithPossibleUnevenDimensions.width,
129
- logLevel,
130
- });
131
- const parallelEncoding = !disallowParallelEncoding &&
132
- hasEnoughMemory &&
133
- (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec);
134
- logger_1.Log.verbose({
135
- indent,
136
- logLevel,
137
- tag: 'renderMedia()',
138
- }, 'Free memory:', freeMemory, 'Estimated usage parallel encoding', estimatedUsage);
125
+ const parallelEncoding = !disallowParallelEncoding && (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec);
139
126
  const resolvedConcurrency = (0, get_concurrency_1.resolveConcurrency)(concurrency);
140
127
  logger_1.Log.verbose({
141
128
  indent,
@@ -176,7 +163,17 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
176
163
  const imageFormat = (0, is_audio_codec_1.isAudioCodec)(codec)
177
164
  ? 'none'
178
165
  : ((_b = provisionalImageFormat !== null && provisionalImageFormat !== void 0 ? provisionalImageFormat : compositionWithPossibleUnevenDimensions.defaultVideoImageFormat) !== null && _b !== void 0 ? _b : image_format_1.DEFAULT_VIDEO_IMAGE_FORMAT);
179
- (0, image_format_1.validateSelectedPixelFormatAndImageFormatCombination)(pixelFormat, imageFormat);
166
+ (0, image_format_1.validateVideoImageFormat)(imageFormat);
167
+ const remotionSharedMemorySupport = !parallelEncoding || disableSharedMemoryCapture
168
+ ? null
169
+ : await (0, prespawn_ffmpeg_1.probeRemotionSharedMemoryFfmpegSupport)({
170
+ binariesDirectory,
171
+ indent,
172
+ logLevel,
173
+ });
174
+ if (!(remotionSharedMemorySupport === null || remotionSharedMemorySupport === void 0 ? void 0 : remotionSharedMemorySupport.sharedMemory)) {
175
+ (0, image_format_1.validateSelectedPixelFormatAndImageFormatCombination)(pixelFormat, imageFormat);
176
+ }
180
177
  const workingDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'react-motion-render'));
181
178
  const preEncodedFileLocation = parallelEncoding
182
179
  ? node_path_1.default.join(workingDir, 'pre-encode.' + (0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, audioCodec))
@@ -195,6 +192,25 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
195
192
  });
196
193
  const actualWidth = widthEvenDimensions * scale;
197
194
  const actualHeight = heightEvenDimensions * scale;
195
+ if (disableSharedMemoryCapture) {
196
+ logger_1.Log.verbose({ indent, logLevel, tag: 'renderMedia()' }, 'Shared-memory capture is disabled by configuration.');
197
+ }
198
+ // Chromium creates file-backed frame pools in this private directory when
199
+ // POSIX shared memory is unavailable (no /dev/shm, as on AWS Lambda). It is
200
+ // only offered when the FFmpeg binary can open such pools via -pool_dir.
201
+ const remotionSharedMemoryPoolDirectory = (remotionSharedMemorySupport === null || remotionSharedMemorySupport === void 0 ? void 0 : remotionSharedMemorySupport.filePools)
202
+ ? node_fs_1.default.mkdtempSync(node_path_1.default.join(workingDir, 'shm-pools-'))
203
+ : null;
204
+ const remotionSharedMemory = (remotionSharedMemorySupport === null || remotionSharedMemorySupport === void 0 ? void 0 : remotionSharedMemorySupport.sharedMemory)
205
+ ? new remotion_shared_memory_1.RemotionSharedMemoryCapture({
206
+ width: Math.round(actualWidth),
207
+ height: Math.round(actualHeight),
208
+ indent,
209
+ logLevel,
210
+ backingDirectory: remotionSharedMemoryPoolDirectory,
211
+ })
212
+ : null;
213
+ remotionSharedMemory === null || remotionSharedMemory === void 0 ? void 0 : remotionSharedMemory.setPixelFormat(pixelFormat);
198
214
  const composition = {
199
215
  ...compositionWithPossibleUnevenDimensions,
200
216
  height: heightEvenDimensions,
@@ -227,8 +243,13 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
227
243
  const { waitForRightTimeOfFrameToBeInserted, setFrameToStitch, waitForFinish } = (0, ensure_frames_in_order_1.ensureFramesInOrder)(framesToRender);
228
244
  const fps = composition.fps / everyNthFrame;
229
245
  (0, validate_1.validateFps)(fps, 'in "renderMedia()"', codec === 'gif');
230
- const createPrestitcherIfNecessary = () => {
231
- if (preEncodedFileLocation) {
246
+ let preStitcherInputMode = null;
247
+ let notifyPreStitcherStarted;
248
+ const preStitcherStarted = new Promise((resolve) => {
249
+ notifyPreStitcherStarted = resolve;
250
+ });
251
+ const createPrestitcherIfNecessary = (inputMode) => {
252
+ if (preEncodedFileLocation && !preStitcher) {
232
253
  preStitcher = (0, prespawn_ffmpeg_1.prespawnFfmpeg)({
233
254
  width: actualWidth,
234
255
  height: actualHeight,
@@ -256,19 +277,30 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
256
277
  binariesDirectory,
257
278
  hardwareAcceleration,
258
279
  onLog,
280
+ inputMode,
281
+ remotionSharedMemoryPoolDirectory: inputMode === 'remotion-shared-memory'
282
+ ? remotionSharedMemoryPoolDirectory
283
+ : null,
259
284
  });
285
+ preStitcherInputMode = inputMode;
260
286
  stitcherFfmpeg = preStitcher.task;
287
+ notifyPreStitcherStarted();
288
+ }
289
+ if (preStitcherInputMode !== inputMode) {
290
+ throw new Error(`Cannot mix ${inputMode} frames with ${preStitcherInputMode} FFmpeg input.`);
261
291
  }
262
292
  };
263
293
  const waitForPrestitcherIfNecessary = async () => {
264
- var _a;
294
+ if (preEncodedFileLocation) {
295
+ await preStitcherStarted;
296
+ }
265
297
  if (stitcherFfmpeg) {
266
298
  await waitForFinish();
267
- (_a = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin) === null || _a === void 0 ? void 0 : _a.end();
299
+ await (preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.finishInput());
268
300
  try {
269
301
  await stitcherFfmpeg;
270
302
  }
271
- catch (_b) {
303
+ catch (_a) {
272
304
  throw new Error(preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.getLogs());
273
305
  }
274
306
  }
@@ -303,7 +335,7 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
303
335
  };
304
336
  let cleanupServerFn = () => Promise.resolve(undefined);
305
337
  const happyPath = new Promise((resolve, reject) => {
306
- Promise.resolve(createPrestitcherIfNecessary())
338
+ Promise.resolve()
307
339
  .then(() => {
308
340
  return (0, prepare_server_1.makeOrReuseServer)(reusedServer, {
309
341
  offthreadVideoThreads: offthreadVideoThreads !== null && offthreadVideoThreads !== void 0 ? offthreadVideoThreads : offthreadvideo_threads_1.DEFAULT_RENDER_FRAMES_OFFTHREAD_VIDEO_THREADS,
@@ -360,31 +392,80 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
360
392
  outputFramesInSequence: true,
361
393
  puppeteerInstance,
362
394
  everyNthFrame,
363
- onFrameBuffer: parallelEncoding
364
- ? async (buffer, frame) => {
395
+ onFrameBuffer: null,
396
+ onFrame: parallelEncoding
397
+ ? async (capturedFrame, frame) => {
365
398
  var _a;
366
- await waitForRightTimeOfFrameToBeInserted(frame);
367
- if (cancelled) {
368
- return;
369
- }
370
- const id = (0, perf_1.startPerfMeasure)('piping');
371
- const exitStatus = preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.getExitStatus();
372
- if ((exitStatus === null || exitStatus === void 0 ? void 0 : exitStatus.type) === 'quit-successfully') {
373
- throw new Error(`FFmpeg already quit while trying to pipe frame ${frame} to it. Stderr: ${exitStatus.stderr}`);
374
- }
375
- if ((exitStatus === null || exitStatus === void 0 ? void 0 : exitStatus.type) === 'quit-with-error') {
376
- throw new Error(`FFmpeg quit with code ${exitStatus.exitCode}${exitStatus.signal ? ` (signal ${exitStatus.signal})` : ''} while piping frame ${frame}. Stderr: ${exitStatus.stderr}`);
399
+ let handedToFfmpeg = false;
400
+ try {
401
+ if ((0, remotion_shared_memory_1.isRemotionRawFrame)(capturedFrame)) {
402
+ let notifyRetirement;
403
+ const retirement = new Promise((resolveRetirement) => {
404
+ notifyRetirement = () => resolveRetirement(true);
405
+ });
406
+ const unsubscribeFromRetirement = capturedFrame.poolLifetime.onRetired(() => {
407
+ notifyRetirement();
408
+ return Promise.resolve();
409
+ });
410
+ if (!unsubscribeFromRetirement) {
411
+ notifyRetirement();
412
+ }
413
+ let retiredBeforeItsTurn;
414
+ try {
415
+ retiredBeforeItsTurn = await Promise.race([
416
+ waitForRightTimeOfFrameToBeInserted(frame).then(() => false),
417
+ retirement,
418
+ ]);
419
+ }
420
+ finally {
421
+ unsubscribeFromRetirement === null || unsubscribeFromRetirement === void 0 ? void 0 : unsubscribeFromRetirement();
422
+ }
423
+ if (retiredBeforeItsTurn) {
424
+ throw new Error('Target closed while a raw frame was waiting for its FFmpeg turn.');
425
+ }
426
+ if (capturedFrame.poolLifetime.isRetired()) {
427
+ throw new Error('Target closed before a raw frame was sent to FFmpeg.');
428
+ }
429
+ }
430
+ else {
431
+ await waitForRightTimeOfFrameToBeInserted(frame);
432
+ }
433
+ if (cancelled) {
434
+ return;
435
+ }
436
+ const id = (0, perf_1.startPerfMeasure)('piping');
437
+ const exitStatus = preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.getExitStatus();
438
+ if ((exitStatus === null || exitStatus === void 0 ? void 0 : exitStatus.type) === 'quit-successfully') {
439
+ throw new Error(`FFmpeg already quit while trying to pipe frame ${frame} to it. Stderr: ${exitStatus.stderr}`);
440
+ }
441
+ if ((exitStatus === null || exitStatus === void 0 ? void 0 : exitStatus.type) === 'quit-with-error') {
442
+ throw new Error(`FFmpeg quit with code ${exitStatus.exitCode}${exitStatus.signal ? ` (signal ${exitStatus.signal})` : ''} while piping frame ${frame}. Stderr: ${exitStatus.stderr}`);
443
+ }
444
+ const inputMode = (0, remotion_shared_memory_1.isRemotionRawFrame)(capturedFrame)
445
+ ? 'remotion-shared-memory'
446
+ : 'encoded-image';
447
+ createPrestitcherIfNecessary(inputMode);
448
+ const frameIndex = framesToRender.indexOf(frame);
449
+ const writeResult = await (preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.writeFrame({
450
+ frame: capturedFrame,
451
+ pts: frameIndex,
452
+ }));
453
+ if (!writeResult) {
454
+ throw new Error(`FFmpeg is not available while trying to pipe frame ${frame} to it.`);
455
+ }
456
+ handedToFfmpeg = true;
457
+ (0, perf_1.stopPerfMeasure)(id);
458
+ setFrameToStitch((_a = framesToRender[frameIndex + 1]) !== null && _a !== void 0 ? _a : lastFrameToRender + 1);
459
+ await writeResult.waitForAck;
377
460
  }
378
- const stdin = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin;
379
- if (!stdin) {
380
- throw new Error(`FFmpeg stdin is not available while trying to pipe frame ${frame} to it.`);
461
+ finally {
462
+ if (!handedToFfmpeg && (0, remotion_shared_memory_1.isRemotionRawFrame)(capturedFrame)) {
463
+ await capturedFrame.release();
464
+ }
381
465
  }
382
- await (0, write_with_backpressure_1.writeWithBackpressure)({ data: buffer, writable: stdin });
383
- (0, perf_1.stopPerfMeasure)(id);
384
- const frameIndex = framesToRender.indexOf(frame);
385
- setFrameToStitch((_a = framesToRender[frameIndex + 1]) !== null && _a !== void 0 ? _a : lastFrameToRender + 1);
386
466
  }
387
467
  : null,
468
+ remotionSharedMemory,
388
469
  webpackBundleOrServeUrl: serveUrl,
389
470
  onBrowserLog,
390
471
  onDownload,
@@ -421,7 +502,8 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
421
502
  waitForPrestitcherIfNecessary(),
422
503
  ]);
423
504
  })
424
- .then(([{ assetsInfo }]) => {
505
+ .then(async ([{ assetsInfo }]) => {
506
+ await (remotionSharedMemory === null || remotionSharedMemory === void 0 ? void 0 : remotionSharedMemory.destroy());
425
507
  renderedDoneIn = Date.now() - renderStart;
426
508
  logger_1.Log.verbose({ indent, logLevel }, 'Rendering frames done in', renderedDoneIn + 'ms');
427
509
  if (absoluteOutputLocation) {
@@ -536,6 +618,7 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
536
618
  * Therefore we first kill the FFMPEG process before deleting the file
537
619
  */
538
620
  cancelled = true;
621
+ preStitcher === null || preStitcher === void 0 ? void 0 : preStitcher.abortInput(err);
539
622
  cancelRenderFrames.cancel();
540
623
  cancelStitcher.cancel();
541
624
  cancelPrestitcher.cancel();
@@ -560,7 +643,8 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, gopSize, crf, compo
560
643
  }
561
644
  reject(err);
562
645
  })
563
- .finally(() => {
646
+ .finally(async () => {
647
+ await (remotionSharedMemory === null || remotionSharedMemory === void 0 ? void 0 : remotionSharedMemory.dispose());
564
648
  if (preEncodedFileLocation !== null &&
565
649
  node_fs_1.default.existsSync(preEncodedFileLocation)) {
566
650
  (0, delete_directory_1.deleteDirectory)(node_path_1.default.dirname(preEncodedFileLocation));
@@ -587,7 +671,7 @@ exports.internalRenderMedia = (0, wrap_with_error_handling_1.wrapWithErrorHandli
587
671
  * @description Render a video or an audio programmatically.
588
672
  * @see [Documentation](https://www.remotion.dev/docs/renderer/render-media)
589
673
  */
590
- const renderMedia = ({ proResProfile, x264Preset, gopSize, crf, composition, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, metadata, hardwareAcceleration, chromeMode, offthreadVideoThreads, compositionStart, mediaCacheSizeInBytes, isProduction, sampleRate, ...apiKeyOrLicenseKey }) => {
674
+ const renderMedia = ({ proResProfile, x264Preset, gopSize, crf, composition, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, disableSharedMemoryCapture, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, metadata, hardwareAcceleration, chromeMode, offthreadVideoThreads, compositionStart, mediaCacheSizeInBytes, isProduction, sampleRate, ...apiKeyOrLicenseKey }) => {
591
675
  var _a, _b, _c, _d;
592
676
  const indent = false;
593
677
  const logLevel = verbose || dumpBrowserLogs ? 'verbose' : (passedLogLevel !== null && passedLogLevel !== void 0 ? passedLogLevel : 'info');
@@ -624,6 +708,7 @@ const renderMedia = ({ proResProfile, x264Preset, gopSize, crf, composition, inp
624
708
  concurrency: concurrency !== null && concurrency !== void 0 ? concurrency : null,
625
709
  crf: crf !== null && crf !== void 0 ? crf : null,
626
710
  disallowParallelEncoding: disallowParallelEncoding !== null && disallowParallelEncoding !== void 0 ? disallowParallelEncoding : false,
711
+ disableSharedMemoryCapture: disableSharedMemoryCapture !== null && disableSharedMemoryCapture !== void 0 ? disableSharedMemoryCapture : false,
627
712
  enforceAudioTrack: enforceAudioTrack !== null && enforceAudioTrack !== void 0 ? enforceAudioTrack : false,
628
713
  envVariables: envVariables !== null && envVariables !== void 0 ? envVariables : {},
629
714
  everyNthFrame: everyNthFrame !== null && everyNthFrame !== void 0 ? everyNthFrame : 1,
@@ -228,6 +228,7 @@ const innerRenderStill = async ({ composition, imageFormat = image_format_1.DEFA
228
228
  jpegQuality,
229
229
  wantsBuffer: !output,
230
230
  timeoutInMilliseconds,
231
+ remotionSharedMemory: null,
231
232
  }),
232
233
  (0, collect_assets_1.collectAssets)({
233
234
  frame,
@@ -0,0 +1,2 @@
1
+ import type { Page } from './browser/BrowserPage';
2
+ export declare const setScreenshotBackground: (page: Page, omitBackground: boolean) => Promise<void>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setScreenshotBackground = void 0;
4
+ const transparentBackgrounds = new WeakSet();
5
+ const setScreenshotBackground = async (page, omitBackground) => {
6
+ if (transparentBackgrounds.has(page) === omitBackground) {
7
+ return;
8
+ }
9
+ if (omitBackground) {
10
+ await page._client().send('Emulation.setDefaultBackgroundColorOverride', {
11
+ color: { r: 0, g: 0, b: 0, a: 0 },
12
+ });
13
+ transparentBackgrounds.add(page);
14
+ }
15
+ else {
16
+ await page._client().send('Emulation.setDefaultBackgroundColorOverride');
17
+ transparentBackgrounds.delete(page);
18
+ }
19
+ };
20
+ exports.setScreenshotBackground = setScreenshotBackground;
@@ -1,5 +1,6 @@
1
1
  import type { Page } from './browser/BrowserPage';
2
- export declare const screenshotTask: ({ format, height, omitBackground, page, width, path, jpegQuality, scale, }: {
2
+ import type { CapturedFrame, RemotionSharedMemoryCapture } from './remotion-shared-memory';
3
+ export declare const screenshotTask: ({ format, height, omitBackground, page, width, path, jpegQuality, scale, remotionSharedMemory, }: {
3
4
  page: Page;
4
5
  format: "jpeg" | "pdf" | "png" | "webp";
5
6
  path?: string | undefined;
@@ -8,4 +9,5 @@ export declare const screenshotTask: ({ format, height, omitBackground, page, wi
8
9
  width: number;
9
10
  height: number;
10
11
  scale: number;
11
- }) => Promise<Buffer>;
12
+ remotionSharedMemory: RemotionSharedMemoryCapture | null;
13
+ }) => Promise<CapturedFrame>;
@@ -6,18 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.screenshotTask = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const perf_1 = require("./perf");
9
- const screenshotTask = async ({ format, height, omitBackground, page, width, path, jpegQuality, scale, }) => {
9
+ const screenshot_background_1 = require("./screenshot-background");
10
+ const screenshotTask = async ({ format, height, omitBackground, page, width, path, jpegQuality, scale, remotionSharedMemory, }) => {
10
11
  var _a;
11
12
  const client = page._client();
12
13
  const target = page.target();
13
14
  await client.send('Target.activateTarget', {
14
15
  targetId: target._targetId,
15
16
  });
16
- if (omitBackground) {
17
- await client.send('Emulation.setDefaultBackgroundColorOverride', {
18
- color: { r: 0, g: 0, b: 0, a: 0 },
19
- });
20
- }
17
+ await (0, screenshot_background_1.setScreenshotBackground)(page, omitBackground);
21
18
  const cap = (0, perf_1.startPerfMeasure)('capture');
22
19
  try {
23
20
  let result;
@@ -44,25 +41,47 @@ const screenshotTask = async ({ format, height, omitBackground, page, width, pat
44
41
  // If the image is larger, always use `fromSurface: true`.
45
42
  const fromSurface = !process.env.DISABLE_FROM_SURFACE || height > 8192 || width > 8192;
46
43
  const scaleFactor = fromSurface ? 1 : scale;
47
- const { value } = await client.send('Page.captureScreenshot', {
48
- format,
49
- quality: jpegQuality,
50
- clip: {
51
- x: 0,
52
- y: 0,
53
- height: height * scaleFactor,
54
- scale: 1,
55
- width: width * scaleFactor,
56
- },
57
- captureBeyondViewport: true,
58
- optimizeForSpeed: true,
59
- fromSurface,
60
- });
44
+ const reservation = await (remotionSharedMemory === null || remotionSharedMemory === void 0 ? void 0 : remotionSharedMemory.acquire(page));
45
+ let value;
46
+ try {
47
+ ({ value } = await client.send('Page.captureScreenshot', {
48
+ format,
49
+ quality: jpegQuality,
50
+ clip: {
51
+ x: 0,
52
+ y: 0,
53
+ height: height * scaleFactor,
54
+ scale: 1,
55
+ width: width * scaleFactor,
56
+ },
57
+ captureBeyondViewport: true,
58
+ optimizeForSpeed: true,
59
+ fromSurface,
60
+ remotionFrameSlot: reservation === null || reservation === void 0 ? void 0 : reservation.slot,
61
+ remotionFrameId: reservation === null || reservation === void 0 ? void 0 : reservation.frameId,
62
+ remotionFastViewport: reservation ? true : undefined,
63
+ }));
64
+ }
65
+ catch (error) {
66
+ reservation === null || reservation === void 0 ? void 0 : reservation.fail();
67
+ throw error;
68
+ }
69
+ if (reservation) {
70
+ if (value.data !== '' || !value.remotionFrame) {
71
+ await reservation.discardPublished();
72
+ throw new Error('Chromium did not return a Remotion shared-memory frame.');
73
+ }
74
+ const rawFrame = await reservation.publish(value.remotionFrame);
75
+ (0, perf_1.stopPerfMeasure)(cap);
76
+ // Keep the background configured until pool cleanup. Encoded
77
+ // screenshots restore it below, including thumbnails on this page.
78
+ return rawFrame;
79
+ }
61
80
  result = value;
62
81
  }
63
82
  (0, perf_1.stopPerfMeasure)(cap);
64
83
  if (omitBackground) {
65
- await client.send('Emulation.setDefaultBackgroundColorOverride');
84
+ await (0, screenshot_background_1.setScreenshotBackground)(page, false);
66
85
  }
67
86
  const buffer = Buffer.from(result.data, 'base64');
68
87
  if (path) {
@@ -143,6 +143,6 @@ const seekToFrame = async ({ frame, page, composition, timeoutInMilliseconds, lo
143
143
  timeoutInMilliseconds,
144
144
  });
145
145
  await (0, exports.waitForReady)({ page, timeoutInMilliseconds, frame, indent, logLevel });
146
- await page.evaluateHandle('document.fonts.ready');
146
+ await page.evaluate('document.fonts.ready.then(() => true)');
147
147
  };
148
148
  exports.seekToFrame = seekToFrame;
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.stitchFramesToVideo = exports.internalStitchFramesToVideo = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
+ const no_react_1 = require("remotion/no-react");
9
10
  const aac_priming_1 = require("./aac-priming");
10
11
  const download_map_1 = require("./assets/download-map");
11
12
  const call_ffmpeg_1 = require("./call-ffmpeg");
@@ -23,11 +24,13 @@ const get_cpu_count_1 = require("./get-cpu-count");
23
24
  const get_extension_from_codec_1 = require("./get-extension-from-codec");
24
25
  const get_extension_of_filename_1 = require("./get-extension-of-filename");
25
26
  const get_fast_start_muxer_1 = require("./get-fast-start-muxer");
27
+ const get_mp4_brand_1 = require("./get-mp4-brand");
26
28
  const get_prores_profile_name_1 = require("./get-prores-profile-name");
27
29
  const logger_1 = require("./logger");
28
30
  const make_cancel_signal_1 = require("./make-cancel-signal");
29
31
  const make_metadata_args_1 = require("./make-metadata-args");
30
32
  const from_lambda_env_1 = require("./memory/from-lambda-env");
33
+ const mux_video_and_audio_1 = require("./mux-video-and-audio");
31
34
  const audio_codec_1 = require("./options/audio-codec");
32
35
  const color_space_1 = require("./options/color-space");
33
36
  const gop_size_1 = require("./options/gop-size");
@@ -40,8 +43,8 @@ const validate_1 = require("./validate");
40
43
  const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
41
44
  const validate_videobitrate_1 = require("./validate-videobitrate");
42
45
  const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec: audioCodecSetting, cancelSignal, codec, crf, gopSize, enforceAudioTrack, ffmpegOverride, force, fps, height, indent, muted, onDownload, outputLocation, pixelFormat, preEncodedFileLocation, preferLossless, proResProfile, logLevel, videoBitrate, maxRate, bufferSize, width, numberOfGifLoops, onProgress, x264Preset, colorSpace, binariesDirectory, separateAudioTo, metadata, hardwareAcceleration, sampleRate, onLog, }, remotionRoot) => {
43
- var _a;
44
- var _b, _c;
46
+ var _a, _b;
47
+ var _c, _d, _e;
45
48
  (0, validate_1.validateDimension)(height, 'height', 'passed to `stitchFramesToVideo()`');
46
49
  (0, validate_1.validateDimension)(width, 'width', 'passed to `stitchFramesToVideo()`');
47
50
  (0, validate_even_dimensions_with_codec_1.validateEvenDimensionsWithCodec)({
@@ -91,7 +94,15 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec:
91
94
  const tempFile = outputLocation
92
95
  ? null
93
96
  : node_path_1.default.join(assetsInfo.downloadMap.stitchFrames, `out.${(0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, resolvedAudioCodec)}`);
94
- const outputExtension = ((_b = (0, get_extension_of_filename_1.getExtensionOfFilename)(outputLocation)) !== null && _b !== void 0 ? _b : (0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, resolvedAudioCodec)).toLowerCase();
97
+ const outputExtension = ((_c = (0, get_extension_of_filename_1.getExtensionOfFilename)(outputLocation)) !== null && _c !== void 0 ? _c : (0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, resolvedAudioCodec)).toLowerCase();
98
+ if (codec === 'aac' &&
99
+ (outputExtension === 'mpg' || outputExtension === 'mpeg')) {
100
+ const message = 'AAC output with .mpg or .mpeg extensions is not supported. Use .aac for raw ADTS AAC or .m4a for an MPEG-4 audio container.';
101
+ if (no_react_1.NoReactInternals.ENABLE_V5_BREAKING_CHANGES) {
102
+ throw new Error(message);
103
+ }
104
+ logger_1.Log.warn({ indent, logLevel }, `${message} Falling back to raw ADTS AAC while keeping the requested filename. This will throw an error in Remotion 5.0.`);
105
+ }
95
106
  const fastStartMuxer = (0, get_fast_start_muxer_1.getFastStartMuxer)(outputExtension);
96
107
  // Fast Start reopens its output for an in-place second pass. Keep that work
97
108
  // away from the public output path so Windows file observers cannot lock it.
@@ -175,7 +186,28 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec:
175
186
  if (separateAudioTo) {
176
187
  throw new Error('`separateAudioTo` was set, but this render was audio-only. This option is meant to be used for video renders.');
177
188
  }
178
- (0, node_fs_1.cpSync)(audio, outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile);
189
+ let audioOnlyFile = audio;
190
+ if ((0, get_mp4_brand_1.getMp4BrandForExtension)(outputExtension)) {
191
+ // Mux away from the public output path: Fast Start reopens the file
192
+ // for a second pass, which Windows file observers can lock.
193
+ audioOnlyFile = node_path_1.default.join(assetsInfo.downloadMap.stitchFrames, `audio-only.${outputExtension}`);
194
+ await (0, mux_video_and_audio_1.muxVideoAndAudio)({
195
+ videoOutput: null,
196
+ audioOutput: audio,
197
+ output: audioOnlyFile,
198
+ indent,
199
+ logLevel,
200
+ onProgress: () => undefined,
201
+ binariesDirectory,
202
+ fps,
203
+ cancelSignal: cancelSignal !== null && cancelSignal !== void 0 ? cancelSignal : undefined,
204
+ metadata,
205
+ numberOfGifLoops: null,
206
+ audioCodec: resolvedAudioCodec,
207
+ sampleRate,
208
+ });
209
+ }
210
+ (0, node_fs_1.cpSync)(audioOnlyFile, outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile);
179
211
  onProgress === null || onProgress === void 0 ? void 0 : onProgress(Math.round(assetsInfo.chunkLengthInSeconds * fps));
180
212
  (0, delete_directory_1.deleteDirectory)(node_path_1.default.dirname(audio));
181
213
  const file = await new Promise((resolve, reject) => {
@@ -261,10 +293,17 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec:
261
293
  }),
262
294
  // Ignore metadata that may come from remote media
263
295
  ['-map_metadata', '-1'],
296
+ // VP8/VP9 store alpha in additional blocks. Stream copying cannot infer
297
+ // the alpha channel from the decoded pixel format, so retain its signal.
298
+ preEncodedFileLocation &&
299
+ (codec === 'vp8' || codec === 'vp9') &&
300
+ pixelFormat === 'yuva420p'
301
+ ? ['-metadata:s:v:0', 'alpha_mode=1']
302
+ : null,
264
303
  ...(0, make_metadata_args_1.makeMetadataArgs)(metadata !== null && metadata !== void 0 ? metadata : {}),
265
304
  force || fastStartIntermediate ? '-y' : null,
266
305
  fastStartIntermediate ? ['-f', fastStartMuxer] : null,
267
- (_c = fastStartIntermediate !== null && fastStartIntermediate !== void 0 ? fastStartIntermediate : outputLocation) !== null && _c !== void 0 ? _c : tempFile,
306
+ (_d = fastStartIntermediate !== null && fastStartIntermediate !== void 0 ? fastStartIntermediate : outputLocation) !== null && _d !== void 0 ? _d : tempFile,
268
307
  ];
269
308
  const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
270
309
  const finalFfmpegString = ffmpegOverride
@@ -312,11 +351,6 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec:
312
351
  }
313
352
  }
314
353
  });
315
- if (separateAudioTo && audio) {
316
- const finalDestination = node_path_1.default.resolve(remotionRoot, separateAudioTo);
317
- (0, node_fs_1.cpSync)(audio, finalDestination);
318
- (0, node_fs_1.rmSync)(audio);
319
- }
320
354
  await new Promise((resolve, reject) => {
321
355
  task.once('close', (code, signal) => {
322
356
  if (code === 0) {
@@ -327,6 +361,33 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec:
327
361
  }
328
362
  });
329
363
  });
364
+ if (separateAudioTo && audio) {
365
+ const finalDestination = node_path_1.default.resolve(remotionRoot, separateAudioTo);
366
+ const separateAudioExtension = (_e = (_b = (0, get_extension_of_filename_1.getExtensionOfFilename)(finalDestination)) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _e !== void 0 ? _e : null;
367
+ let separateAudioFile = audio;
368
+ if ((0, get_mp4_brand_1.getMp4BrandForExtension)(separateAudioExtension)) {
369
+ // Like audio-only renders: the ADTS stream is remuxed into the
370
+ // container, away from the public path because of Fast Start.
371
+ separateAudioFile = node_path_1.default.join(assetsInfo.downloadMap.stitchFrames, `separate-audio.${separateAudioExtension}`);
372
+ await (0, mux_video_and_audio_1.muxVideoAndAudio)({
373
+ videoOutput: null,
374
+ audioOutput: audio,
375
+ output: separateAudioFile,
376
+ indent,
377
+ logLevel,
378
+ onProgress: () => undefined,
379
+ binariesDirectory,
380
+ fps,
381
+ cancelSignal: cancelSignal !== null && cancelSignal !== void 0 ? cancelSignal : undefined,
382
+ metadata: null,
383
+ numberOfGifLoops: null,
384
+ audioCodec: resolvedAudioCodec,
385
+ sampleRate,
386
+ });
387
+ }
388
+ (0, node_fs_1.cpSync)(separateAudioFile, finalDestination);
389
+ (0, node_fs_1.rmSync)(audio);
390
+ }
330
391
  if (fastStartIntermediate && fastStartMuxer) {
331
392
  const destination = outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile;
332
393
  if (destination === null) {
@@ -1,7 +1,9 @@
1
1
  import type { Page } from './browser/BrowserPage';
2
- export declare const takeFrame: ({ freePage, imageFormat, jpegQuality, width, height, output, scale, wantsBuffer, timeoutInMilliseconds, }: {
2
+ import type { StillImageFormat, VideoImageFormat } from './image-format';
3
+ import type { CapturedFrame, RemotionSharedMemoryCapture } from './remotion-shared-memory';
4
+ type TakeFrameOptions = {
3
5
  freePage: Page;
4
- imageFormat: "jpeg" | "none" | "pdf" | "png" | "webp";
6
+ imageFormat: VideoImageFormat | StillImageFormat;
5
7
  jpegQuality: number | undefined;
6
8
  height: number;
7
9
  width: number;
@@ -9,4 +11,10 @@ export declare const takeFrame: ({ freePage, imageFormat, jpegQuality, width, he
9
11
  scale: number;
10
12
  wantsBuffer: boolean;
11
13
  timeoutInMilliseconds: number;
12
- }) => Promise<Buffer | null>;
14
+ remotionSharedMemory: RemotionSharedMemoryCapture | null;
15
+ };
16
+ type TakeFrameResult<T extends RemotionSharedMemoryCapture | null> = T extends null ? Buffer | null : CapturedFrame | null;
17
+ export declare const takeFrame: <T extends RemotionSharedMemoryCapture | null>({ freePage, imageFormat, jpegQuality, width, height, output, scale, wantsBuffer, timeoutInMilliseconds, remotionSharedMemory, }: Omit<TakeFrameOptions, "remotionSharedMemory"> & {
18
+ remotionSharedMemory: T;
19
+ }) => Promise<TakeFrameResult<T>>;
20
+ export {};