Skip to content

3.13.1 — Embedded ASS subtitle feed keeps up on packet-dense tracks

Choose a tag to compare

@superuser404notfound superuser404notfound released this 22 Jun 11:59

Fixed

Embedded ASS subtitle feed fell behind playback on packet-dense tracks (#56)

When a host opts into raw ASS cue delivery (LoadOptions(preserveASSMarkup: true)) and the active embedded subtitle track packs many events onto the same (or nearly the same) timestamp, on-screen subtitles rendered early and then stopped. The embedded subtitle side reader published every decoded event through its own awaited MainActor.run hop, so on a packet-dense track those per-event hops serialized the demux loop against the host's on-MainActor ASS renderer. Demux throughput then collapsed to the MainActor scheduling rate and the published subtitleCues fell far behind the playhead. In the reported sample (Ex1.mkv), the "Dialogue" track stacks 1534 ASS events on a single 5.207 s timestamp (and 1735 on another), which is exactly the cluster the reader was choking on.

Decoded events are now coalesced and flushed to the MainActor in a single hop once the batch spans a short window of source time, or reaches a count cap:

  • The window rule keeps a sparse track flushing per event, so normal dialogue gains no latency.
  • The count cap is the decisive throttle for a same-timestamp burst (its source-time span stays zero, so the window rule never trips). It turns that 1534-event cluster into roughly a dozen MainActor hops instead of 1534, and the demuxer streams freely between flushes.

The flush also fires before the reader parks at the read-ahead horizon and at end of stream; a real track switch / seek / stop still drops the trailing batch through the existing cancellation guard. The native tx3g (mov_text) reader added in 3.13.0 already wrote cues to an off-actor store and is unaffected.

The flush decision (shouldFlushSubtitleBatch) is pure and covered by SubtitleBatchFlushTests.

Thanks to @edde746 for the precise report and the reproduction samples.

Full diff: 3.13.0...3.13.1