1use std::io;
2
3use byteorder::ReadBytesExt;
4use bytes::Bytes;
5use scuffle_bytes_util::BitReader;
6use scuffle_expgolomb::BitReaderExpGolombExt;
7
8#[derive(Debug, Clone, PartialEq)]
9pub struct Sps {
12 pub width: u64,
14 pub height: u64,
16 pub frame_rate: f64,
18 pub color_config: Option<ColorConfig>,
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct ColorConfig {
25 pub full_range: bool,
27 pub color_primaries: u8,
29 pub transfer_characteristics: u8,
31 pub matrix_coefficients: u8,
33}
34
35impl Sps {
36 pub fn parse(data: Bytes) -> io::Result<Self> {
39 let mut vec = Vec::with_capacity(data.len());
40
41 let mut i = 0;
43 while i < data.len() {
44 if i + 2 < data.len() && data[i] == 0x00 && data[i + 1] == 0x00 && data[i + 2] == 0x03 {
45 vec.push(0x00);
46 vec.push(0x00);
47 } else {
48 vec.push(data[i]);
49 i += 1;
50 }
51 }
52
53 let mut bit_reader = BitReader::new_from_slice(vec);
54
55 let forbidden_zero_bit = bit_reader.read_bit()?;
56 if forbidden_zero_bit {
57 return Err(io::Error::new(io::ErrorKind::InvalidData, "forbidden_zero_bit is not zero"));
58 }
59
60 let nalu_type = bit_reader.read_bits(6)?;
61 if nalu_type != 33 {
62 return Err(io::Error::new(
63 io::ErrorKind::InvalidData,
64 "nalu_type is not 33", ));
66 }
67
68 bit_reader.seek_bits(
69 6 + 3 + 4, )?;
73
74 let sps_max_sub_layers_minus1 = bit_reader.read_bits(3)?;
75 bit_reader.seek_bits(1)?; {
77 bit_reader.seek_bits(
78 2 + 1 + 5 + 32 + 1 + 1 + 1 + 1 + 43 + 1 + 8, )?;
90
91 let mut sub_layer_level_present_flags = vec![false; sps_max_sub_layers_minus1 as usize];
92 for v in sub_layer_level_present_flags.iter_mut() {
93 bit_reader.seek_bits(1)?; *v = bit_reader.read_bit()?; }
96
97 if sps_max_sub_layers_minus1 > 0 && sps_max_sub_layers_minus1 < 8 {
98 bit_reader.seek_bits(2 * (8 - sps_max_sub_layers_minus1 as i64))?;
99 }
101
102 for v in sub_layer_level_present_flags.drain(..) {
103 bit_reader.seek_bits(
104 2 + 1 + 5 + 32 + 1 + 1 + 1 + 1 + 43 + 1, )?;
115 if v {
116 bit_reader.seek_bits(8)?; }
118 }
119 }
120
121 bit_reader.read_exp_golomb()?; let chroma_format_idc = bit_reader.read_exp_golomb()?;
123 if chroma_format_idc == 3 {
124 bit_reader.read_bit()?;
125 }
126 let pic_width_in_luma_samples = bit_reader.read_exp_golomb()?;
127 let pic_height_in_luma_samples = bit_reader.read_exp_golomb()?;
128 let conformance_window_flag = bit_reader.read_bit()?;
129
130 let conf_win_left_offset;
131 let conf_win_right_offset;
132 let conf_win_top_offset;
133 let conf_win_bottom_offset;
134
135 if conformance_window_flag {
136 conf_win_left_offset = bit_reader.read_exp_golomb()?;
137 conf_win_right_offset = bit_reader.read_exp_golomb()?;
138 conf_win_top_offset = bit_reader.read_exp_golomb()?;
139 conf_win_bottom_offset = bit_reader.read_exp_golomb()?;
140 } else {
141 conf_win_left_offset = 0;
142 conf_win_right_offset = 0;
143 conf_win_top_offset = 0;
144 conf_win_bottom_offset = 0;
145 }
146
147 let (sub_width_c, sub_height_c) = match chroma_format_idc {
148 0 => (1, 1),
149 1 => (2, 2),
150 2 => (2, 1),
151 3 => (1, 1),
152 _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "chroma_format_idc is not 0-3")),
153 };
154
155 let width = pic_width_in_luma_samples - sub_width_c * (conf_win_left_offset + conf_win_right_offset);
156 let height = pic_height_in_luma_samples - sub_height_c * (conf_win_top_offset + conf_win_bottom_offset);
157
158 bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; let sps_sub_layer_ordering_info_present_flag = bit_reader.read_bit()?;
162
163 if sps_sub_layer_ordering_info_present_flag {
164 for _ in 0..=sps_max_sub_layers_minus1 {
165 bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; }
169 };
170
171 bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; let scaling_list_enabled_flag = bit_reader.read_bit()?;
179 if scaling_list_enabled_flag {
180 let sps_scaling_list_data_present_flag = bit_reader.read_bit()?;
181 if sps_scaling_list_data_present_flag {
182 for size_id in 0..4 {
183 let mut matrix_id = 0;
184 while matrix_id < 6 {
185 let scaling_list_pred_mode_flag = bit_reader.read_bit()?;
186 if !scaling_list_pred_mode_flag {
187 bit_reader.read_exp_golomb()?; } else {
189 let coef_num = 64.min(1 << (4 + (size_id << 1)));
190 let mut next_coef = 8;
191 if size_id > 1 {
192 let scaling_list_dc_coef_minus8 = bit_reader.read_signed_exp_golomb()?;
193 next_coef = 8 + scaling_list_dc_coef_minus8;
194 }
195 for _ in 0..coef_num {
196 let scaling_list_delta_coef = bit_reader.read_signed_exp_golomb()?;
197 next_coef = (next_coef + scaling_list_delta_coef + 256) % 256;
198 }
199 }
200 matrix_id += if size_id == 3 { 3 } else { 1 };
201 }
202 }
203 }
204 }
205
206 bit_reader.seek_bits(1)?; bit_reader.seek_bits(1)?; if bit_reader.read_bit()? {
210 bit_reader.seek_bits(4)?; bit_reader.seek_bits(4)?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.seek_bits(1)?; }
217
218 let num_short_term_ref_pic_sets = bit_reader.read_exp_golomb()?;
219 let mut num_delta_pocs = vec![0; num_short_term_ref_pic_sets as usize];
220 for st_rps_idx in 0..num_short_term_ref_pic_sets {
221 if st_rps_idx != 0 && bit_reader.read_bit()? {
222 bit_reader.seek_bits(1)?;
223 bit_reader.read_exp_golomb()?; num_delta_pocs[st_rps_idx as usize] = 0;
226
227 for _ in 0..num_delta_pocs[(st_rps_idx - 1) as usize] {
228 let used_by_curr_pic_flag = bit_reader.read_bit()?;
229 let use_delta_flag = if !used_by_curr_pic_flag {
230 bit_reader.read_bit()? } else {
232 false
233 };
234
235 if used_by_curr_pic_flag || use_delta_flag {
236 num_delta_pocs[st_rps_idx as usize] += 1;
237 }
238 }
239 } else {
240 let num_negative_pics = bit_reader.read_exp_golomb()?;
241 let num_positive_pics = bit_reader.read_exp_golomb()?;
242
243 num_delta_pocs[st_rps_idx as usize] = num_negative_pics + num_positive_pics;
244 for _ in 0..num_negative_pics {
245 bit_reader.read_exp_golomb()?; bit_reader.seek_bits(1)?; }
248 for _ in 0..num_positive_pics {
249 bit_reader.read_exp_golomb()?; bit_reader.seek_bits(1)?; }
252 }
253 }
254
255 let long_term_ref_pics_present_flag = bit_reader.read_bit()?;
256 if long_term_ref_pics_present_flag {
257 let num_long_term_ref_pics_sps = bit_reader.read_exp_golomb()?;
258 for _ in 0..num_long_term_ref_pics_sps {
259 bit_reader.read_exp_golomb()?; bit_reader.seek_bits(1)?; }
262 }
263
264 bit_reader.seek_bits(1)?; bit_reader.seek_bits(1)?; let vui_parameters_present_flag = bit_reader.read_bit()?;
267
268 let mut color_config = None;
269
270 let mut frame_rate = 0.0;
271 if vui_parameters_present_flag {
272 let aspect_ratio_info_present_flag = bit_reader.read_bit()?;
273 if aspect_ratio_info_present_flag {
274 let aspect_ratio_idc = bit_reader.read_bits(8)?;
275 if aspect_ratio_idc == 255 {
276 bit_reader.seek_bits(16)?; bit_reader.seek_bits(16)?; }
279 }
280
281 let overscan_info_present_flag = bit_reader.read_bit()?;
282 if overscan_info_present_flag {
283 bit_reader.seek_bits(1)?; }
285
286 let video_signal_type_present_flag = bit_reader.read_bit()?;
287 if video_signal_type_present_flag {
288 bit_reader.seek_bits(3)?; let full_range = bit_reader.read_bit()?; let color_primaries;
291 let transfer_characteristics;
292 let matrix_coefficients;
293
294 let colour_description_present_flag = bit_reader.read_bit()?;
295 if colour_description_present_flag {
296 color_primaries = bit_reader.read_u8()?; transfer_characteristics = bit_reader.read_u8()?; matrix_coefficients = bit_reader.read_u8()?; } else {
300 color_primaries = 2; transfer_characteristics = 2; matrix_coefficients = 2; }
304
305 color_config = Some(ColorConfig {
306 full_range,
307 color_primaries,
308 transfer_characteristics,
309 matrix_coefficients,
310 });
311 }
312
313 let chroma_loc_info_present_flag = bit_reader.read_bit()?;
314 if chroma_loc_info_present_flag {
315 bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; }
318
319 bit_reader.seek_bits(1)?;
320 bit_reader.seek_bits(1)?;
321 bit_reader.seek_bits(1)?;
322 let default_display_window_flag = bit_reader.read_bit()?;
323
324 if default_display_window_flag {
325 bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; bit_reader.read_exp_golomb()?; }
330
331 let vui_timing_info_present_flag = bit_reader.read_bit()?;
332 if vui_timing_info_present_flag {
333 let num_units_in_tick = bit_reader.read_bits(32)?; let time_scale = bit_reader.read_bits(32)?; if num_units_in_tick == 0 {
337 return Err(io::Error::new(
338 io::ErrorKind::InvalidData,
339 "vui_num_units_in_tick cannot be zero",
340 ));
341 }
342
343 frame_rate = time_scale as f64 / num_units_in_tick as f64;
344 }
345 }
346
347 Ok(Sps {
348 width,
349 height,
350 frame_rate,
351 color_config,
352 })
353 }
354}
355
356#[cfg(test)]
357#[cfg_attr(all(test, coverage_nightly), coverage(off))]
358mod tests {
359 use bytes::Bytes;
360
361 use crate::{ColorConfig, Sps};
362
363 #[test]
364 fn test_sps_parse() {
365 let data = b"B\x01\x01\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\xa0\x01@ \x05\xa1e\x95R\x90\x84d_\xf8\xc0Z\x80\x80\x80\x82\0\0\x03\0\x02\0\0\x03\x01 \xc0\x0b\xbc\xa2\0\x02bX\0\x011-\x08".to_vec();
366
367 let sps = Sps::parse(Bytes::from(data.to_vec())).unwrap();
368 assert_eq!(
369 sps,
370 Sps {
371 color_config: Some(ColorConfig {
372 full_range: false,
373 color_primaries: 1,
374 matrix_coefficients: 1,
375 transfer_characteristics: 1,
376 }),
377 frame_rate: 144.0,
378 width: 2560,
379 height: 1440,
380 }
381 );
382 }
383
384 #[test]
385 fn test_parse_sps_with_zero_vui_num_units_in_tick() {
386 let sps = Bytes::from(b"B\x01\x01\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\xa0\x01@ \x05\xa1e\x95R\x90\x84d_\xf8\xc0Z\x80\0\x80\x82\0\0\x03\0\0\0\0\0\x01 \xc0\x0b\xbc\xa2\0\x02bX\0\x011-\x08".to_vec());
387 let sps = Sps::parse(sps);
388
389 match sps {
390 Ok(_) => panic!("Expected error for vui_num_units_in_tick = 0, but got Ok"),
391 Err(e) => assert_eq!(
392 e.kind(),
393 std::io::ErrorKind::InvalidData,
394 "Expected InvalidData error, got {:?}",
395 e
396 ),
397 }
398 }
399}