libfreemkv: rc.5.1 DVD correctness fixes

- CSS: unlock scrambled-sector reads on enforcing drives via bus-auth
  only; classify sense 6F/03 as CSS-locked; early-bail on a fully locked
  scan; gate the AACS handshake off DVD discs.
- DVD first-play menu no longer prepended to the feature: read the title
  VOBS base from vtstt_vobs (0xC4), not the menu VOBS vtsm_vobs (0xC0).
- Interlaced field-duration (DefaultDecodedFieldDuration) written as a
  direct TrackEntry child rather than inside Video, so Windows reports
  the correct frame rate.
- Audio channel count read from the AC-3 bitstream; FieldOrder set to
  TFF; per-track BPS tags.
- Structured disc diagnostics at --log-level 3; reduced per-operation
  log spam.
This commit is contained in:
Matthew Jackson
2026-06-24 14:34:55 -07:00
parent 315276dd13
commit 6592f2a590
18 changed files with 1938 additions and 120 deletions
+40 -12
View File
@@ -161,6 +161,10 @@ pub struct DiscStream {
halt: Option<Halt>,
event_fn: Option<Box<dyn Fn(Event) + Send>>,
eof: bool,
/// Count of dropped DVD navigation packets (private_stream_2, 0xBF) — these
/// are expected on every disc; tallied and summarised once at EOF instead of
/// a per-packet WARN.
dropped_nav_packets: u64,
// Cumulative bytes successfully read from the source. Drives
// EventKind::BytesRead emission and autorip's per-device progress.
@@ -284,6 +288,7 @@ impl DiscStream {
halt: None,
event_fn: None,
eof: false,
dropped_nav_packets: 0,
bytes_read_total: 0,
bytes_total_extents,
ts_demuxer,
@@ -578,6 +583,13 @@ impl crate::pes::Stream for DiscStream {
let t0 = self.profiling.then(std::time::Instant::now);
if !self.fill_extents()? {
self.eof = true;
if self.dropped_nav_packets > 0 {
tracing::debug!(
target: "mux",
"dropped {} DVD navigation packets (private_stream_2/0xBF) — expected, carry no elementary stream",
self.dropped_nav_packets
);
}
// Flush demuxer — last PES packet may still be in the assembler
if let Some(ref mut demuxer) = self.ts_demuxer {
for pes in &demuxer.flush() {
@@ -603,12 +615,20 @@ impl crate::pes::Stream for DiscStream {
// pipelined_stream.rs); the old (sub_id & 0x1F)+1
// heuristic mis-routed VobSub into the AC-3 parser.
let Some(pid) = ps.dvd_pid() else {
tracing::warn!(
target: "mux",
"dropping unmappable PS packet (stream_id={:#04x}, sub_stream_id={:?})",
ps.stream_id,
ps.sub_stream_id,
);
if ps.is_nav() {
// Expected DVD navigation packet (PCI/DSI) —
// tally, no WARN.
self.dropped_nav_packets += 1;
} else {
// Unexpected unmappable stream_id (a
// possibly-dropped real stream). Keep the WARN.
tracing::warn!(
target: "mux",
"dropping unmappable PS packet (stream_id={:#04x}, sub_stream_id={:?})",
ps.stream_id,
ps.sub_stream_id,
);
}
continue;
};
let Some((_, track)) =
@@ -714,12 +734,20 @@ impl crate::pes::Stream for DiscStream {
// pipelined_stream.rs); the old (sub_id & 0x1F)+1
// heuristic mis-routed VobSub into the AC-3 parser.
let Some(pid) = ps.dvd_pid() else {
tracing::warn!(
target: "mux",
"dropping unmappable PS packet (stream_id={:#04x}, sub_stream_id={:?})",
ps.stream_id,
ps.sub_stream_id,
);
if ps.is_nav() {
// Expected DVD navigation packet (PCI/DSI) — tally,
// no WARN.
self.dropped_nav_packets += 1;
} else {
// Unexpected unmappable stream_id (a possibly-dropped
// real stream). Keep the individual WARN.
tracing::warn!(
target: "mux",
"dropping unmappable PS packet (stream_id={:#04x}, sub_stream_id={:?})",
ps.stream_id,
ps.sub_stream_id,
);
}
continue;
};
let Some((_, track)) =