libfreemkv: rc.5.2 DVD test coverage — depth-aware mux, colour codes, CSS scan

Implements the rc.5.2 quick-units list from the DVD coverage audit and
corrects the "passes-but-encodes-the-bug" tests that could not
distinguish correct from wrong behaviour.

New tests (each with the bug it guards):

mux/mkv.rs
- field_duration_is_direct_trackentry_child_not_in_video: depth-aware
  check that DefaultDecodedFieldDuration (and DefaultDuration) are direct
  TrackEntry children, NOT nested in the Video master. Replaces the flat
  find_id byte-scan that passed either way. Adds master_children /
  first_track_entry depth-walking helpers.
- pal_576i_emits_bt470bg_colour_codes / ntsc_480i_emits_smpte170m_colour_codes:
  assert the actual CICP tuples written into the MKV Colour master —
  PAL (5,5,5,1) vs NTSC (6,6,6,1) — not just stream-layer ColorSpace.
- ntsc_480i_field_order_is_tff_and_encoded: pins NTSC 480i hardcoded TFF
  and its ~33.37ms/16.68ms frame/field durations, asserting the encoded
  FlagInterlaced/FieldOrder bytes (480i was never exercised before).

ifo.rs
- video_attr_absolute_bytes_pin_real_layout: drives parse_video_attr with
  HARDCODED real DVD-Video bytes (PAL/NTSC x 4:3/16:9, plus mpeg_version
  in bits 7-6) instead of v_atr_byte, so a co-edit of the shift constants
  can't re-seed the PAL-as-NTSC bug. Anchors that permitted_df bits (1-0)
  are not read as the TV system.

disc/dvd.rs
- scan_dvd_titles_lpcm_routes_to_a0_pid_range: LPCM (coding 4) → sub-id
  0xA0 → PID 0xBDA0, disjoint from the AC-3 0xBD8x space, channels kept.
- scan_dvd_titles_multiple_vobsub_tracks_distinct_pids: three VobSub
  tracks → distinct 0x20+ordinal PIDs, per-language, shared palette.

css/mod.rs
- crack_outcome_reaches_cracked_with_span: drives the full crack scan to
  CrackOutcome::Cracked via a Stevenson-crackable synthetic sector and
  asserts crack_span recording (the Cracked branch was never exercised).
- recrack_succeeds_on_other_vts_extents: per-VTS re-crack SUCCESS path.
- all_locked_synthetic_iso_yields_css_key_missing_signal: all-locked
  multi-extent ISO → ScrambledUncracked, the signal the scan converts to
  css_error = Some(CssKeyMissing).

Corrected fixtures (passes-but-encodes-the-bug):
- scan_dvd_titles_mixed_audio_codecs_distinct_pids: real channel nibbles
  (AC-3 5.1 = 6ch, DTS 2.0 = 2ch) replacing the 1ch placeholders; asserts
  channel counts and exact canonical PIDs (0xBD80 / 0xBD88).
- ebml.rs FieldOrder comment: drop the stale "PAL DVD (576i) is
  bottom-field-first" line that contradicted the TFF-for-all code.
This commit is contained in:
Matthew Jackson
2026-06-24 15:41:26 -07:00
parent 63ed05bd63
commit 794d88f6e7
5 changed files with 643 additions and 10 deletions
+48
View File
@@ -1056,6 +1056,54 @@ mod tests {
assert_eq!(attr.resolution, Resolution::R576i);
}
/// ABSOLUTE-BYTE pin (audit §3 #2): the existing video-attr tests build the
/// byte via `v_atr_byte(...)`, which uses the SAME shift constants the parser
/// reads with — a co-edit of constant + helper would silently re-introduce
/// the PAL-as-NTSC bug and every test would still pass. This test feeds
/// `parse_video_attr` HARDCODED bytes captured from real DVD-Video layouts
/// (DVD spec / libdvdread `video_attr_t`: mpeg_version[7-6] video_format[5-4]
/// display_aspect[3-2] permitted_df[1-0]) — no `v_atr_byte`. If the parser's
/// bit positions drift, these fail.
#[test]
fn video_attr_absolute_bytes_pin_real_layout() {
// (byte @0x200, expected standard, expected aspect, expected resolution).
// PAL 16:9 anamorphic = mpeg(00) format(01=PAL) aspect(11=16:9) df(00)
// = 0b0001_1100 = 0x1C (e.g. a PAL 16:9 R2 feature disc).
// PAL 4:3 = 0b0001_0000 = 0x10.
// NTSC 16:9 = 0b0000_1100 = 0x0C.
// NTSC 4:3 = 0b0000_0000 = 0x00.
// A real disc also sets mpeg_version=01 (MPEG-2) in bits 7-6, which the
// parser must IGNORE; OR it in (|0x40) to prove it doesn't leak into the
// video_format read.
let cases: &[(u8, TvSystem, DvdAspect, Resolution)] = &[
(0x1C, TvSystem::Pal, DvdAspect::R16x9, Resolution::R576i),
(0x10, TvSystem::Pal, DvdAspect::R4x3, Resolution::R576i),
(0x0C, TvSystem::Ntsc, DvdAspect::R16x9, Resolution::R480i),
(0x00, TvSystem::Ntsc, DvdAspect::R4x3, Resolution::R480i),
// mpeg_version=2 (MPEG-2) in bits 7-6 must not perturb the read.
(0x5C, TvSystem::Pal, DvdAspect::R16x9, Resolution::R576i),
];
for &(b0, std, aspect, res) in cases {
let mut data = vec![0u8; 0x204];
data[0x200] = b0;
let attr = parse_video_attr(&data).unwrap();
assert_eq!(attr.standard, std, "byte {b0:#04x} → standard");
assert_eq!(attr.aspect, aspect, "byte {b0:#04x} → aspect");
assert_eq!(attr.resolution, res, "byte {b0:#04x} → resolution");
}
// Anti-bug anchor: the original bug read the TV system from bits 1-0
// (permitted_df). A PAL byte whose low 2 bits are 0 (0x1C) must NOT be
// misread as NTSC — and a byte with low bits set but format=NTSC
// (0x03 = NTSC, df=11) must stay NTSC, proving the low bits are ignored.
let mut df = vec![0u8; 0x204];
df[0x200] = 0x03; // format=NTSC(00), df=11
assert_eq!(
parse_video_attr(&df).unwrap().standard,
TvSystem::Ntsc,
"permitted_df bits (1-0) must NOT be read as the TV system"
);
}
#[test]
fn audio_attr_parsing() {
let mut data = vec![0u8; 16];