Fix PGS subtitle misclassified as audio in STN parsing

When MPLS STN table parsing drifts (disc-specific alignment issue),
a PGS subtitle entry (coding_type 0x90/0x91) can appear in the audio
stream section. Previously this showed as garbled "ng PGS 5.1" audio.

Fix: guard in stream builder checks if audio-typed streams have
subtitle codecs and reclassifies them as subtitles.

Also: unknown stream types now filtered out (filter_map) instead of
creating fake Video entries that showed as "?" in output.

Tested on V for Vendetta BD — "ng PGS 5.1" gone, clean output.
This commit is contained in:
MattJackson
2026-04-08 21:14:39 -07:00
parent 79b1b4d5b5
commit 71a21b5c6f
+23 -18
View File
@@ -671,10 +671,10 @@ impl Disc {
} }
// Build streams from STN table // Build streams from STN table
let streams: Vec<Stream> = parsed.streams.iter().map(|s| { let streams: Vec<Stream> = parsed.streams.iter().filter_map(|s| {
let codec = Codec::from_coding_type(s.coding_type); let codec = Codec::from_coding_type(s.coding_type);
match s.stream_type { match s.stream_type {
1 | 6 | 7 => Stream::Video(VideoStream { 1 | 6 | 7 => Some(Stream::Video(VideoStream {
pid: s.pid, pid: s.pid,
codec, codec,
resolution: format_resolution(s.video_format, s.video_rate), resolution: format_resolution(s.video_format, s.video_rate),
@@ -694,8 +694,19 @@ impl Disc {
7 => "Dolby Vision EL".to_string(), 7 => "Dolby Vision EL".to_string(),
_ => String::new(), _ => String::new(),
}, },
}), })),
2 | 5 => Stream::Audio(AudioStream { 2 | 5 => {
// Guard: if coding_type is a subtitle codec (PGS 0x90/0x91),
// this is a misaligned stream — treat as subtitle, not audio
if matches!(codec, Codec::Pgs) {
Some(Stream::Subtitle(SubtitleStream {
pid: s.pid,
codec,
language: s.language.clone(),
forced: false,
}))
} else {
Some(Stream::Audio(AudioStream {
pid: s.pid, pid: s.pid,
codec, codec,
channels: format_channels(s.audio_format), channels: format_channels(s.audio_format),
@@ -703,23 +714,17 @@ impl Disc {
sample_rate: format_samplerate(s.audio_rate), sample_rate: format_samplerate(s.audio_rate),
secondary: s.stream_type == 5, secondary: s.stream_type == 5,
label: String::new(), label: String::new(),
}), }))
3 => Stream::Subtitle(SubtitleStream { }
}
3 => Some(Stream::Subtitle(SubtitleStream {
pid: s.pid, pid: s.pid,
codec, codec,
language: s.language.clone(), language: s.language.clone(),
forced: false, // TODO: parse from MPLS stream attributes forced: false,
}), })),
_ => Stream::Video(VideoStream { // Stream type 4 = IG, unknown types — skip
pid: s.pid, _ => None,
codec,
resolution: String::new(),
frame_rate: String::new(),
hdr: HdrFormat::Sdr,
color_space: ColorSpace::Unknown,
secondary: false,
label: String::new(),
}),
} }
}).collect(); }).collect();