scuffle_h265/sps/
sps_scc_extension.rs1use std::io;
2
3use scuffle_bytes_util::BitReader;
4use scuffle_expgolomb::BitReaderExpGolombExt;
5
6use crate::range_check::range_check;
7
8#[derive(Debug, Clone, PartialEq)]
15pub struct SpsSccExtension {
16 pub sps_curr_pic_ref_enabled_flag: bool,
22 pub palette_mode: Option<SpsSccExtensionPaletteMode>,
24 pub motion_vector_resolution_control_idc: u8,
29 pub intra_boundary_filtering_disabled_flag: bool,
34}
35
36impl SpsSccExtension {
37 pub(crate) fn parse<R: io::Read>(
38 bit_reader: &mut BitReader<R>,
39 chroma_format_idc: u8,
40 bit_depth_y: u8,
41 bit_depth_c: u8,
42 ) -> io::Result<Self> {
43 let sps_curr_pic_ref_enabled_flag = bit_reader.read_bit()?;
44
45 let mut palette_mode = None;
46 let palette_mode_enabled_flag = bit_reader.read_bit()?;
47 if palette_mode_enabled_flag {
48 let palette_max_size = bit_reader.read_exp_golomb()?;
49 let delta_palette_max_predictor_size = bit_reader.read_exp_golomb()?;
50
51 if palette_max_size == 0 && delta_palette_max_predictor_size != 0 {
52 return Err(io::Error::new(
53 io::ErrorKind::InvalidData,
54 "delta_palette_max_predictor_size must be 0 when palette_max_size is 0",
55 ));
56 }
57
58 let sps_palette_predictor_initializers_present_flag = bit_reader.read_bit()?;
59 if palette_max_size == 0 && !sps_palette_predictor_initializers_present_flag {
60 return Err(io::Error::new(
61 io::ErrorKind::InvalidData,
62 "sps_palette_predictor_initializers_present_flag must be 0 when palette_max_size is 0",
63 ));
64 }
65
66 let mut sps_palette_predictor_initializers = None;
67 if sps_palette_predictor_initializers_present_flag {
68 let sps_num_palette_predictor_initializers_minus1 = bit_reader.read_exp_golomb()?;
69
70 if sps_num_palette_predictor_initializers_minus1 >= palette_max_size {
71 return Err(io::Error::new(
72 io::ErrorKind::InvalidData,
73 "sps_num_palette_predictor_initializers_minus1 + 1 must be less than or equal to palette_max_size",
74 ));
75 }
76
77 let num_comps = if chroma_format_idc == 0 { 1 } else { 3 };
78
79 let mut initializers = vec![vec![0; sps_num_palette_predictor_initializers_minus1 as usize + 1]; num_comps];
80 for (comp, initializer) in initializers.iter_mut().enumerate().take(num_comps) {
81 for sps_palette_predictor_initializer in initializer.iter_mut() {
82 let bit_depth = if comp == 0 { bit_depth_y } else { bit_depth_c };
83 *sps_palette_predictor_initializer = bit_reader.read_bits(bit_depth)?;
84 }
85 }
86
87 sps_palette_predictor_initializers = Some(initializers);
88 }
89
90 palette_mode = Some(SpsSccExtensionPaletteMode {
91 palette_max_size,
92 delta_palette_max_predictor_size,
93 sps_palette_predictor_initializers,
94 });
95 }
96
97 let motion_vector_resolution_control_idc = bit_reader.read_bits(2)? as u8;
98 range_check!(motion_vector_resolution_control_idc, 0, 2)?; let intra_boundary_filtering_disabled_flag = bit_reader.read_bit()?;
101
102 Ok(Self {
103 sps_curr_pic_ref_enabled_flag,
104 palette_mode,
105 motion_vector_resolution_control_idc,
106 intra_boundary_filtering_disabled_flag,
107 })
108 }
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub struct SpsSccExtensionPaletteMode {
114 pub palette_max_size: u64,
116 pub delta_palette_max_predictor_size: u64,
120 pub sps_palette_predictor_initializers: Option<Vec<Vec<u64>>>,
132}
133
134impl SpsSccExtensionPaletteMode {
135 pub fn palette_max_predictor_size(&self) -> u64 {
139 self.palette_max_size + self.delta_palette_max_predictor_size
140 }
141}
142
143#[cfg(test)]
144#[cfg_attr(all(test, coverage_nightly), coverage(off))]
145mod tests {
146 use byteorder::WriteBytesExt;
147 use scuffle_bytes_util::BitWriter;
148 use scuffle_expgolomb::BitWriterExpGolombExt;
149
150 #[test]
151 fn test_parse() {
152 let mut data = Vec::new();
153 let mut bit_writer = BitWriter::new(&mut data);
154
155 bit_writer.write_bit(true).unwrap(); bit_writer.write_bit(true).unwrap(); bit_writer.write_exp_golomb(5).unwrap(); bit_writer.write_exp_golomb(2).unwrap(); bit_writer.write_bit(true).unwrap(); bit_writer.write_exp_golomb(1).unwrap(); bit_writer.write_u8(1).unwrap(); bit_writer.write_u8(2).unwrap(); bit_writer.write_u8(3).unwrap(); bit_writer.write_u8(4).unwrap(); bit_writer.write_u8(5).unwrap(); bit_writer.write_u8(6).unwrap(); bit_writer.write_bits(0, 2).unwrap(); bit_writer.write_bit(false).unwrap(); bit_writer.write_bits(0, 8).unwrap(); let scc_extension = super::SpsSccExtension::parse(
177 &mut scuffle_bytes_util::BitReader::new(&data[..]),
178 1, 8, 8, )
182 .unwrap();
183
184 assert!(scc_extension.sps_curr_pic_ref_enabled_flag);
185
186 assert!(scc_extension.palette_mode.is_some());
187 let palette_mode = scc_extension.palette_mode.unwrap();
188 assert_eq!(palette_mode.palette_max_size, 5);
189 assert_eq!(palette_mode.delta_palette_max_predictor_size, 2);
190 assert_eq!(palette_mode.palette_max_predictor_size(), 7);
191
192 assert!(palette_mode.sps_palette_predictor_initializers.is_some());
193 let initializers = palette_mode.sps_palette_predictor_initializers.unwrap();
194 assert_eq!(initializers.len(), 3);
195 assert_eq!(initializers[0].len(), 2);
196 assert_eq!(initializers[0][0], 1);
197 assert_eq!(initializers[0][1], 2);
198 assert_eq!(initializers[1].len(), 2);
199 assert_eq!(initializers[1][0], 3);
200 assert_eq!(initializers[1][1], 4);
201 assert_eq!(initializers[2].len(), 2);
202 assert_eq!(initializers[2][0], 5);
203 assert_eq!(initializers[2][1], 6);
204
205 assert_eq!(scc_extension.motion_vector_resolution_control_idc, 0);
206 assert!(!scc_extension.intra_boundary_filtering_disabled_flag);
207 }
208}