diff --git a/src/aacs/content.rs b/src/aacs/content.rs index e395152..ca447f7 100644 --- a/src/aacs/content.rs +++ b/src/aacs/content.rs @@ -664,23 +664,11 @@ mod tests { let original = vec![0x42u8; 128]; // 8 blocks let mut data = original.clone(); - // Encrypt with CBC manually (forward direction) - fn aes_cbc_encrypt(key: &[u8; 16], data: &mut [u8]) { - let cipher = Aes128::new(GenericArray::from_slice(key)); - let mut prev = super::AACS_IV; - let num_blocks = data.len() / 16; - 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]); - } - } - + // Encrypt with the REAL production primitive. This test previously + // defined a local `fn aes_cbc_encrypt` that SHADOWED it, so it round- + // tripped a copy of the algorithm against itself and never exercised + // `crypto::aes_cbc_encrypt` at all — a mutation to the shipped function + // could not fail it. aes_cbc_encrypt(&key, &mut data); assert_ne!(data, original); // should be different after encrypt diff --git a/src/mux/codec/dts.rs b/src/mux/codec/dts.rs index accfe65..1acb4bc 100644 --- a/src/mux/codec/dts.rs +++ b/src/mux/codec/dts.rs @@ -691,9 +691,9 @@ const DTS_PCMBLOCK_SAMPLES: u32 = 32; const DTS_SUBBAND_SAMPLES: u32 = 8; /// 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; -/// only 16-63 are reserved/user-defined and undecodable. ffmpeg's -/// `ff_dca_channels[16] = {1,2,2,2,2,3,3,4,4,5,6,6,6,7,8,8}` confirms all 16 are -/// decodable — codes 10-15 are the 6/7/8-channel layouts. A frame is dropped +/// only 16-63 are reserved/user-defined and undecodable. The per-AMODE channel +/// counts in ETSI TS 102 114 §5.3.1 cover all 16, confirming they are decodable — +/// 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); /// dropping a legal 10-15 multichannel core would silence recoverable audio. const DTS_AMODE_COUNT: u32 = 16; diff --git a/src/mux/tsmux.rs b/src/mux/tsmux.rs index bbed3ce..1b32dc4 100644 --- a/src/mux/tsmux.rs +++ b/src/mux/tsmux.rs @@ -195,8 +195,22 @@ impl TsMuxer { Codec::H264 => avcc_to_annex_b(cp), _ => hvcc_to_annex_b(cp), }; - if let Some(params) = params { - annex_b.extend_from_slice(¶ms); + match params { + 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;