From 5b9d3cacad886587b24df0514d148764fb45ff1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Sat, 11 Jul 2026 18:24:06 +0000 Subject: [PATCH] fix(render): stream long low-memory captures --- .../producer/src/services/renderOrchestrator.test.ts | 7 +++++++ packages/producer/src/services/renderOrchestrator.ts | 9 +++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/producer/src/services/renderOrchestrator.test.ts b/packages/producer/src/services/renderOrchestrator.test.ts index 20ccf03b86..0960f2abf4 100644 --- a/packages/producer/src/services/renderOrchestrator.test.ts +++ b/packages/producer/src/services/renderOrchestrator.test.ts @@ -392,6 +392,7 @@ describe("shouldUseStreamingEncode", () => { const streamingEnabledConfig = { enableStreamingEncode: true, streamingEncodeMaxDurationSeconds: 240, + lowMemoryMode: false, }; it("enables streaming for default single-worker video renders", () => { @@ -434,6 +435,12 @@ describe("shouldUseStreamingEncode", () => { ), ).toBe(false); }); + + it("keeps long single-worker renders streaming in low-memory mode", () => { + expect( + shouldUseStreamingEncode({ ...streamingEnabledConfig, lowMemoryMode: true }, "mp4", 1, 411), + ).toBe(true); + }); }); describe("createCompiledFrameSrcResolver", () => { diff --git a/packages/producer/src/services/renderOrchestrator.ts b/packages/producer/src/services/renderOrchestrator.ts index 2a493f566c..88c7a4d166 100644 --- a/packages/producer/src/services/renderOrchestrator.ts +++ b/packages/producer/src/services/renderOrchestrator.ts @@ -966,7 +966,8 @@ function replaceBodyWithRenderClone(body: HTMLElement, renderClone: Element): vo } export function shouldUseStreamingEncode( - cfg: Pick, + cfg: Pick & + Partial>, outputFormat: NonNullable, workerCount: number, // Composition timeline duration in seconds. @@ -980,7 +981,11 @@ export function shouldUseStreamingEncode( if (outputFormat === "png-sequence") return false; if (outputFormat === "gif") return false; if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) return false; - if (durationSeconds > cfg.streamingEncodeMaxDurationSeconds) return false; + // Low-memory mode already pins capture to one worker. Keep those renders on + // the streaming path regardless of duration so captured frames are drained + // directly into FFmpeg instead of accumulating hundreds of gigabytes of + // data URIs / disk frames until Chrome OOMs. + if (!cfg.lowMemoryMode && durationSeconds > cfg.streamingEncodeMaxDurationSeconds) return false; // HF_DE_PARALLEL_STREAM (manual opt-in) / forceParallelStream (router): // allow multi-worker streaming for the interleaved drawElement produce // path. Contiguous-chunk parallel streaming stalls (worker k+1's first