Repository navigation
Conversation
…d 4:4:4 chroma Generated with [Indent](https://indent.com) Co-Authored-By: Indent <noreply@indent.com>
Two issues caused mpv @ 24 fps to stall on a 120 Hz display over a <200 ms link: 1. Server-side bandwidth cap starved pacing during bootstrap. surface_pacing_fps divided goodput_bps (seeded at 262 KB/s) by the first keyframe's frame-size estimate, yielding ~10 fps — well below the source rate — until the EWMA converged hundreds of ms later. Drop the bandwidth cap: inflight-window + outbox backpressure already handle genuinely slow links without this conservative gate. 2. Client-side decoder reconfigure orphaned in-flight VideoFrames. When an H.264 SPS changed codec string, VideoDecoder.configure() was called while frames were still queued, orphaning them — Chromium logs "VideoFrame was garbage collected without being closed" and eventually exhausts its frame pool. Queue a flush() before the reconfigure so output callbacks close pending frames first. Generated with [Indent](https://indent.com) Co-Authored-By: Indent <noreply@indent.com>
Coverage
|
|
🔗 Preview: https://blit-il0hv9crf-indent.vercel.app |
indent-zero
Bot
changed the base branch from
indent-2026-04-15-dynamic-musl-dlopen
to
main
April 17, 2026 11:33
Contributor
|
Folding into #20 — single PR for everything. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
surface_pacing_fps— use the client'sdisplay_fpsdirectly. Flow control is already provided bysurface_inflight_limit(RTT×display_fps),outbox_backpressured, andsurface_encodes_in_flight.VideoDecoderbefore re-configuring it on H.264 SPS codec-string changes, so queuedVideoFrames drain through the output callback (which closes them) instead of being orphaned.Motivation
mpv @ 24 fps on a 120 Hz display over a <200 ms link stalls after a few seconds. Two interacting problems:
Pacing underruns during bootstrap.
surface_pacing_fps = max(goodput_bps, delivery_bps) / avg_surface_frame_bytesuses a conservative 262 KB/s goodput seed. On the first keyframe the frame-size estimate jumps to ~25 KB (keyframe/4 heuristic), giving262144/25600 ≈ 10 fps— below the 24 fps source. Becausegoodput_bpsonly updates from ACKs that have traversed the RTT, it takes several hundred ms to converge on a high-latency link, long enough for mpv's Wayland frame-callback clock to stall. The inflight window + outbox backpressure already handle genuinely slow links without this cap.Orphaned
VideoFrames on reconfigure. When an H.264 SPS with a different profile/compat/level arrives,entry.decoder.configure(...)is called directly. Per WebCodecs spec,configure()on an already-configured decoder resets its internal state, dropping any queuedVideoFrames without running the output callback — they are eventually GC'd and Chromium logs "A VideoFrame was garbage collected without being closed. Applications should call close() on frames when done with them to prevent stalls." With enough orphans the decoder's frame pool is exhausted and decode stalls. Queueingflush()beforeconfigure()lets the decoder drain through the output callback (which already callsframe.close()); since WebCodecs processes control messages in order, the subsequentconfigure()anddecode()of the incoming keyframe naturally run after the flush.Testing
npx tsc --noEmitinjs/corepasses.Tag
@indentto continue the conversation here.