audit: void empty-timeline duration, cover sniff overlap

Round-11 findings from the 10-phase release audit (no real HIGH):

- When a no-declared-duration source (HD-DVD) muxes a degenerate single
  frame at tick 0 with no per-frame duration, max_block_ticks stays 0 and
  the reserved DURATION placeholder was left as a literal 0.0 (players read
  that as a zero-length file). Void the element instead, so the Segment
  omits DURATION as an unknown-duration source did before the back-patch.
- Add a regression test for the sniff_video_codec overlap fix (a
  picture_start_code whose payload begins 00 00 followed by a real start
  code) so the i+=4 marker skip can't silently regress to i+=3.
This commit is contained in:
Matthew Jackson
2026-07-09 20:40:54 -07:00
parent 640502d5a8
commit 18082d0df1
2 changed files with 46 additions and 0 deletions
+30
View File
@@ -1365,6 +1365,19 @@ impl<W: Write + Seek> MkvMuxer<W> {
self.writer.seek(std::io::SeekFrom::Start(pos))?;
self.writer
.write_all(&(self.max_block_ticks as f64).to_be_bytes())?;
} else {
// The timeline never advanced past tick 0 (a degenerate
// single-frame recovery at t=0 with no per-frame duration): we
// can't derive a runtime, so DON'T leave a literal DURATION=0.0
// (players read that as a zero-length/corrupt file). Void the
// whole 11-byte DURATION element (ID 2 + size 1 + 8-byte payload)
// so the Segment simply omits it, as an unknown-duration source
// did before the back-patch. `pos` is the payload start (+3 from
// the element start), so back up 3.
self.writer.seek(std::io::SeekFrom::Start(pos - 3))?;
ebml::write_id(&mut self.writer, ebml::VOID)?;
ebml::write_size(&mut self.writer, 9)?; // 11 - 1 (Void id) - 1 (size)
self.writer.write_all(&[0u8; 9])?;
}
}
@@ -2907,6 +2920,23 @@ mod tests {
.map(|b| f64::from_be_bytes(b.try_into().unwrap()))
}
#[test]
fn duration_placeholder_voided_when_timeline_never_advances() {
// Degenerate recovery: a source with no declared duration muxes exactly
// one keyframe at tick 0 with no per-frame duration, so max_block_ticks
// stays 0. The reserved DURATION placeholder must be VOIDED (element
// omitted) rather than left as a bogus 0.0 that players read as a
// zero-length file.
let tracks = [make_video_track()];
let one_frame = vec![(0usize, 0i64, true, vec![0xAAu8; 16])];
let (data, _) = mux_to_bytes(&tracks, &[], &one_frame);
assert_eq!(
find_duration_ticks(&data),
None,
"no DURATION element (placeholder voided), not a 0.0 duration"
);
}
#[test]
fn duration_backpatched_from_timeline_when_source_gives_none() {
// `mux_to_bytes` muxes with `duration_secs = 0.0` (as an HD-DVD title