audit: bound DTS marks, align disc-format tree order, doc/test cleanups
Round-7 findings from the 10-phase release audit (no HIGH; convergence): - Cap DtsParser.pts_marks (MAX_PTS_MARKS): a run of zero-length timed PES packets grew no buffer bytes, so the drain_front mark-prune never ran — the deque could accumulate without bound on hostile PS input. - detect_disc_format tested HVDVD_TS before BDMV while the title-scan dispatch tests BDMV first, so a disc with both trees would be classified HD-DVD but enumerated as Blu-ray. Align both to BDMV → HVDVD_TS → VIDEO_TS. - Document why the DTS new-PES re-base can emit a locally-decreasing PTS (the muxer's block_ts applies the strictly-monotonic audio nudge, tested in mkv.rs) — this is by design, not a mux defect. - Fix stale aacs/keys.rs comment references (functions moved to aacs/inf.rs / aacs::resolve/derive in the module split).
This commit is contained in:
@@ -140,6 +140,12 @@ impl DtsParser {
|
||||
/// this without a clean boundary we resync rather than stall or balloon.
|
||||
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
|
||||
/// (bytes 5-7) can be decoded. This is a HEADER-LAYOUT minimum — "enough bytes
|
||||
/// to read the size field" — and is deliberately distinct from
|
||||
@@ -231,6 +237,14 @@ impl CodecParser for DtsParser {
|
||||
// that core's timestamp even when its extensions / the following core
|
||||
// arrive (with a later PTS) in this same parse() call.
|
||||
self.pts_marks.push((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.remove(0);
|
||||
}
|
||||
self.buf.extend_from_slice(&pes.data);
|
||||
|
||||
let mut frames = Vec::new();
|
||||
@@ -915,6 +929,22 @@ mod tests {
|
||||
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]
|
||||
fn new_pes_rebases_to_its_own_pts_no_drift() {
|
||||
// Regression for the drift bug: a global running clock overshot a
|
||||
@@ -922,6 +952,14 @@ mod tests {
|
||||
// PES arrives whose PTS is BEHIND where accumulated frame durations
|
||||
// would put a running clock, the AU must re-base to that PES's OWN
|
||||
// timestamp — tracking the container, not drifting ahead of it.
|
||||
//
|
||||
// The re-base can make one emitted PTS sit just below the previous AU's
|
||||
// (a fresh PES whose PTS lands under the within-PES cursor). That is
|
||||
// CORRECT here and is NOT a muxer defect: the parser reports the true
|
||||
// container timestamps, and the mkv muxer applies the strictly-monotonic
|
||||
// per-track nudge to AUDIO at emit time (`mkv::block_ts` / `monotonic_ts`,
|
||||
// tested in `mkv.rs`), so the written block DTS is always monotonic. The
|
||||
// alternative — clamping in the parser — is what reintroduced the drift.
|
||||
let mut parser = DtsParser::new();
|
||||
// PES A: core1 + core2 (2 frames), pts 90000.
|
||||
let mut pes_a = make_dts_core(512);
|
||||
|
||||
Reference in New Issue
Block a user