render: fix 4K playback memory growth and decode-to-target-size
Root causes found for the 4K stalls and the second-footage memory blowup (audit + code review): - ticket bookkeeping leaked unbounded: the procpool ticket table and the arena slot map only ever grew (50-100 tickets/sec during playback, each pinning montage params and shm region views). Completed/cancelled/superseded/crashed entries are now removed, and the arena reaps fire-and-forget tickets once finished; the sync poll path reaps via a terminal result() read. InFlight duplicate submits now answer State immediately instead of sitting in the map forever. - decode ran a full-resolution swscale to F32 RGBA (~132 MB at 4K) plus a second full-res copy before downscaling to the 480px proxy: RetrieveVideoParams.target_size lets swscale convert AND resize in one pass (bilinear, matching the old Rust resampler), so a 4K preview frame costs ~1 MB instead of ~260 MB of churn. This applies to proxy AND full-res requests alike. - per-process decoder cache was unbounded (each session pins an FFmpeg context + 2 native decoded frames): LRU-capped at 16, eviction drops the map entry (in-flight renders keep their Arc; Drop releases FFmpeg). - playback window completions were not generation-gated: a stale render from before an edit landed in the rebuilt window (wrong frame displayed, fresh request blocked). Stale completions now return their shm slot credit instead. - async audio prefetch used the polling ticket submit without ever polling: switched to the fire-and-forget submit so entries reap.
This commit is contained in:
@@ -136,6 +136,13 @@ pub struct RetrieveVideoParams {
|
||||
pub mode: RenderMode,
|
||||
/// Frame alpha channel is premultiplied.
|
||||
pub alpha_is_premultiplied: bool,
|
||||
/// Target output size for the scaled frame: `Some((w, h))` lets the
|
||||
/// decoder's swscale pass convert AND resize in one step (native
|
||||
/// yuv → RGBA/F32 at the target size), skipping the full-resolution
|
||||
/// float intermediate (a 4K frame is ~132 MB as F32 RGBA — decoding
|
||||
/// to a 480px preview through it costs ~260 MB of churn per frame).
|
||||
/// `None` keeps the native size (the old behavior).
|
||||
pub target_size: Option<(u32, u32)>,
|
||||
}
|
||||
|
||||
/// `Decoder::RetrieveAudioStatus` — outcome of an audio retrieve.
|
||||
@@ -708,6 +715,7 @@ mod tests_unimplemented {
|
||||
image_sequence_number: 0,
|
||||
mode: RenderMode::Offline,
|
||||
alpha_is_premultiplied: false,
|
||||
target_size: None,
|
||||
};
|
||||
assert!(d.retrieve_video_frame(&p).is_err());
|
||||
assert!(d.retrieve_video(&p).is_err());
|
||||
|
||||
Reference in New Issue
Block a user