audit: drop dead DTS marks cap, lazy passthrough buf, doc corrections
Round-9 findings from the 10-phase release audit (no HIGH): - Remove the MAX_PTS_MARKS backstop and its tautological test: an empty DTS PES returns before recording a mark, and a non-empty run is already bounded by the MAX_AU_BYTES buffer clear (which clears pts_marks) — so the deque cannot grow unbounded and the cap was dead code. - AuAssembler::for_codec no longer reserves 256 KiB for a Passthrough stream (audio/subtitle, and every TS/BD stream) whose buf is never written; only the reassembling modes reserve. - Correct the scan comment that claimed region is computed (it is a Region-free stub until region detection lands) and drop a public-repo reference to internal "private refactor notes" in the mkb module doc.
This commit is contained in:
+3
-4
@@ -2,10 +2,9 @@
|
|||||||
//!
|
//!
|
||||||
//! The MKB record format (framing walker, the `MkbRecord` view, record-body
|
//! The MKB record format (framing walker, the `MkbRecord` view, record-body
|
||||||
//! finders), the MKBType / AACS-generation classification, and MKB-file
|
//! finders), the MKBType / AACS-generation classification, and MKB-file
|
||||||
//! utilities (content length, trimming, version). Consolidated here from the
|
//! utilities (content length, trimming, version). Consolidated here so the one
|
||||||
//! former `keys.rs` / `variant.rs` so the one place that understands MKB bytes
|
//! place that understands MKB bytes is `mkb`. Some duplicate record finders
|
||||||
//! is `mkb`. A follow-up collapses the remaining duplicate finders (see the
|
//! still live side by side pending a follow-up that collapses them.
|
||||||
//! private refactor notes) — for now both dialects live here side by side.
|
|
||||||
|
|
||||||
// ── MKB record types ([C] Chapter 3) ──────────────────────────────────────
|
// ── MKB record types ([C] Chapter 3) ──────────────────────────────────────
|
||||||
// The ONE canonical set. Every record-type comparison in the `aacs` module
|
// The ONE canonical set. Every record-type comparison in the `aacs` module
|
||||||
|
|||||||
+4
-2
@@ -1950,8 +1950,10 @@ impl Disc {
|
|||||||
crate::labels::apply(reader, &udf_fs, &mut titles);
|
crate::labels::apply(reader, &udf_fs, &mut titles);
|
||||||
crate::labels::fill_defaults(&mut titles);
|
crate::labels::fill_defaults(&mut titles);
|
||||||
|
|
||||||
// 5. Format (AACS MKB generation → BD/UHD/FMTS; tree → HD-DVD/DVD),
|
// 5. Format (AACS MKB generation → BD/UHD/FMTS; tree → HD-DVD/DVD) and
|
||||||
// layers, region.
|
// layers. Region coding is not yet decoded from the disc — every disc
|
||||||
|
// reports Region-free for now (correct for all UHD; a stub for
|
||||||
|
// region-locked BD/DVD until region detection is implemented).
|
||||||
let format = Self::detect_disc_format(reader, &udf_fs, &titles);
|
let format = Self::detect_disc_format(reader, &udf_fs, &titles);
|
||||||
let layers = if capacity > 24_000_000 { 2 } else { 1 };
|
let layers = if capacity > 24_000_000 { 2 } else { 1 };
|
||||||
let region = DiscRegion::Free;
|
let region = DiscRegion::Free;
|
||||||
|
|||||||
@@ -142,7 +142,13 @@ impl AuAssembler {
|
|||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
mode,
|
mode,
|
||||||
buf: Vec::with_capacity(256 * 1024),
|
// Passthrough never writes `buf` (one fragment → one unit); only the
|
||||||
|
// reassembling modes need reserve. Avoids ~256 KiB per audio/subtitle
|
||||||
|
// stream (and every TS/BD stream, which never feeds the assembler).
|
||||||
|
buf: match mode {
|
||||||
|
Mode::Passthrough => Vec::new(),
|
||||||
|
_ => Vec::with_capacity(256 * 1024),
|
||||||
|
},
|
||||||
base: 0,
|
base: 0,
|
||||||
marks: VecDeque::new(),
|
marks: VecDeque::new(),
|
||||||
disc_marks: VecDeque::new(),
|
disc_marks: VecDeque::new(),
|
||||||
|
|||||||
+3
-30
@@ -140,12 +140,6 @@ impl DtsParser {
|
|||||||
/// this without a clean boundary we resync rather than stall or balloon.
|
/// this without a clean boundary we resync rather than stall or balloon.
|
||||||
const MAX_AU_BYTES: usize = 65536;
|
const MAX_AU_BYTES: usize = 65536;
|
||||||
|
|
||||||
/// Cap on buffered PTS marks. A real AU spans a few PES; this bounds the deque so
|
|
||||||
/// a run of zero-length timed PES packets (which grow no buffer bytes, so the
|
|
||||||
/// `drain_front` prune never fires) cannot accumulate marks without bound on
|
|
||||||
/// hostile program-stream input.
|
|
||||||
const MAX_PTS_MARKS: usize = 64 * 1024;
|
|
||||||
|
|
||||||
/// Number of leading bytes that must be buffered before the core `fsize` field
|
/// Number of leading bytes that must be buffered before the core `fsize` field
|
||||||
/// (bytes 5-7) can be decoded. This is a HEADER-LAYOUT minimum — "enough bytes
|
/// (bytes 5-7) can be decoded. This is a HEADER-LAYOUT minimum — "enough bytes
|
||||||
/// to read the size field" — and is deliberately distinct from
|
/// to read the size field" — and is deliberately distinct from
|
||||||
@@ -236,15 +230,10 @@ impl CodecParser for DtsParser {
|
|||||||
// (see `front_pts`), so an AU whose core arrived in an earlier PES keeps
|
// (see `front_pts`), so an AU whose core arrived in an earlier PES keeps
|
||||||
// that core's timestamp even when its extensions / the following core
|
// that core's timestamp even when its extensions / the following core
|
||||||
// arrive (with a later PTS) in this same parse() call.
|
// arrive (with a later PTS) in this same parse() call.
|
||||||
|
// (pts_marks is bounded implicitly: an empty PES returns above without
|
||||||
|
// pushing a mark, and a non-empty run grows `buf`, which is cleared —
|
||||||
|
// along with pts_marks — once it exceeds MAX_AU_BYTES.)
|
||||||
self.pts_marks.push_back((self.buf.len(), pts_ns));
|
self.pts_marks.push_back((self.buf.len(), pts_ns));
|
||||||
// Backstop: a run of zero-length (sub-header-only) PES packets that each
|
|
||||||
// carry a PTS grows no buffer bytes, so `drain_front` (which prunes marks)
|
|
||||||
// never runs. Bound the deque directly — drop the oldest, which belongs to
|
|
||||||
// an already-emitted or lost AU — so hostile PS input can't accumulate
|
|
||||||
// marks without bound.
|
|
||||||
if self.pts_marks.len() > MAX_PTS_MARKS {
|
|
||||||
self.pts_marks.pop_front();
|
|
||||||
}
|
|
||||||
self.buf.extend_from_slice(&pes.data);
|
self.buf.extend_from_slice(&pes.data);
|
||||||
|
|
||||||
let mut frames = Vec::new();
|
let mut frames = Vec::new();
|
||||||
@@ -929,22 +918,6 @@ mod tests {
|
|||||||
assert_eq!(dts_core_sample_rate(&core), 48_000);
|
assert_eq!(dts_core_sample_rate(&core), 48_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn pts_marks_stay_bounded_on_zero_length_pes() {
|
|
||||||
// A run of zero-length (sub-header-only) DTS PES packets that each carry a
|
|
||||||
// PTS grows no buffer bytes, so drain_front (which prunes marks) never
|
|
||||||
// runs. The MAX_PTS_MARKS backstop must bound the deque regardless.
|
|
||||||
let mut parser = DtsParser::new();
|
|
||||||
for i in 0..(MAX_PTS_MARKS * 2) {
|
|
||||||
parser.parse(&make_pes(Vec::new(), Some(i as i64)));
|
|
||||||
}
|
|
||||||
assert!(
|
|
||||||
parser.pts_marks.len() <= MAX_PTS_MARKS,
|
|
||||||
"pts_marks bounded, got {}",
|
|
||||||
parser.pts_marks.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_pes_rebases_to_its_own_pts_no_drift() {
|
fn new_pes_rebases_to_its_own_pts_no_drift() {
|
||||||
// Regression for the drift bug: a global running clock overshot a
|
// Regression for the drift bug: a global running clock overshot a
|
||||||
|
|||||||
Reference in New Issue
Block a user