5.28.0 - Side reader link priority
The subtitle side reader and the video pump were competing for the same link, and on a link with little headroom the video path lost. Reported by cmcpherson274 (#240) with per-seek timings from a real device.
Fixed
-
Far seeks stop competing with the subtitle side reader for the source link. On Matroska a subtitle-only side reader is a second full copy of the stream:
matroska_parse_clusterreads every block off the wire and onlymatroska_parse_blockthen honours the discard flag, so a session with subtitles on asks the link for roughly twice the media rate (2.6x measured in #220). Above about 2x headroom nobody notices. At 1.3x to 1.5x, an ordinary Wi-Fi bench in front of a high-bitrate remux, the two readers split the link and the video path misses its deadlines: the reporter measured the same segment serving in 2.2 s alone and 7.5 s alongside the prefetcher, which expired the seek landing budget, after which the recovery re-anchored, the clock jumped, the jump rebuilt the prefetch session, that took more link, and landings stacked to 25 s.The video path has priority now, as a rule rather than a share, because playback is load-bearing and subtitle lookahead is not. A seek in flight owns the link outright. A pump that is fetching outranks a side reader. A parked pump, which on a link with headroom is nearly all of the time, leaves the link to it. Two bounded escapes keep this from becoming a mute switch: a grace window after each anchor, so a freshly selected track fills even while the pump is busy, and a cap on continuous yielding, so a pump that never parks cannot silently disable lookahead for the rest of a session.
-
A playhead jump re-anchors the running prefetch session in place instead of rebuilding it. A rebuild pays a fresh demuxer open, the Matroska cue-index prewarm and a positioning seek, and since the bounded ranges of 5.24.0 each of those seeks takes a full range off the link, once per jump, on exactly the constrained link where a seek is already struggling. The running session already holds an open, positioned demuxer. Positioning is one shared function for both paths now, so an in-place move cannot drift from the session-start rules (#234).
Measured on a shaped bench (900 s Matroska at 8 Mbit/s, one SRT track, all connections sharing 1.4x the media rate, five far seeks 25 s apart, two runs per build): far-seek landings 23.5 s to 12.7 s at the median, source connections 35 to 21, and the side reader's share of the delivered bytes roughly halved. What remains is transfer geometry on a link that thin, not arbitration.
Added
- Per-reader link attribution in the log. Every
AVIOReadercarries a label (pump,prefetch,nativesubs,extract), the connection-start line names it and reports its range length, and that line is no longerDEBUG-only. The 30 s memprobe reportspumpFetchedMBnext toprefFetchedMB, plus the prefetcher's live state and cumulative link yield. Several readers against one origin were previously indistinguishable in a field log, and one reader walking forward in bounded ranges reads like several concurrent connections when nothing names it. aetherctl play --seek-pattern a,b,cwalks a list of absolute far-seek targets, one per--seek-everytick, and prints how long eachseek(to:)took. The existing 6 s backward hop lands in the segment cache and never restarts the producer, so it exercises none of the machinery a far seek does.Scripts/throttle-origin.py --sharedshapes the sum of all connections instead of each one, which is what a real link does. With per-connection shaping two readers each get the full rate, so a contention defect cannot reproduce under it at all.--head MBsets how much of each body passes unshaped; set it to 0 when measuring a reader that fetches in bounded ranges.
No API changes. Hosts that drive HLSVideoEngine directly, without an AetherEngine, are unaffected: no gate is set, so the side readers behave exactly as before.