Files
libfreemkv/docs/mpls-universal.md
T
Matthew Jackson 6e14fc0c0c libfreemkv: 1.7.0 groundwork — sector-recycle soundness + CI hardening
Security
- Remove the unsafe Vec::set_len over recycled sector buffers — UB reachable
  from safe code (GHSA-j8ww-f5fg-9pmh, low). Uses Vec::resize; pooling unchanged.

CI / tooling
- clippy on stable with the MSRV single-sourced from Cargo.toml; cargo-deny
  dependency-audit gate with first-party git sources allowed (#15); audience-based
  comment-guard (#17).

Docs
- README (keydb ownership, BD-J parser count), drive-access transport/reset
  notes, mux timeline module-doc links.
2026-09-02 12:40:55 -07:00

4.9 KiB

src/labels/mpls_universal.rs

Universal MPLS-based stream labels — the confidence-tier "floor" for the labels registry.

Why this module exists

Unlike the framework-specific parsers in src/labels/ (dbp, pixelogic, ctrm, criterion, ...), this module is the floor: every Blu-ray ships with MPLS playlists under /BDMV/PLAYLIST/, and every MPLS file has an STN table with per-stream ISO 639-2 language codes plus coding-type / channel-layout / sample-rate bytes from the BD spec.

The framework parsers extract richer editorial labels ("English Dolby Atmos", "Director's Commentary") when the disc was authored with a recognized tool. When none of them match (e.g. a "no BD-J" disc, or an authoring framework we haven't catalogued), MPLS still gives us language + codec on every stream — enough to render something more useful than the bare PID.

Output confidence is Low: MPLS carries language + codec but never purpose/qualifier info (no way to tell "Commentary" from "Normal" from the STN table alone). Higher-confidence framework parsers, when present, always win on the registry's max-by-confidence tiebreaker — MPLS is only chosen when nothing else matched.

build_labels

Converts every stream entry across playlists into one StreamLabel per physical stream. Factored out of parse so unit tests can drive the actual conversion logic (stream-type mapping, identity, slot numbering) directly from already-parsed crate::mpls::Playlist values, without needing a synthetic on-disc UDF image.

Identity is (clip, PID) — what the STN entry states — and it is both the dedup key and the label's StreamId. A stream twenty playlists list is one label; two clips that both open their first audio at 0x1100 are two. This replaced a disc-global dense counter that numbered surviving entries 1, 2, 3, … in playlist-directory order: that number was not an STN slot in anything, but it was handed to a binder that reads stream_number as one.

label_type_for

Which per-type numbering list an STN entry belongs to, or None when it is not a labellable stream at all.

This MUST agree with the stream list disc::bluray builds from the same entries, because that list is what labels::apply_labels counts against when it binds stream_number. The two counters run over the same STN entries in the same order, so any entry one side keeps and the other drops — or files under a different type — shifts every later label of that type onto the wrong stream. Three rules, all mirroring disc::bluray:

  • coding_type == 0 is the STN table's empty/padding slot. Not a stream on either side.
  • a PG coding_type in an audio STN slot is a subtitle, not audio. mpls::parse_stream_entry has a dedicated arm for this layout, so it is an authored shape rather than a corruption.
  • video (1 / 6 / 7 = primary, secondary, Dolby Vision EL) and IG (4) have no StreamLabelType; they are numbered in their own STN lists and never interleave with the audio or PG lists.

Test helpers and fixtures

playlist_with: a playlist over clip "00001". Playlist::streams is read out of the first play item's STN table, so a playlist that has streams always has a play item to have read them from — the fixture carries one so tests exercise the shape production sees, and so each label gets the (clip, PID) identity it is bound by.

labels_from_playlists: drives the actual production conversion logic (build_labels, the function parse() calls) starting from already-parsed Playlists, so tests don't have to synthesize valid on-disc MPLS/UDF bytes. This calls the real code under test rather than a hand-written re-implementation, so mutations inside build_labels (stream-type mapping, dedup key, counters) are actually caught here.

padding_stn_entry_does_not_consume_a_label_slot: stream_number is bound by labels::apply_labels against the title's own stream list, which disc::bluray builds from these same STN entries. That builder DROPS an entry whose coding_type is 0 — the STN table's empty/padding slot — so it must not be counted here either. Counting it advances the audio counter past a stream that never materializes, and every label behind it binds one stream late.

pg_coding_type_in_an_audio_slot_counts_as_a_subtitle: a PG coding_type sitting in an audio STN slot is a real, documented shape — mpls::parse_stream_entry has an explicit arm for it, and disc::bluray builds it as a Subtitle stream, not an Audio one. This module must classify it the same way, or the audio counter runs one ahead and the subtitle counter one behind for every later stream.

same_pid_in_two_clips_is_two_streams: the same PID in two DIFFERENT clips is two different streams — a PID is only unique within one clip. Deduping on the PID alone (as the old key's (type, language, codec_hint, pid) did across clips) collapses them into one label, and the second clip's stream is then described by the first clip's.