mux: fix DVD subtitle/audio track collision, PGS/VobSub flush, unify TS codec table

Subtitle/DVD output-corruption + stream-mapping coverage fixes.

1. DVD subtitle/audio track-mapping collision (CRITICAL). The PS path
   routed 0xBD private-stream packets to a track via (sub_id & 0x1F)+1,
   so VobSub subtitle sub-id 0x20+j aliased audio track j+1: subtitle
   PES was fed to the AC-3 parser and the real subtitle track got
   nothing. Route by the canonical DVD PID instead via a new
   PsPacket::dvd_pid() that mirrors scan_dvd_titles' PID assignment
   (video 0xE0, audio 0xBD00+i, subtitle 0x20+j), then look up the
   track in pid_to_track. Fixed identically at all three sites
   (pipelined_stream consume_ps, disc.rs live feed, disc.rs EOF flush).
   Unmappable/unmapped packets now WARN instead of silently dropping.

2. PGS flush() missing. PgsParser inherited the no-op default flush, so
   the last subtitle of every PGS track (emitted only when a following
   PCS arrives) was dropped at EOF. Implemented flush() to drain the
   pending display set (duration_ns: None for the trailing block).

3. DVD VobSub multi-PES SPU not reassembled. A subpicture unit larger
   than one PES spans multiple PES (only the head carries a PTS).
   DvdSubParser is now stateful: it buffers per sub-stream until the
   leading 2-byte SPU_size is satisfied, inherits the head PTS, and
   emits one Frame. flush() drains a truncated trailing SPU at EOF.

4. One-table hygiene. scan_streams had a duplicate stream_type->Codec
   table that had drifted from Codec::from_coding_type (missing 0x80
   LPCM, 0x85 mapped to DTS-HD MA vs HR, etc.). scan_streams now uses
   from_coding_type plus a new Codec::kind()/CodecKind category split,
   so the two mappings can never diverge. Silent drops in
   scan_streams and bluray STN parsing now WARN with PID + type.

Tests: dvd_pid mapping + subtitle/audio collision regression, PGS
final-subtitle flush, VobSub multi-PES reassembly + EOF flush,
scan_streams 0x80 LPCM via from_coding_type.
This commit is contained in:
MattJackson
2026-06-06 21:33:11 -07:00
parent 7d58ba7b08
commit cfc12774f2
8 changed files with 519 additions and 152 deletions
+10 -2
View File
@@ -156,8 +156,16 @@ impl Disc {
qualifier: crate::disc::LabelQualifier::None,
codec_data: None,
})),
// Stream type 4 = IG, unknown types -- skip
_ => None,
// Stream type 4 = IG, unknown types -- skip.
other => {
tracing::warn!(
"dropping STN stream entry: unhandled stream_type {} (PID {:#06x}, coding_type {:#04x})",
other,
s.pid,
s.coding_type,
);
None
}
}
})
.collect();
+35 -1
View File
@@ -522,7 +522,7 @@ impl Codec {
("ssa", "SSA", Codec::Ssa),
];
fn from_coding_type(ct: u8) -> Self {
pub(crate) fn from_coding_type(ct: u8) -> Self {
match ct {
0x24 => Codec::Hevc,
0x1B => Codec::H264,
@@ -540,6 +540,40 @@ impl Codec {
ct => Codec::Unknown(ct),
}
}
/// Broad stream category for a codec. Used by demuxers to decide
/// whether a PMT/STN entry becomes a video, audio, or subtitle
/// `Stream` without duplicating per-codec knowledge.
pub fn kind(&self) -> CodecKind {
match self {
Codec::Hevc | Codec::H264 | Codec::Vc1 | Codec::Mpeg2 | Codec::Mpeg1 | Codec::Av1 => {
CodecKind::Video
}
Codec::TrueHd
| Codec::DtsHdMa
| Codec::DtsHdHr
| Codec::Dts
| Codec::Ac3
| Codec::Ac3Plus
| Codec::Lpcm
| Codec::Aac
| Codec::Mp2
| Codec::Mp3
| Codec::Flac
| Codec::Opus => CodecKind::Audio,
Codec::Pgs | Codec::DvdSub | Codec::Srt | Codec::Ssa => CodecKind::Subtitle,
Codec::Unknown(_) => CodecKind::Unknown,
}
}
}
/// Broad category of a [`Codec`] — video / audio / subtitle / unknown.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CodecKind {
Video,
Audio,
Subtitle,
Unknown,
}
impl std::fmt::Display for Codec {