labels/mpls_universal: dense stream numbering across playlists

Per-playlist stream_number counters were resetting between MPLS
files, so a disc with 2 MPLS files each listing the same 8 audio
streams produced labels with stream_number 1..8 then 1..8 again
(dedup kept whichever PID was different, leaving the numbering
visibly broken — multiple "audio1: eng" rows).

Move the counters outside the per-file loop and increment only
when an entry survives dedup. Surviving entries now get dense
1..N numbering across the whole disc per stream_type.

Verified on corpus disc-02 (HDMV-only): was `audio1, audio1, audio1`
for the 3 distinct audio codecs (TrueHD/AC-3/DTS-HD MA), now
`audio1, audio2, audio3`. Same fix applies to disc-01 (12 audio
streams across multiple MPLS) and disc-09 (14 audio streams).
This commit is contained in:
MattJackson
2026-05-10 20:58:33 -07:00
parent 764230b1eb
commit 5ee28c08b9
+20 -18
View File
@@ -68,6 +68,15 @@ pub fn parse(reader: &mut dyn SectorReader, udf: &UdfFs) -> Option<ParseResult>
// to share a PID across playlists with different metadata. // to share a PID across playlists with different metadata.
let mut seen: Vec<(u8, String, String, u16)> = Vec::new(); let mut seen: Vec<(u8, String, String, u16)> = Vec::new();
// Global 1-based counters keyed by StreamLabelType. Incremented
// only when an entry survives dedup, so stream_numbers are dense
// (1, 2, 3, ...) per type across the whole disc — not reset per
// playlist. A disc with 2 MPLS files that each list the same
// 8 audio streams ends up with audio_1..audio_8, not audio_1..
// audio_16 or audio_1..audio_8 with audio_1 duplicated.
let mut audio_idx: u16 = 0;
let mut sub_idx: u16 = 0;
for name in &mpls_names { for name in &mpls_names {
let path = format!("/BDMV/PLAYLIST/{}", name); let path = format!("/BDMV/PLAYLIST/{}", name);
let Ok(data) = udf.read_file(reader, &path) else { let Ok(data) = udf.read_file(reader, &path) else {
@@ -77,13 +86,6 @@ pub fn parse(reader: &mut dyn SectorReader, udf: &UdfFs) -> Option<ParseResult>
continue; continue;
}; };
// Per-MPLS-file 1-based counters keyed by StreamLabelType.
// The dedup pass below removes duplicates across files; the
// numbering of the *surviving* entries comes from whichever
// playlist contributed each PID first.
let mut audio_idx: u16 = 0;
let mut sub_idx: u16 = 0;
for entry in &playlist.streams { for entry in &playlist.streams {
let label_type = match entry.stream_type { let label_type = match entry.stream_type {
2 | 5 => StreamLabelType::Audio, // primary + secondary audio 2 | 5 => StreamLabelType::Audio, // primary + secondary audio
@@ -95,17 +97,6 @@ pub fn parse(reader: &mut dyn SectorReader, udf: &UdfFs) -> Option<ParseResult>
_ => continue, _ => continue,
}; };
let stream_number = match label_type {
StreamLabelType::Audio => {
audio_idx += 1;
audio_idx
}
StreamLabelType::Subtitle => {
sub_idx += 1;
sub_idx
}
};
let language = normalize_language(&entry.language); let language = normalize_language(&entry.language);
let name = language_display_name(&language); let name = language_display_name(&language);
let codec_hint = build_codec_hint(label_type, entry); let codec_hint = build_codec_hint(label_type, entry);
@@ -117,6 +108,17 @@ pub fn parse(reader: &mut dyn SectorReader, udf: &UdfFs) -> Option<ParseResult>
} }
seen.push(key); seen.push(key);
let stream_number = match label_type {
StreamLabelType::Audio => {
audio_idx += 1;
audio_idx
}
StreamLabelType::Subtitle => {
sub_idx += 1;
sub_idx
}
};
labels.push(StreamLabel { labels.push(StreamLabel {
stream_number, stream_number,
stream_type: label_type, stream_type: label_type,