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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user