Repository navigation
fix(producer): extract HDR video frames a window at a time to bound scratch disk - #6304
Conversation
There was a problem hiding this comment.
Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits · head cd8b174d
The windowed store and lease/eviction look right to me, and the shared scratch is safe because nothing awaits after the readSync. One blocker, inline: a looped source's cycle length is now an estimate, and it gets corrected late.
Scope
I read all non-test changes: hdrFrameWindows.ts, captureHdrResources.ts, and the hdrCompositor.ts blit/close. CI was still running when I posted. I did not run the 5 min render.
Edit accuracy: accurate 271 (base branch 271), smooth 113 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
cd8b174 to
a255b65
Compare
There was a problem hiding this comment.
Verdict: REQUEST CHANGES — 0 resolved, 1 open, 0 new · cd8b174d → a255b65e. The looped-source frame count is still ceil(duration*fps - firstTick) (captureHdrResources.ts:478). Setup still leases only window 0, so the loop modulus is corrected lazily, as in the open thread.
6cb995f to
e6cee60
Compare
There was a problem hiding this comment.
Verdict: REQUEST CHANGES — 0 resolved, 1 open, 0 new · a21d677a → e6cee608. The blit split and the propagation of extraction failures look fine. The looped-source frame count (captureHdrResources.ts:479) is still an estimate corrected lazily after only lease(0) (L523), per the open thread.
e0760d6 to
1fbdacd
Compare
… disk stays bounded
…en a window cannot be extracted
…raction's measured delta
1fbdacd to
1a9281b
Compare
Window slots counted from the first decoded frame, so a video stream that starts after its audio played early by its lead. Slots now count from the extraction start and show the first frame until the stream begins, as they did before windowed extraction (#6304) and as Chrome does. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…one frame (heygen-com#6575) * fix(producer): stop HDR video windows after the first from repeating one frame A raw HDR window seeks to a whole second, then trims its lead-in frames. trim keeps their timestamps, and the raw muxer writes none, so when the input has an audio track FFmpeg's default CFR sync pads from pts 0 with copies of the window's first frame and -frames:v cuts the real ones off. Phone footage always has audio, so HLG clips rendered at ~half their frames. Pass frames through as the filter graph emits them. Fixes heygen-com#6556 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> * fix(producer): hold the first frame until a delayed HDR video starts Window slots counted from the first decoded frame, so a video stream that starts after its audio played early by its lead. Slots now count from the extraction start and show the first frame until the stream begins, as they did before windowed extraction (heygen-com#6304) and as Chrome does. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> * test(producer): add an HDR fixture whose clips carry audio and span extraction windows Neither HDR fixture had an audio track, which is how heygen-com#6556 shipped. Window A checks frames after the first extraction window are not repeats; window B checks a video stream that starts 0.5 s after its audio holds its first frame until the picture starts. The baseline was generated in Docker and the fixture fails against main. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
A long HDR clip no longer needs the whole clip's raw frames on disk at once, so a 5 minute HLG video renders instead of stopping at the disk-space check.
Cause:
extractHdrVideoFrameswrote every frame of each HDR video as raw 16-bit RGB before the first frame was captured: 6 bytes per pixel per frame. 5 minutes at 30 fps and 1080p is 9000 frames x 12.4 MB = 112 GB. The headroom check then refuses it (draft quality changes nothing, extraction does not depend on it).Fix: each video is cut into windows of about 512 MB (43 frames at 1080p). A window is extracted with one FFmpeg pass when the capture first reaches a frame in it, the next one starts half way through, and least-recently-used windows are deleted once more than workers + 1 exist. Scratch disk is that bound, not the clip length. Frames are read through a lease that pins a window while a frame is read, so parallel capture workers cannot evict each other's window.
Frame accuracy: every window runs on the clip's own tick grid. The seek lands on a whole second before the window,
fpsis pinned to the clip's first frame offset (probed once), and the lead-in frames are trimmed. Checked against the old whole-file pass byte by byte at every frame, window boundaries included, on a 5 minute 10-bit HLG clip (mediaStart 3.37 and 0, 43-frame windows) and a 24 fps clip (three start offsets): 0 mismatches of about 1200 frames each. The naive per-window seek is wrong on 24 to 30 fps (478 of 1199 frames), which is why the grid is pinned.One behaviour change: a variable frame rate source now maps each output frame to the nearest source frame. The old pass (
-r) carried timing drift from earlier frames that a window cannot replay (171 of 1200 frames in the VFR fixture differed, always the neighbouring source frame). The windowed output is identical between windows and a single whole-file pass.Measured on a 1080p 10-bit HLG clip, draft render, peak extra disk during the render:
Tests: window store (extract on demand, bounded resident windows, a leased window is not evicted, short source and end-at-boundary hold the last frame, failed extraction retries, close removes files), the FFmpeg arguments, and a long clip held in at most two windows. The two bound tests fail with eviction disabled. 50 tests pass three runs in a row.
Package size: producer packed budget raised by 2389 bytes (768601 to 770990), exactly this change's measured delta on a linux pack against current main; the bytes buy HDR scratch of 112 GB down to about 3 GB for a 5 minute clip. The code lands in both producer bundles; prefetch of the next window was left out because the 5 min render was 29m 17s with it and 30m 01s without.
Stands alone.