DVD vob_start absolute rebase + rc.5.3 audit fixes

- ifo.rs: rebase VTS title VOBS to absolute disc LBA (file_start_lba +
  vtstt_vobs); fixes DVD rips opening on the menu region instead of the
  movie (e.g. SOTL). Adds absolute-placement regression test.
- aacs/boil.rs: add mk_from_pk primitive (PK -> MK via MKB walk).
- dvdnav/: nav-VM command decoder + start-cell resolver seam, parked
  behind USE_NAV_RESOLVER (kept compiled, never executed).
- mux: FVI src.byte within-sector per spec; Unknown colour -> CICP
  unspecified (2,2,2,1); demux clear PCS -> NORMAL; ts.rs feed() base
  reset + boundary provenance fix.
- Assorted audit fixes (doc/comment/test accuracy) across the crate.
This commit is contained in:
Matthew Jackson
2026-06-26 17:03:58 -07:00
parent d8c323bf9f
commit 835cc990ad
31 changed files with 1149 additions and 129 deletions
+13 -3
View File
@@ -82,8 +82,16 @@ fn write_fvi_record(w: &mut dyn Write, r: &PictureRecord) -> io::Result<()> {
// `src` is REQUIRED by the record schema (Appendix A); when provenance is
// absent the member is still emitted as null — a reader treats null as
// "position unknown".
//
// Per `docs/FVI_FORMAT.md` §9, `src.byte` is the offset of the AU's first
// byte WITHIN its `sector` (not the absolute source offset). `SourcePos.byte`
// is the absolute offset, so reduce it modulo the sector size; `sector`
// already carries the whole-sector count.
let src = match r.source {
Some(s) => serde_json::json!({ "sector": s.sector, "byte": s.byte }),
Some(s) => serde_json::json!({
"sector": s.sector,
"byte": s.byte % u64::from(FVI_SECTOR_SIZE),
}),
None => serde_json::Value::Null,
};
@@ -355,8 +363,9 @@ mod tests {
let dir = tempdir();
let path = dir.join("movie.fvi");
let mut sink = FviSink::create(&path, &mpeg2_title(), "iso://m.iso".into(), 1).unwrap();
// Video frame on track 0 → indexed.
sink.write(&vframe(0, Some(i_pic()), Some(SourcePos::at_byte(2048))))
// Video frame on track 0 → indexed. Offset 2148 = sector 1, byte 100
// within that sector (exercises the within-sector `src.byte`, §9).
sink.write(&vframe(0, Some(i_pic()), Some(SourcePos::at_byte(2148))))
.unwrap();
// Audio frame on a non-video track → ignored.
sink.write(&vframe(7, None, Some(SourcePos::at_byte(9999))))
@@ -387,6 +396,7 @@ mod tests {
assert_eq!(rec["nb_fields"], 2);
assert_eq!(rec["pts"], 0);
assert_eq!(rec["src"]["sector"], 1);
assert_eq!(rec["src"]["byte"], 100); // 2148 % 2048 → within-sector (§9)
assert!(rec.get("dts").is_none(), "no DTS on a frame → omitted");
assert!(
rec.get("gop").is_none(),