Cover the non-NAL video path, including the wiring that selects it

set_nal_video had exactly one production caller and zero test callers. The
branch it gates decides whether a video track's ES goes through
length_prefixed_to_annex_b, and MPEG-2 and VC-1 must not: they are already
start-code ES. Getting it wrong is silent — frame_count still increments,
so the mux reports success while emitting a video-less file.

Five tests, each verified against a real mutant:

  * non-NAL ES passes through byte-for-byte, and the default path still
    converts. Both use a deliberately length-prefix-SHAPED payload so a
    wrongly-applied conversion rewrites the leading four bytes into a start
    code — a payload the converter happened to leave alone would let a
    mutant pass.
  * a non-NAL keyframe arms params_written, so following non-keyframes are
    not dropped by the pre-keyframe guard.
  * set_nal_video rejects an out-of-range track instead of panicking.
  * M2tsStream::create wires a VC-1 track to the non-NAL path.

That last one matters more than it looks. The four TsMuxer-level tests set
the flag themselves, so deleting the set_nal_video loop from
M2tsStream::create left all 2366 tests passing — the exact mutant the
finding named went undetected until a test drove the real wiring. It now
also catches the subtler mutant of widening the matches! arm to include
Vc1.
This commit is contained in:
Matthew Jackson
2026-07-29 17:54:27 -07:00
parent d09ed76e07
commit bf2d15f39c
2 changed files with 145 additions and 0 deletions
+46
View File
@@ -170,6 +170,52 @@ mod tests {
}
}
/// `M2tsStream::create` must opt a VC-1 video track OUT of Annex-B conversion.
///
/// This pins the WIRING in `create`, not just `TsMuxer`'s flag: deleting the
/// `set_nal_video` loop leaves every TsMuxer-level test passing, because those
/// drive the muxer directly and set the flag themselves. Only a test that goes
/// through `create` catches it — and mangling MPEG-2/VC-1 video is silent, since
/// frame_count still increments and the mux reports success.
///
/// Mutation: remove the `set_nal_video` loop from `create`, or widen its
/// `matches!` to include Vc1 -> the ES gains a start code and this fails.
#[test]
fn vc1_video_is_wired_to_the_non_nal_path() {
let mut title = make_title();
if let DiscStream::Video(v) = &mut title.streams[0] {
v.codec = Codec::Vc1;
}
title.codec_privates = vec![None];
// Length-prefix SHAPED ES: if the conversion is wrongly applied it rewrites
// these leading four bytes into a 00 00 00 01 start code.
let es: Vec<u8> = vec![0x00, 0x00, 0x00, 0x06, 0x0F, 0x12, 0x34, 0x56, 0x78, 0x9A];
let shared = std::sync::Arc::new(std::sync::Mutex::new(Vec::<u8>::new()));
let sink = SharedSink(shared.clone());
let mut stream = M2tsStream::create(sink, &title).unwrap();
stream
.write(&PesFrame {
coding: None,
source: None,
track: 0,
pts: 0,
keyframe: true,
data: es.clone(),
duration_ns: None,
})
.unwrap();
stream.finish().unwrap();
drop(stream);
let buf = shared.lock().unwrap().clone();
assert!(
buf.windows(es.len()).any(|w| w == &es[..]),
"VC-1 ES must reach the output verbatim, not converted to Annex-B"
);
}
#[test]
fn m2ts_stream_forwards_keyframe_to_rai() {
let title = make_title();