Fix three defects in last round's own fixes
Round 3 audited the round-1/2 fix commits rather than trusting them, and found three defects in that new code. This is why the pin moves each round. 1. LICENCE REGRESSION, and it was mine. Reverting the "distinguish a failed key source" commit also restored a verbatim reference-decoder table citation in src/mux/codec/dts.rs, because both changes were in that one commit. The MIT licence cleanup was silently undone at HEAD and nothing caught it. The citation is replaced with ETSI TS 102 114 §5.3.1 again, and — more importantly — the rule now lives in the leak gate instead of in my memory. scan-secrets.sh gains LICENCE_RE, which flags ff_dca*, dcadec, l-smash, libav*, and bare ffmpeg/FFmpeg as REF-IMPL-CITATION. `no ffmpeg` is explicitly allowed via negative lookbehind: stating what this project does NOT depend on carries no risk and is a genuine selling point. Verified by re-introducing the citation (gate fails) and removing it (gate clean). 2. TsMuxer armed params_written even when the avcC/hvcC parser returned None, so a track whose codec_private exists but will not parse was muxed to BD-TS with no VPS/SPS/PPS ever emitted — undecodable video, reported as success, with no log line. Last round's fix corrected WHICH parser is used and left this half untouched. Arming the flag is still right (retrying identical bytes cannot succeed) but it is no longer silent: it now warns with the track, codec and codec_private length. 3. test_aes_cbc_roundtrip defined a LOCAL fn aes_cbc_encrypt that SHADOWED the production primitive, so it round-tripped a copy of the algorithm against itself and never touched crypto::aes_cbc_encrypt — the function this cycle added. Any mutation to the shipped code passed it. The shadow is deleted and the test now calls the real primitive; verified by mutating crypto::aes_cbc_encrypt, which now fails it and previously would not have.
This commit is contained in:
+5
-17
@@ -664,23 +664,11 @@ mod tests {
|
|||||||
let original = vec![0x42u8; 128]; // 8 blocks
|
let original = vec![0x42u8; 128]; // 8 blocks
|
||||||
let mut data = original.clone();
|
let mut data = original.clone();
|
||||||
|
|
||||||
// Encrypt with CBC manually (forward direction)
|
// Encrypt with the REAL production primitive. This test previously
|
||||||
fn aes_cbc_encrypt(key: &[u8; 16], data: &mut [u8]) {
|
// defined a local `fn aes_cbc_encrypt` that SHADOWED it, so it round-
|
||||||
let cipher = Aes128::new(GenericArray::from_slice(key));
|
// tripped a copy of the algorithm against itself and never exercised
|
||||||
let mut prev = super::AACS_IV;
|
// `crypto::aes_cbc_encrypt` at all — a mutation to the shipped function
|
||||||
let num_blocks = data.len() / 16;
|
// could not fail it.
|
||||||
for i in 0..num_blocks {
|
|
||||||
let offset = i * 16;
|
|
||||||
for j in 0..16 {
|
|
||||||
data[offset + j] ^= prev[j];
|
|
||||||
}
|
|
||||||
let mut block = GenericArray::clone_from_slice(&data[offset..offset + 16]);
|
|
||||||
cipher.encrypt_block(&mut block);
|
|
||||||
data[offset..offset + 16].copy_from_slice(&block);
|
|
||||||
prev.copy_from_slice(&data[offset..offset + 16]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aes_cbc_encrypt(&key, &mut data);
|
aes_cbc_encrypt(&key, &mut data);
|
||||||
assert_ne!(data, original); // should be different after encrypt
|
assert_ne!(data, original); // should be different after encrypt
|
||||||
|
|
||||||
|
|||||||
@@ -691,9 +691,9 @@ const DTS_PCMBLOCK_SAMPLES: u32 = 32;
|
|||||||
const DTS_SUBBAND_SAMPLES: u32 = 8;
|
const DTS_SUBBAND_SAMPLES: u32 = 8;
|
||||||
/// Number of LEGAL `AMODE` (channel-arrangement) codes. The 6-bit AMODE field
|
/// Number of LEGAL `AMODE` (channel-arrangement) codes. The 6-bit AMODE field
|
||||||
/// (ETSI TS 102 114 §5.3.1) has 16 defined channel arrangements, codes 0-15;
|
/// (ETSI TS 102 114 §5.3.1) has 16 defined channel arrangements, codes 0-15;
|
||||||
/// only 16-63 are reserved/user-defined and undecodable. ffmpeg's
|
/// only 16-63 are reserved/user-defined and undecodable. The per-AMODE channel
|
||||||
/// `ff_dca_channels[16] = {1,2,2,2,2,3,3,4,4,5,6,6,6,7,8,8}` confirms all 16 are
|
/// counts in ETSI TS 102 114 §5.3.1 cover all 16, confirming they are decodable —
|
||||||
/// decodable — codes 10-15 are the 6/7/8-channel layouts. A frame is dropped
|
/// codes 10-15 are the 6/7/8-channel layouts. A frame is dropped
|
||||||
/// only when `audio_mode >= DTS_AMODE_COUNT` (i.e. a truly reserved 16-63 code);
|
/// only when `audio_mode >= DTS_AMODE_COUNT` (i.e. a truly reserved 16-63 code);
|
||||||
/// dropping a legal 10-15 multichannel core would silence recoverable audio.
|
/// dropping a legal 10-15 multichannel core would silence recoverable audio.
|
||||||
const DTS_AMODE_COUNT: u32 = 16;
|
const DTS_AMODE_COUNT: u32 = 16;
|
||||||
|
|||||||
+16
-2
@@ -195,8 +195,22 @@ impl<W: Write> TsMuxer<W> {
|
|||||||
Codec::H264 => avcc_to_annex_b(cp),
|
Codec::H264 => avcc_to_annex_b(cp),
|
||||||
_ => hvcc_to_annex_b(cp),
|
_ => hvcc_to_annex_b(cp),
|
||||||
};
|
};
|
||||||
if let Some(params) = params {
|
match params {
|
||||||
annex_b.extend_from_slice(¶ms);
|
Some(params) => annex_b.extend_from_slice(¶ms),
|
||||||
|
// A codec_private that EXISTS but will not parse means no
|
||||||
|
// VPS/SPS/PPS reaches the stream and it is undecodable.
|
||||||
|
// Arming the flag below is still right — retrying the same
|
||||||
|
// bytes on the next keyframe cannot succeed — but it must
|
||||||
|
// not be silent, which is what it was: the mux reported
|
||||||
|
// success while emitting parameter-set-free video.
|
||||||
|
None => tracing::warn!(
|
||||||
|
track,
|
||||||
|
codec = ?self.video_codec[track],
|
||||||
|
codec_private_len = cp.len(),
|
||||||
|
"bd-ts: codec_private did not parse as an avcC/hvcC \
|
||||||
|
record; no parameter sets emitted and the video will \
|
||||||
|
not decode"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.params_written[track] = true;
|
self.params_written[track] = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user