Repository navigation
feat(producer): a capture segment extracts the frames it shows and deletes them - #7241
Conversation
2c08d8a to
79072a0
Compare
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 1 important · 1 nit · 79072a0
The on-demand hook holds up. fresh() is the only one the engine calls (frameCapture.ts:5629, the self-verify truth page). Recycles only happen between segments, at cadence or on retry, while injector is null. Static dedup turns itself off whenever a hook is set. So each worker's self-verify truth frames come from frames it has actually extracted.
- nit:
removeJoinedSegments(captureSegmentedStage.ts:382) doesn't lower the peak. The orchestrator already runsrmSync(segmentDir)on success under the samekeepSegmentscheck, right after this stage returns. The peak happens during the concat, which both deletes come after.
Scope
Read segmentVideoFrames.ts and the stage diff end to end, plus the tests. I also traced the engine's BeforeCaptureHook callers: self-verify, prepareFrameForCapture, motion-blur accumulation and deferred drawElement init. CI doesn't run on stacked PRs. The dispatched run 42039548198 on the top branch, 1768fb8, includes this diff and is green.
— Genesis (Claude)
|
|
||
| /** Extracts the given output frames into `dir` and returns an injector over them plus the fully extracted videos. */ | ||
| const injectorFor = async (frames: number[], dir: string): Promise<BeforeCaptureHook | null> => { | ||
| const sliced = await extractFrames({ |
There was a problem hiding this comment.
important: Windowed extraction has no transient retry. Flag off, every ffmpeg extraction runs inside runVideoExtractionWithRetry, and so does extractAllDeferredFrames in #7242. These per-segment and on-demand calls don't. A long render makes about one call per video per segment, plus one per self-verify sample on every session open, all while the workers' Chromes are running. One EAGAIN/EMFILE (ffmpeg_transient) or download_transient on any of them propagates: retryAfterTargetLoss rethrows anything that isn't a target loss, so the render fails at segment N. The calibration forFrames call in #7242 also runs before its try, so the same error there kills a render that calibration would otherwise only downgrade to a conservative worker budget.
Fix: wrap this call in runVideoExtractionWithRetry({ signal, maxTransientRetries, onRetry: () => { rmSync(dir, …); mkdirSync(dir, …) } }), passing maxTransientRetries in from the orchestrator as resolveVideoExtractionPolicy().maxTransientRetries. That covers prepare, on-demand and forFrames together. Add one stage test where the stubbed extractor throws a retryable VideoSourceExtractionError once.
The base branch was changed.
…letes them when it closes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… prepared window Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
79072a0 to
920661f
Compare
Edit accuracy: accurate 267 (base branch 267), smooth 97 of thoseThe gate passes. Quarantined, measured but not gated (8)
Unstable (1)
|
…view Adopts heygen-com#7240 (deferred frame extraction leaves the distributed code), heygen-com#7241 (a capture segment extracts and deletes its own frames), heygen-com#7255 (segmented and sequential capture check drawElement samples), heygen-com#7254 (normalize-audio --reference stops short of the peak ceiling), heygen-com#7256 (engine names a failed script's origin first), heygen-com#7258 (SVG gradient text judged by its stops) and heygen-com#7242 (windowed source frames, off unless HF_VIDEO_FRAME_WINDOW=true). Release v0.9.17 is not synced wholesale; the producer packed budget takes upstream's +12000 from this range. Watermark advances to 32eb4c3. Co-authored-by: Vance Ingalls <vance@heygen.com> Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
An optional stage input,
segmentVideoFrames. When it's present, each capture segment extracts only the source frames it shows into<workDir>/segment-frames/segment_NNNNN/, deletes them when it closes, and the stage deletes segment files after a successful join. Nothing sets it yet: the routing is the next PR, so no render changes here.Why
Part 2 of 3. See the last PR for the whole picture.
How
prepareswaps in an injector over that segment's frames, andreleaseremoves the folder on success, failure and abort.frameCapture.tsand stored black video boxes. Note thatcaptureSegmentedStagedoes not itself compare drawElement frames with that ground truth, which predates this stack, so what this protects today is the arming path and any later check. So the hook extracts each sampled frame, injects it and deletes it, and carriesfresh()for the isolated truth page.frameCapture.tsis unchanged.prepare, and progress saysReading video for segment N/M, so slow seeks neither trip it nor look frozen.Test plan
segmentVideoFrames.test.ts, with a stubbed extractor.validateCompletedSegments.🤖 Generated with Claude Code