audit: guard 0xFD video routing, carry frame duration, add cap tests
Round-5 findings from the 10-phase release audit: - collect_es routed EVERY extended-stream-id (0xFD) PES into the video ES buffer, so a 0xFD HD-audio sub-stream (MLP/TrueHD) could pollute the video sample and — if it preceded the video PES — stamp the video track with the audio PID, losing the video. Only the VC-1 extension (0x55) is now treated as video; routing 0xFD audio to its own track is deferred to the HD-DVD program-chain follow-up. - The sparse-PTS reorder now carries its calibrated per-frame duration onto each frame, so the muxer emits a BlockDuration and the back-patched Segment Duration covers the final frame instead of understating it. - Add regression tests for the MAX_MARKS and MAX_VTI_HITS caps (promote MAX_VTI_HITS to module scope); make the differential-test factory array a named type; drop an identity-op in a reorder test.
This commit is contained in:
+25
-3
@@ -466,7 +466,7 @@ mod tests {
|
||||
|
||||
fn au(payload: u8, len: usize) -> Vec<u8> {
|
||||
let mut v = AUD.to_vec();
|
||||
v.extend(std::iter::repeat(payload).take(len));
|
||||
v.extend(std::iter::repeat_n(payload, len));
|
||||
v
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ mod tests {
|
||||
|
||||
fn bdu(ty: u8, payload: u8, len: usize) -> Vec<u8> {
|
||||
let mut v = vec![0x00, 0x00, 0x01, ty];
|
||||
v.extend(std::iter::repeat(payload).take(len));
|
||||
v.extend(std::iter::repeat_n(payload, len));
|
||||
v
|
||||
}
|
||||
|
||||
@@ -762,7 +762,8 @@ mod tests {
|
||||
};
|
||||
// (label, stream, assembler factory). MPEG-2 uses the dedicated mpeg2()
|
||||
// assembler (Mode::Mpeg2); the AUD/VC-1 codecs use for_codec().
|
||||
let cases: [(&str, &[u8], fn() -> AuAssembler); 3] = [
|
||||
type MakeAsm = fn() -> AuAssembler;
|
||||
let cases: [(&str, &[u8], MakeAsm); 3] = [
|
||||
("h264", &h264, || AuAssembler::for_codec(Codec::H264)),
|
||||
("vc1", &vc1, || AuAssembler::for_codec(Codec::Vc1)),
|
||||
("mpeg2", &mpeg2, AuAssembler::mpeg2),
|
||||
@@ -780,6 +781,27 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn marks_deques_stay_bounded_on_zero_length_timed_fragments() {
|
||||
// A run of zero-length fragments that each carry a PTS (or a
|
||||
// discontinuity) grows no buffer bytes, so the buf-size cap never prunes
|
||||
// the mark deques. The MAX_MARKS backstop must bound them regardless.
|
||||
let mut a = AuAssembler::for_codec(Codec::H264);
|
||||
for i in 0..(MAX_MARKS * 2) {
|
||||
a.push(&[], Some(i as i64), None, None, true);
|
||||
}
|
||||
assert!(
|
||||
a.marks.len() <= MAX_MARKS,
|
||||
"marks bounded at MAX_MARKS, got {}",
|
||||
a.marks.len()
|
||||
);
|
||||
assert!(
|
||||
a.disc_marks.len() <= MAX_MARKS,
|
||||
"disc_marks bounded at MAX_MARKS, got {}",
|
||||
a.disc_marks.len()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_cap_without_boundary_force_flushes() {
|
||||
let mut a = AuAssembler::for_codec(Codec::H264);
|
||||
|
||||
@@ -190,6 +190,10 @@ impl SparsePtsReorder {
|
||||
let mut out = Vec::with_capacity(pend.len());
|
||||
for (mut p, didx) in pend.into_iter().zip(dispidx) {
|
||||
p.frame.pts_ns = origin + didx * dur;
|
||||
// Carry the calibrated per-frame duration so the muxer emits a
|
||||
// BlockDuration and the back-patched Segment Duration covers the
|
||||
// final frame (the source gives no duration on this path).
|
||||
p.frame.duration_ns = Some(dur as u64);
|
||||
out.push(p.frame);
|
||||
}
|
||||
// Next GOP with no anchor continues after this one's last display slot.
|
||||
@@ -295,7 +299,7 @@ mod tests {
|
||||
// GOP 1 decode order I P B P B -> display indices 0 2 1 4 3 -> PTS:
|
||||
assert_eq!(
|
||||
&got[0..5],
|
||||
&[0, 2 * dur, 1 * dur, 4 * dur, 3 * dur],
|
||||
&[0, 2 * dur, dur, 4 * dur, 3 * dur],
|
||||
"GOP1 display PTS in decode order"
|
||||
);
|
||||
// GOP 2 re-locks origin to 5*dur.
|
||||
|
||||
Reference in New Issue
Block a user