Skip to content

6.3.0 - External subtitle tracks can address a container's Nth stream

Choose a tag to compare

@superuser404notfound superuser404notfound released this 31 Jul 08:41

An external subtitle URL does not have to be a sidecar. It can be a container holding several subtitle streams, and a track can now name which one it means.

Added

  • ExternalSubtitleTrack.sourceStreamIndex, an absolute AVStream index inside the container at the track's url. A host that registers one track per embedded stream of the same MKV (English, English SDH, Spanish) previously got three selectable tracks all rendering the same cues: SubtitleDecoder.decodeFile stopped at the container's first AVMEDIA_TYPE_SUBTITLE stream and the descriptor carried no index to say otherwise (#266).

    The index is absolute, matching the convention that embedded track ids are stream indices, not an ordinal over the subtitle streams. nil keeps decoding the container's first subtitle stream, so every existing registration behaves exactly as before. An index that is out of range or names a non-subtitle stream throws SubtitleDecoderError.streamIndexNotSubtitle rather than falling back, because a silent fallback would be indistinguishable from leaving the field nil, which is the behaviour the index exists to escape.

    Honoured on both selection channels, primary and the companion secondary track, and on the native WebVTT rendition fill for load-declared tracks. Note that TrackInfo.codec is still derived from the URL extension, so a container URL reports subrip; a host driving a styled ASS renderer should set formatHint: "ass" on such tracks. Requested by edde746.

Changed

  • External tracks sharing a container are filled from a single pass over it. Each load-declared external track used to get its own whole-file read, so three tracks pointing at one MKV meant three full downloads at load. Discarding the unwanted streams would not have helped: a Matroska demuxer reads every discarded byte anyway, so only a single pass actually saves the bytes. Tracks sharing a URL and headers are now decoded together, one stream decoder per requested stream, each with its own timing anchor, ASS play resolution and open-composition bookkeeping.

    A pass covering several streams fails as a whole, so a failure retries the targets individually and one host-side index mistake cannot blank the container's other tracks. A store that still could not be filled stays unfinished rather than serving a complete but blank rendition.

    SubtitleDecoder.decodeFile gained a variant taking several stream indices and returning positionally, so a caller maps results back onto its own targets without having to resolve what a nil entry became.

Upgrading

.package(url: "https://github.com/superuser404notfound/AetherEngine", from: "6.3.0")

Source-compatible. ExternalSubtitleTrack's new field is the last initializer parameter and defaults to nil, which is the pre-6.3.0 behaviour, so existing registrations need no change. Hosts that resolve external subtitles from a container URL can now register one track per stream instead of one track per file.