Fix all v4 audit findings (22 items)
HIGH: ISO writer multi-extent for >4GB, end-to-end MKV mux test MEDIUM: AACS cvalue bounds, UV offset, macOS discovery, VC-1 resolution from sequence header, HEVC profile flags from SPS, ISO CRC + reserve AVDP LOW: PS AC3 sub-header, CSS crack first-match break, TrackUID unique, AC3 no-sync empty return, --all for iso://, --min warning, dead code removed 320 tests, all passing.
This commit is contained in:
+1
-10
@@ -81,16 +81,7 @@ impl CodecParser for Ac3Parser {
|
||||
}
|
||||
}
|
||||
|
||||
// If we found no syncword at all, emit the whole PES as a frame
|
||||
// (backwards-compatible with old behaviour).
|
||||
if frames.is_empty() {
|
||||
frames.push(Frame {
|
||||
pts_ns,
|
||||
keyframe: true,
|
||||
data: data.to_vec(),
|
||||
});
|
||||
}
|
||||
|
||||
// If we found no syncword at all, return empty — the data is not valid AC3.
|
||||
frames
|
||||
}
|
||||
|
||||
|
||||
+18
-4
@@ -144,10 +144,24 @@ impl CodecParser for HevcParser {
|
||||
} else {
|
||||
record.push(0);
|
||||
}
|
||||
// general_profile_compatibility_flags (4 bytes)
|
||||
record.extend_from_slice(&[0, 0, 0, 0]);
|
||||
// general_constraint_indicator_flags (6 bytes)
|
||||
record.extend_from_slice(&[0, 0, 0, 0, 0, 0]);
|
||||
// general_profile_compatibility_flags (4 bytes) — from SPS bytes 2..6
|
||||
if sps.len() > 5 {
|
||||
record.extend_from_slice(&sps[2..6]);
|
||||
} else {
|
||||
record.extend_from_slice(&[0, 0, 0, 0]);
|
||||
}
|
||||
// general_constraint_indicator_flags (6 bytes) — from SPS bytes 6..12
|
||||
if sps.len() > 11 {
|
||||
record.extend_from_slice(&sps[6..12]);
|
||||
} else {
|
||||
let avail = sps.len().saturating_sub(6).min(6);
|
||||
if avail > 0 {
|
||||
record.extend_from_slice(&sps[6..6 + avail]);
|
||||
record.extend_from_slice(&vec![0u8; 6 - avail]);
|
||||
} else {
|
||||
record.extend_from_slice(&[0, 0, 0, 0, 0, 0]);
|
||||
}
|
||||
}
|
||||
// general_level_idc
|
||||
record.push(if sps.len() > 12 { sps[12] } else { 0 });
|
||||
// min_spatial_segmentation_idc (4 + 12 bits)
|
||||
|
||||
+53
-3
@@ -14,6 +14,8 @@ const SC_FRAME: u8 = 0x0D;
|
||||
pub struct Vc1Parser {
|
||||
seq_header: Option<Vec<u8>>,
|
||||
entry_point: Option<Vec<u8>>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl Default for Vc1Parser {
|
||||
@@ -27,6 +29,8 @@ impl Vc1Parser {
|
||||
Self {
|
||||
seq_header: None,
|
||||
entry_point: None,
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +55,13 @@ impl CodecParser for Vc1Parser {
|
||||
match sc_type {
|
||||
SC_SEQUENCE_HEADER => {
|
||||
let end = find_next_sc(data, i + 4).unwrap_or(data.len());
|
||||
self.seq_header = Some(data[i..end].to_vec());
|
||||
let sh = &data[i..end];
|
||||
self.seq_header = Some(sh.to_vec());
|
||||
// Try to parse resolution from advanced profile sequence header
|
||||
if let Some((w, h)) = parse_vc1_resolution(sh) {
|
||||
self.width = w;
|
||||
self.height = h;
|
||||
}
|
||||
has_seq_header = true;
|
||||
}
|
||||
SC_ENTRY_POINT => {
|
||||
@@ -102,8 +112,8 @@ impl CodecParser for Vc1Parser {
|
||||
|
||||
// BITMAPINFOHEADER (40 bytes, little-endian)
|
||||
cp.extend_from_slice(&header_size.to_le_bytes()); // biSize
|
||||
cp.extend_from_slice(&1920u32.to_le_bytes()); // biWidth (updated by player)
|
||||
cp.extend_from_slice(&1080u32.to_le_bytes()); // biHeight
|
||||
cp.extend_from_slice(&self.width.to_le_bytes()); // biWidth
|
||||
cp.extend_from_slice(&self.height.to_le_bytes()); // biHeight
|
||||
cp.extend_from_slice(&1u16.to_le_bytes()); // biPlanes
|
||||
cp.extend_from_slice(&24u16.to_le_bytes()); // biBitCount
|
||||
cp.extend_from_slice(b"WVC1"); // biCompression = "WVC1" FOURCC
|
||||
@@ -121,6 +131,46 @@ impl CodecParser for Vc1Parser {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse width and height from a VC-1 advanced profile sequence header.
|
||||
/// The sequence header starts with 00 00 01 0F. After the start code:
|
||||
/// byte 0 bits 7-6: profile (3 = advanced)
|
||||
/// For advanced profile, the coded dimensions are encoded as 12-bit fields.
|
||||
fn parse_vc1_resolution(sh: &[u8]) -> Option<(u32, u32)> {
|
||||
// sh starts at the start code (00 00 01 0F ...)
|
||||
if sh.len() < 8 {
|
||||
return None;
|
||||
}
|
||||
let byte4 = sh[4]; // first byte after start code
|
||||
let profile = (byte4 >> 6) & 0x03;
|
||||
if profile != 3 {
|
||||
// Simple/Main profile: resolution not in sequence header
|
||||
return None;
|
||||
}
|
||||
// Advanced profile layout (bit-level starting from sh[4]):
|
||||
// profile(2) + level(3) + chroma_format(2) + quantizer_spec(3) +
|
||||
// postproc_flag(1) + max_coded_width(12) + max_coded_height(12) ...
|
||||
// Total bits before width: 2+3+2+3+1 = 11 bits
|
||||
// We need at least 11+12+12 = 35 bits = 5 bytes from sh[4..]
|
||||
if sh.len() < 9 {
|
||||
return None;
|
||||
}
|
||||
// Build a u64 from bytes 4..9 for easy bit extraction
|
||||
let mut bits: u64 = 0;
|
||||
for j in 0..5 {
|
||||
bits = (bits << 8) | sh[4 + j] as u64;
|
||||
}
|
||||
// bits has 40 bits. Skip first 11 bits, then read 12+12.
|
||||
let coded_width = ((bits >> (40 - 11 - 12)) & 0xFFF) as u32 + 1;
|
||||
let coded_height = ((bits >> (40 - 11 - 24)) & 0xFFF) as u32 + 1;
|
||||
let w = coded_width * 2;
|
||||
let h = coded_height * 2;
|
||||
if w > 0 && h > 0 && w <= 8192 && h <= 8192 {
|
||||
Some((w, h))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn find_next_sc(data: &[u8], from: usize) -> Option<usize> {
|
||||
(from..data.len().saturating_sub(2)).find(|&i| data[i] == 0x00 && data[i + 1] == 0x00 && data[i + 2] == 0x01)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user