Skip to content

4.0.3

Choose a tag to compare

@superuser404notfound superuser404notfound released this 25 Jun 07:18

Fixed

Subtitles could freeze the scrub-preview (trickplay) thumbnails (#27)

Reported by @cstark27. With subtitles on, the scrub-preview thumbnails would freeze on a single frame (or update only sporadically) while scrubbing; with subtitles off they tracked the scrub smoothly. It was most visible on interlaced 480p MPEG-2 on an Apple TV 4K (3rd gen).

Root cause was on the engine side and had two parts:

  • The freeze. On-device scrub thumbnails are produced by a separate still-extraction pipeline that opens its own connection to the source and runs on a single serial decode queue. For a remote source its chunk read could park on a flat ~35s timeout (up to several retry passes) with no way to cancel it. The FrameExtractor's cancel token was only checked between decoded packets, never inside the network read, so one stalled read froze the serial queue and every superseding scrub queued behind it, pinning the preview on the last decoded frame.
  • Why subtitles triggered it. Enabling subtitles spins up a third FFmpeg/HTTP context (the subtitle side-demuxer), opened with the persistent playback profile and a 90-second read-ahead. It competes with the thumbnail reader for the source's bandwidth and the device's cores, lengthening the thumbnail reads into the park. With subtitles off there is no third reader, the reads return promptly, and supersession works. Interlaced MPEG-2 made it worse because that codec is software-decoded, so playback already held the cores.

The fix, scoped strictly to the still-extraction path (playback and live read paths are untouched):

  • A still chunk fetch now aborts within ~100ms when a scrub supersedes it or the extractor is torn down, instead of riding the full timeout (a new abortable semaphore wait that polls close/deadline; the seekable read path now honours both and reports a read error, not a clean EOF).
  • Each thumbnail decode is bounded by a short (8s) read deadline, and a stalled still fetch fails fast (one retry instead of three across two URLs).
  • The thumbnail decoder is capped to two threads at .utility QoS (was every core at .userInitiated), so it yields to the real-time software playback decode instead of starving it.

No public API change.

On the bonus question about server-side trickplay: pulling Jellyfin's pre-generated trickplay tiles would indeed be faster wherever they exist (a tile is a single cached JPEG, no demux, seek, or decode), and "prefer server tiles, fall back to on-device extraction" is a planned host-side follow-up in Sodalite. This engine fix lands first so libraries without server tiles also stop freezing.

Dead live remote-HLS streams froze silently instead of retuning

When a live IPTV/HLS source stopped delivering segments (segment 404s or an expired auth token), the native player's failedToPlayToEnd was only logged and the item stayed readyToPlay, so no terminal error reached the host and the automatic live retune never fired. Remote-HLS failedToPlayToEnd is now routed through deferred-confirmation into a terminal error (gated to remote-HLS live only), so the host's live retune kicks in.

Diagnostics

  • A positive content-vs-clock ledger and a VOD backpressure-wedge probe were added to keep instrumenting the #65 post-seek-burst frame-drift investigation.

Compatibility

Patch release. Source-compatible with 4.0.x; no API changes. SwiftPM from: adopters get it on the next resolve. 115 tests green, strict-concurrency build clean.