scuffle_h264/sps/mod.rs
1mod chroma_sample_loc;
2use self::chroma_sample_loc::ChromaSampleLoc;
3
4mod color_config;
5use self::color_config::ColorConfig;
6
7mod frame_crop_info;
8use self::frame_crop_info::FrameCropInfo;
9
10mod pic_order_count_type1;
11use self::pic_order_count_type1::PicOrderCountType1;
12
13mod sample_aspect_ratio;
14use self::sample_aspect_ratio::SarDimensions;
15
16mod sps_ext;
17pub use self::sps_ext::SpsExtended;
18
19mod timing_info;
20use std::io;
21
22use byteorder::ReadBytesExt;
23use scuffle_bytes_util::{BitReader, BitWriter, EmulationPreventionIo};
24use scuffle_expgolomb::{BitReaderExpGolombExt, BitWriterExpGolombExt, size_of_exp_golomb};
25
26pub use self::timing_info::TimingInfo;
27use crate::NALUnitType;
28
29/// The Sequence Parameter Set.
30/// ISO/IEC-14496-10-2022 - 7.3.2
31#[derive(Debug, Clone, PartialEq)]
32pub struct Sps {
33 /// The `nal_ref_idc` is comprised of 2 bits.
34 ///
35 /// A nonzero value means the NAL unit has any of the following: SPS, SPS extension,
36 /// subset SPS, PPS, slice of a reference picture, slice of a data partition of a reference picture,
37 /// or a prefix NAL unit preceeding a slice of a reference picture.
38 ///
39 /// 0 means that the stream is decoded using the process from Clauses 2-9 (ISO/IEC-14496-10-2022)
40 /// that the slice or slice data partition is part of a non-reference picture.
41 /// Additionally, if `nal_ref_idc` is 0 for a NAL unit with `nal_unit_type`
42 /// ranging from \[1, 4\] then `nal_ref_idc` must be 0 for all NAL units with `nal_unit_type` between [1, 4].
43 ///
44 /// If the `nal_unit_type` is 5, then the `nal_ref_idc` cannot be 0.
45 ///
46 /// If `nal_unit_type` is 6, 9, 10, 11, or 12, then the `nal_ref_idc` must be 0.
47 ///
48 /// ISO/IEC-14496-10-2022 - 7.4.1
49 pub nal_ref_idc: u8,
50
51 /// The `nal_unit_type` is comprised of 5 bits. See the NALUnitType nutype enum for more info.
52 pub nal_unit_type: NALUnitType,
53
54 /// The `profile_idc` of the coded video sequence as a u8.
55 ///
56 /// It is comprised of 8 bits or 1 byte. ISO/IEC-14496-10-2022 - 7.4.2.1.1
57 pub profile_idc: u8,
58
59 /// `constraint_set0_flag`: `1` if it abides by the constraints in A.2.1, `0` if unsure or otherwise.
60 ///
61 /// If `profile_idc` is 44, 100, 110, 122, or 244, this is automatically set to false.
62 ///
63 /// It is a single bit. ISO/IEC-14496-10-2022 - 7.4.2.1.1
64 pub constraint_set0_flag: bool,
65
66 /// `constraint_set1_flag`: `1` if it abides by the constraints in A.2.2, `0` if unsure or otherwise.
67 ///
68 /// If `profile_idc` is 44, 100, 110, 122, or 244, this is automatically set to false.
69 ///
70 /// It is a single bit. ISO/IEC-14496-10-2022 - 7.4.2.1.1
71 pub constraint_set1_flag: bool,
72
73 /// `constraint_set2_flag`: `1` if it abides by the constraints in A.2.3, `0` if unsure or otherwise.
74 ///
75 /// If `profile_idc` is 44, 100, 110, 122, or 244, this is automatically set to false.
76 ///
77 /// It is a single bit. ISO/IEC-14496-10-2022 - 7.4.2.1.1
78 pub constraint_set2_flag: bool,
79
80 /// `constraint_set3_flag`:
81 /// ```text
82 /// if (profile_idc == 66, 77, or 88) AND (level_idc == 11):
83 /// 1 if it abides by the constraints in Annex A for level 1b
84 /// 0 if it abides by the constraints in Annex A for level 1.1
85 /// elif profile_idc == 100 or 110:
86 /// 1 if it abides by the constraints for the "High 10 Intra profile"
87 /// 0 if unsure or otherwise
88 /// elif profile_idc == 122:
89 /// 1 if it abides by the constraints in Annex A for the "High 4:2:2 Intra profile"
90 /// 0 if unsure or otherwise
91 /// elif profile_idc == 44:
92 /// 1 by default
93 /// 0 is not possible.
94 /// elif profile_idc == 244:
95 /// 1 if it abides by the constraints in Annex A for the "High 4:4:4 Intra profile"
96 /// 0 if unsure or otherwise
97 /// else:
98 /// 1 is reserved for future use
99 /// 0 otherwise
100 /// ```
101 ///
102 /// It is a single bit. ISO/IEC-14496-10-2022 - 7.4.2.1.1
103 pub constraint_set3_flag: bool,
104
105 /// `constraint_set4_flag`:
106 /// ```text
107 /// if (profile_idc == 77, 88, 100, or 110):
108 /// 1 if frame_mbs_only_flag == 1
109 /// 0 if unsure or otherwise
110 /// elif (profile_idc == 118, 128, or 134):
111 /// 1 if it abides by the constraints in G.6.1.1
112 /// 0 if unsure or otherwise
113 /// else:
114 /// 1 is reserved for future use
115 /// 0 otherwise
116 /// ```
117 ///
118 /// It is a single bit. ISO/IEC-14496-10-2022 - 7.4.2.1.1
119 pub constraint_set4_flag: bool,
120
121 /// `constraint_set5_flag`:
122 /// ```text
123 /// if (profile_idc == 77, 88, or 100):
124 /// 1 if there are no B slice types
125 /// 0 if unsure or otherwise
126 /// elif profile_idc == 118:
127 /// 1 if it abides by the constraints in G.6.1.2
128 /// 0 if unsure or otherwise
129 /// else:
130 /// 1 is reserved for future use
131 /// 0 otherwise
132 /// ```
133 ///
134 /// It is a single bit. ISO/IEC-14496-10-2022 - 7.4.2.1.1
135 pub constraint_set5_flag: bool,
136
137 /// The `level_idc` of the coded video sequence as a u8.
138 ///
139 /// It is comprised of 8 bits or 1 byte. ISO/IEC-14496-10-2022 - 7.4.2.1.1
140 pub level_idc: u8,
141
142 /// The `seq_parameter_set_id` is the id of the SPS referred to by the PPS (picture parameter set).
143 ///
144 /// The value of this ranges from \[0, 31\].
145 ///
146 /// This is a variable number of bits as it is encoded by an exp golomb (unsigned).
147 /// The smallest encoding would be for `0` which is encoded as `1`, which is a single bit.
148 /// The largest encoding would be for `31` which is encoded as `000 0010 0000`, which is 11 bits.
149 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
150 ///
151 /// For more information:
152 ///
153 /// <https://en.wikipedia.org/wiki/Exponential-Golomb_coding>
154 pub seq_parameter_set_id: u16,
155
156 /// An optional `SpsExtended`. Refer to the SpsExtended struct for more info.
157 ///
158 /// This will be parsed if `profile_idc` is equal to any of the following values:
159 /// 44, 83, 86, 100, 110, 118, 122, 128, 134, 135, 138, 139, or 244.
160 pub ext: Option<SpsExtended>,
161
162 /// The `log2_max_frame_num_minus4` is the value used when deriving MaxFrameNum from the equation:
163 /// `MaxFrameNum` = 2^(`log2_max_frame_num_minus4` + 4)
164 ///
165 /// The value of this ranges from \[0, 12\].
166 ///
167 /// This is a variable number of bits as it is encoded by an exp golomb (unsigned).
168 /// The smallest encoding would be for `0` which is encoded as `1`, which is a single bit.
169 /// The largest encoding would be for `12` which is encoded as `000 1101`, which is 7 bits.
170 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
171 ///
172 /// For more information:
173 ///
174 /// <https://en.wikipedia.org/wiki/Exponential-Golomb_coding>
175 pub log2_max_frame_num_minus4: u8,
176
177 /// The `pic_order_cnt_type` specifies how to decode the picture order count in subclause 8.2.1.
178 ///
179 /// The value of this ranges from \[0, 2\].
180 ///
181 /// This is a variable number of bits as it is encoded by an exp golomb (unsigned).
182 /// The smallest encoding would be for `0` which is encoded as `1`, which is a single bit.
183 /// The largest encoding would be for `2` which is encoded as `011`, which is 3 bits.
184 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
185 ///
186 /// For more information:
187 ///
188 /// <https://en.wikipedia.org/wiki/Exponential-Golomb_coding>
189 ///
190 /// There are a few subsequent fields that are read if `pic_order_cnt_type` is 0 or 1.
191 ///
192 /// In the case of 0, `log2_max_pic_order_cnt_lsb_minus4` is read as an exp golomb (unsigned).
193 ///
194 /// In the case of 1, `delta_pic_order_always_zero_flag`, `offset_for_non_ref_pic`,
195 /// `offset_for_top_to_bottom_field`, `num_ref_frames_in_pic_order_cnt_cycle` and
196 /// `offset_for_ref_frame` will be read and stored in pic_order_cnt_type1.
197 ///
198 /// Refer to the PicOrderCountType1 struct for more info.
199 pub pic_order_cnt_type: u8,
200
201 /// The `log2_max_pic_order_cnt_lsb_minus4` is the value used when deriving MaxFrameNum from the equation:
202 /// `MaxPicOrderCntLsb` = 2^(`log2_max_frame_num_minus4` + 4) from subclause 8.2.1.
203 ///
204 /// This is an `Option<u8>` because the value is only set if `pic_order_cnt_type == 0`.
205 ///
206 /// The value of this ranges from \[0, 12\].
207 ///
208 /// This is a variable number of bits as it is encoded by an exp golomb (unsigned).
209 /// The smallest encoding would be for `0` which is encoded as `1`, which is a single bit.
210 /// The largest encoding would be for `12` which is encoded as `000 1101`, which is 7 bits.
211 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
212 ///
213 /// For more information:
214 ///
215 /// <https://en.wikipedia.org/wiki/Exponential-Golomb_coding>
216 pub log2_max_pic_order_cnt_lsb_minus4: Option<u8>,
217
218 /// An optional `PicOrderCountType1`. This is computed from other fields, and isn't directly set.
219 ///
220 /// If `pic_order_cnt_type == 1`, then the `PicOrderCountType1` will be computed.
221 ///
222 /// Refer to the PicOrderCountType1 struct for more info.
223 pub pic_order_cnt_type1: Option<PicOrderCountType1>,
224
225 /// The `max_num_ref_frames` is the max short-term and long-term reference frames,
226 /// complementary reference field pairs, and non-paired reference fields that
227 /// can be used by the decoder for inter-prediction of pictures in the coded video.
228 ///
229 /// The value of this ranges from \[0, `MaxDpbFrames`\], which is specified in subclause A.3.1 or A.3.2.
230 ///
231 /// This is a variable number of bits as it is encoded by an exp golomb (unsigned).
232 /// The smallest encoding would be for `0` which is encoded as `1`, which is a single bit.
233 /// The largest encoding would be for `14` which is encoded as `000 1111`, which is 7 bits.
234 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
235 ///
236 /// For more information:
237 ///
238 /// <https://en.wikipedia.org/wiki/Exponential-Golomb_coding>
239 pub max_num_ref_frames: u8,
240
241 /// The `gaps_in_frame_num_value_allowed_flag` is a single bit.
242 ///
243 /// The value specifies the allowed values of `frame_num` from subclause 7.4.3 and the decoding process
244 /// if there is an inferred gap between the values of `frame_num` from subclause 8.2.5.2.
245 pub gaps_in_frame_num_value_allowed_flag: bool,
246
247 /// The `pic_width_in_mbs_minus1` is the width of each decoded picture in macroblocks as a u64.
248 ///
249 /// We then use this (along with the left and right frame crop offsets) to calculate the width as:
250 ///
251 /// `width = ((pic_width_in_mbs_minus1 + 1) * 16) - frame_crop_right_offset * 2 - frame_crop_left_offset * 2`
252 ///
253 /// This is a variable number of bits as it is encoded by an exp golomb (unsigned).
254 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
255 ///
256 /// For more information:
257 ///
258 /// <https://en.wikipedia.org/wiki/Exponential-Golomb_coding>
259 pub pic_width_in_mbs_minus1: u64,
260
261 /// The `pic_height_in_map_units_minus1` is the height of each decoded frame in slice group map units as a u64.
262 ///
263 /// We then use this (along with the bottom and top frame crop offsets) to calculate the height as:
264 ///
265 /// `height = ((2 - frame_mbs_only_flag as u64) * (pic_height_in_map_units_minus1 + 1) * 16) -
266 /// frame_crop_bottom_offset * 2 - frame_crop_top_offset * 2`
267 ///
268 /// This is a variable number of bits as it is encoded by an exp golomb (unsigned).
269 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
270 ///
271 /// For more information:
272 ///
273 /// <https://en.wikipedia.org/wiki/Exponential-Golomb_coding>
274 pub pic_height_in_map_units_minus1: u64,
275
276 /// The `mb_adaptive_frame_field_flag` is a single bit.
277 ///
278 /// If `frame_mbs_only_flag` is NOT set then this field is read and stored.
279 ///
280 /// 0 means there is no switching between frame and field macroblocks in a picture.
281 ///
282 /// 1 means the might be switching between frame and field macroblocks in a picture.
283 ///
284 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
285 pub mb_adaptive_frame_field_flag: Option<bool>,
286
287 /// The `direct_8x8_inference_flag` specifies the method used to derive the luma motion
288 /// vectors for B_Skip, B_Direct_8x8 and B_Direct_16x16 from subclause 8.4.1.2, and is a single bit.
289 ///
290 /// ISO/IEC-14496-10-2022 - 7.4.2.1.1
291 pub direct_8x8_inference_flag: bool,
292
293 /// An optional `frame_crop_info` struct. This is computed by other fields, and isn't directly set.
294 ///
295 /// If the `frame_cropping_flag` is set, then `frame_crop_left_offset`, `frame_crop_right_offset`,
296 /// `frame_crop_top_offset`, and `frame_crop_bottom_offset` will be read and stored.
297 ///
298 /// Refer to the FrameCropInfo struct for more info.
299 pub frame_crop_info: Option<FrameCropInfo>,
300
301 /// An optional `SarDimensions` struct. This is computed by other fields, and isn't directly set.
302 ///
303 /// If the `aspect_ratio_info_present_flag` is set, then the `aspect_ratio_idc` will be read and stored.
304 ///
305 /// If the `aspect_ratio_idc` is 255, then the `sar_width` and `sar_height` will be read and stored.
306 ///
307 /// Also known as `sample_aspect_ratio` in the spec.
308 ///
309 /// The default values are set to 0 for the `aspect_ratio_idc`, `sar_width`, and `sar_height`.
310 /// Therefore, this will always be returned by the parse function.
311 /// ISO/IEC-14496-10-2022 - E.2.1
312 ///
313 /// Refer to the SarDimensions struct for more info.
314 pub sample_aspect_ratio: Option<SarDimensions>,
315
316 /// An optional `overscan_appropriate_flag` is a single bit.
317 ///
318 /// If the `overscan_info_present_flag` is set, then this field will be read and stored.
319 ///
320 /// 0 means the overscan should not be used. (ex: screensharing or security cameras)
321 ///
322 /// 1 means the overscan can be used. (ex: entertainment TV programming or live video conference)
323 ///
324 /// ISO/IEC-14496-10-2022 - E.2.1
325 pub overscan_appropriate_flag: Option<bool>,
326
327 /// An optional `ColorConfig`. This is computed from other fields, and isn't directly set.
328 ///
329 /// If `video_signal_type_present_flag` is set, then the `ColorConfig` will be computed, and
330 /// if the `color_description_present_flag` is set, then the `ColorConfig` will be
331 /// comprised of the `video_full_range_flag` (1 bit), `color_primaries` (1 byte as a u8),
332 /// `transfer_characteristics` (1 byte as a u8), and `matrix_coefficients` (1 byte as a u8).
333 ///
334 /// Otherwise, `color_primaries`, `transfer_characteristics`, and `matrix_coefficients` are set
335 /// to 2 (unspecified) by default.
336 ///
337 /// Refer to the ColorConfig struct for more info.
338 pub color_config: Option<ColorConfig>,
339
340 /// An optional `ChromaSampleLoc`. This is computed from other fields, and isn't directly set.
341 ///
342 /// If `chrome_loc_info_present_flag` is set, then the `ChromaSampleLoc` will be computed, and
343 /// is comprised of `chroma_sample_loc_type_top_field` and `chroma_sample_loc_type_bottom_field`.
344 ///
345 /// Refer to the ChromaSampleLoc struct for more info.
346 pub chroma_sample_loc: Option<ChromaSampleLoc>,
347
348 /// An optional `TimingInfo`. This is computed from other fields, and isn't directly set.
349 ///
350 /// If `timing_info_present_flag` is set, then the `TimingInfo` will be computed, and
351 /// is comprised of `num_units_in_tick` and `time_scale`.
352 ///
353 /// Refer to the TimingInfo struct for more info.
354 pub timing_info: Option<TimingInfo>,
355}
356
357impl Sps {
358 /// Parses an Sps from the input bytes.
359 ///
360 /// Returns an `Sps` struct.
361 pub fn parse(reader: impl io::Read) -> io::Result<Self> {
362 let mut bit_reader = BitReader::new(reader);
363
364 let forbidden_zero_bit = bit_reader.read_bit()?;
365 if forbidden_zero_bit {
366 return Err(io::Error::new(io::ErrorKind::InvalidData, "Forbidden zero bit is set"));
367 }
368
369 let nal_ref_idc = bit_reader.read_bits(2)? as u8;
370 let nal_unit_type = bit_reader.read_bits(5)? as u8;
371 if NALUnitType(nal_unit_type) != NALUnitType::SPS {
372 return Err(io::Error::new(io::ErrorKind::InvalidData, "NAL unit type is not SPS"));
373 }
374
375 let profile_idc = bit_reader.read_u8()?;
376
377 let constraint_set0_flag;
378 let constraint_set1_flag;
379 let constraint_set2_flag;
380
381 match profile_idc {
382 // 7.4.2.1.1
383 44 | 100 | 110 | 122 | 244 => {
384 // constraint_set0 thru 2 must be false in this case
385 bit_reader.read_bits(3)?;
386 constraint_set0_flag = false;
387 constraint_set1_flag = false;
388 constraint_set2_flag = false;
389 }
390 _ => {
391 // otherwise we parse the bits as expected
392 constraint_set0_flag = bit_reader.read_bit()?;
393 constraint_set1_flag = bit_reader.read_bit()?;
394 constraint_set2_flag = bit_reader.read_bit()?;
395 }
396 }
397
398 let constraint_set3_flag = if profile_idc == 44 {
399 bit_reader.read_bit()?;
400 false
401 } else {
402 bit_reader.read_bit()?
403 };
404
405 let constraint_set4_flag = match profile_idc {
406 // 7.4.2.1.1
407 77 | 88 | 100 | 118 | 128 | 134 => bit_reader.read_bit()?,
408 _ => {
409 bit_reader.read_bit()?;
410 false
411 }
412 };
413
414 let constraint_set5_flag = match profile_idc {
415 77 | 88 | 100 | 118 => bit_reader.read_bit()?,
416 _ => {
417 bit_reader.read_bit()?;
418 false
419 }
420 };
421 // reserved_zero_2bits
422 bit_reader.read_bits(2)?;
423
424 let level_idc = bit_reader.read_u8()?;
425 let seq_parameter_set_id = bit_reader.read_exp_golomb()? as u16;
426
427 let sps_ext = match profile_idc {
428 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135 => {
429 Some(SpsExtended::parse(&mut bit_reader)?)
430 }
431 _ => None,
432 };
433
434 let log2_max_frame_num_minus4 = bit_reader.read_exp_golomb()? as u8;
435 let pic_order_cnt_type = bit_reader.read_exp_golomb()? as u8;
436
437 let mut log2_max_pic_order_cnt_lsb_minus4 = None;
438 let mut pic_order_cnt_type1 = None;
439
440 if pic_order_cnt_type == 0 {
441 log2_max_pic_order_cnt_lsb_minus4 = Some(bit_reader.read_exp_golomb()? as u8);
442 } else if pic_order_cnt_type == 1 {
443 pic_order_cnt_type1 = Some(PicOrderCountType1::parse(&mut bit_reader)?)
444 }
445
446 let max_num_ref_frames = bit_reader.read_exp_golomb()? as u8;
447 let gaps_in_frame_num_value_allowed_flag = bit_reader.read_bit()?;
448 let pic_width_in_mbs_minus1 = bit_reader.read_exp_golomb()?;
449 let pic_height_in_map_units_minus1 = bit_reader.read_exp_golomb()?;
450
451 let frame_mbs_only_flag = bit_reader.read_bit()?;
452 let mut mb_adaptive_frame_field_flag = None;
453 if !frame_mbs_only_flag {
454 mb_adaptive_frame_field_flag = Some(bit_reader.read_bit()?);
455 }
456
457 let direct_8x8_inference_flag = bit_reader.read_bit()?;
458
459 let mut frame_crop_info = None;
460
461 let frame_cropping_flag = bit_reader.read_bit()?;
462 if frame_cropping_flag {
463 frame_crop_info = Some(FrameCropInfo::parse(&mut bit_reader)?)
464 }
465
466 // setting default values for vui section
467 let mut sample_aspect_ratio = None;
468 let mut overscan_appropriate_flag = None;
469 let mut color_config = None;
470 let mut chroma_sample_loc = None;
471 let mut timing_info = None;
472
473 let vui_parameters_present_flag = bit_reader.read_bit()?;
474 if vui_parameters_present_flag {
475 // We read the VUI parameters to get the frame rate.
476
477 let aspect_ratio_info_present_flag = bit_reader.read_bit()?;
478 if aspect_ratio_info_present_flag {
479 sample_aspect_ratio = Some(SarDimensions::parse(&mut bit_reader)?)
480 }
481
482 let overscan_info_present_flag = bit_reader.read_bit()?;
483 if overscan_info_present_flag {
484 overscan_appropriate_flag = Some(bit_reader.read_bit()?);
485 }
486
487 let video_signal_type_present_flag = bit_reader.read_bit()?;
488 if video_signal_type_present_flag {
489 color_config = Some(ColorConfig::parse(&mut bit_reader)?)
490 }
491
492 let chroma_loc_info_present_flag = bit_reader.read_bit()?;
493 if sps_ext.as_ref().unwrap_or(&SpsExtended::default()).chroma_format_idc != 1 && chroma_loc_info_present_flag {
494 return Err(io::Error::new(
495 io::ErrorKind::InvalidData,
496 "chroma_loc_info_present_flag cannot be set to 1 when chroma_format_idc is not 1",
497 ));
498 }
499
500 if chroma_loc_info_present_flag {
501 chroma_sample_loc = Some(ChromaSampleLoc::parse(&mut bit_reader)?)
502 }
503
504 let timing_info_present_flag = bit_reader.read_bit()?;
505 if timing_info_present_flag {
506 timing_info = Some(TimingInfo::parse(&mut bit_reader)?)
507 }
508 }
509
510 Ok(Sps {
511 nal_ref_idc,
512 nal_unit_type: NALUnitType(nal_unit_type),
513 profile_idc,
514 constraint_set0_flag,
515 constraint_set1_flag,
516 constraint_set2_flag,
517 constraint_set3_flag,
518 constraint_set4_flag,
519 constraint_set5_flag,
520 level_idc,
521 seq_parameter_set_id,
522 ext: sps_ext,
523 log2_max_frame_num_minus4,
524 pic_order_cnt_type,
525 log2_max_pic_order_cnt_lsb_minus4,
526 pic_order_cnt_type1,
527 max_num_ref_frames,
528 gaps_in_frame_num_value_allowed_flag,
529 pic_width_in_mbs_minus1,
530 pic_height_in_map_units_minus1,
531 mb_adaptive_frame_field_flag,
532 direct_8x8_inference_flag,
533 frame_crop_info,
534 sample_aspect_ratio,
535 overscan_appropriate_flag,
536 color_config,
537 chroma_sample_loc,
538 timing_info,
539 })
540 }
541
542 /// Builds the Sps struct into a byte stream.
543 /// Returns a built byte stream.
544 pub fn build(&self, writer: impl io::Write) -> io::Result<()> {
545 let mut bit_writer = BitWriter::new(writer);
546
547 bit_writer.write_bit(false)?;
548 bit_writer.write_bits(self.nal_ref_idc as u64, 2)?;
549 bit_writer.write_bits(self.nal_unit_type.0 as u64, 5)?;
550 bit_writer.write_bits(self.profile_idc as u64, 8)?;
551
552 bit_writer.write_bit(self.constraint_set0_flag)?;
553 bit_writer.write_bit(self.constraint_set1_flag)?;
554 bit_writer.write_bit(self.constraint_set2_flag)?;
555 bit_writer.write_bit(self.constraint_set3_flag)?;
556 bit_writer.write_bit(self.constraint_set4_flag)?;
557 bit_writer.write_bit(self.constraint_set5_flag)?;
558 // reserved 2 bits
559 bit_writer.write_bits(0, 2)?;
560
561 bit_writer.write_bits(self.level_idc as u64, 8)?;
562 bit_writer.write_exp_golomb(self.seq_parameter_set_id as u64)?;
563
564 // sps ext
565 if let Some(ext) = &self.ext {
566 ext.build(&mut bit_writer)?;
567 }
568
569 bit_writer.write_exp_golomb(self.log2_max_frame_num_minus4 as u64)?;
570 bit_writer.write_exp_golomb(self.pic_order_cnt_type as u64)?;
571
572 if self.pic_order_cnt_type == 0 {
573 bit_writer.write_exp_golomb(self.log2_max_pic_order_cnt_lsb_minus4.unwrap() as u64)?;
574 } else if let Some(pic_order_cnt) = &self.pic_order_cnt_type1 {
575 pic_order_cnt.build(&mut bit_writer)?;
576 }
577
578 bit_writer.write_exp_golomb(self.max_num_ref_frames as u64)?;
579 bit_writer.write_bit(self.gaps_in_frame_num_value_allowed_flag)?;
580 bit_writer.write_exp_golomb(self.pic_width_in_mbs_minus1)?;
581 bit_writer.write_exp_golomb(self.pic_height_in_map_units_minus1)?;
582
583 bit_writer.write_bit(self.mb_adaptive_frame_field_flag.is_none())?;
584 if let Some(flag) = self.mb_adaptive_frame_field_flag {
585 bit_writer.write_bit(flag)?;
586 }
587
588 bit_writer.write_bit(self.direct_8x8_inference_flag)?;
589
590 bit_writer.write_bit(self.frame_crop_info.is_some())?;
591 if let Some(frame_crop_info) = &self.frame_crop_info {
592 frame_crop_info.build(&mut bit_writer)?;
593 }
594
595 match (
596 &self.sample_aspect_ratio,
597 &self.overscan_appropriate_flag,
598 &self.color_config,
599 &self.chroma_sample_loc,
600 &self.timing_info,
601 ) {
602 (None, None, None, None, None) => {
603 bit_writer.write_bit(false)?;
604 }
605 _ => {
606 // vui_parameters_present_flag
607 bit_writer.write_bit(true)?;
608
609 // aspect_ratio_info_present_flag
610 bit_writer.write_bit(self.sample_aspect_ratio.is_some())?;
611 if let Some(sar) = &self.sample_aspect_ratio {
612 sar.build(&mut bit_writer)?;
613 }
614
615 // overscan_info_present_flag
616 bit_writer.write_bit(self.overscan_appropriate_flag.is_some())?;
617 if let Some(overscan) = &self.overscan_appropriate_flag {
618 bit_writer.write_bit(*overscan)?;
619 }
620
621 // video_signal_type_prsent_flag
622 bit_writer.write_bit(self.color_config.is_some())?;
623 if let Some(color) = &self.color_config {
624 color.build(&mut bit_writer)?;
625 }
626
627 // chroma_log_info_present_flag
628 bit_writer.write_bit(self.chroma_sample_loc.is_some())?;
629 if let Some(chroma) = &self.chroma_sample_loc {
630 chroma.build(&mut bit_writer)?;
631 }
632
633 // timing_info_present_flag
634 bit_writer.write_bit(self.timing_info.is_some())?;
635 if let Some(timing) = &self.timing_info {
636 timing.build(&mut bit_writer)?;
637 }
638 }
639 }
640 bit_writer.finish()?;
641
642 Ok(())
643 }
644
645 /// Parses the Sps struct from a reader that may contain emulation prevention bytes.
646 /// Is the same as calling [`Self::parse`] with an [`EmulationPreventionIo`] wrapper.
647 pub fn parse_with_emulation_prevention(reader: impl io::Read) -> io::Result<Self> {
648 Self::parse(EmulationPreventionIo::new(reader))
649 }
650
651 /// Builds the Sps struct into a byte stream that may contain emulation prevention bytes.
652 /// Is the same as calling [`Self::build`] with an [`EmulationPreventionIo`] wrapper.
653 pub fn build_with_emulation_prevention(self, writer: impl io::Write) -> io::Result<()> {
654 self.build(EmulationPreventionIo::new(writer))
655 }
656
657 /// Returns the total byte size of the Sps struct.
658 pub fn size(&self) -> u64 {
659 (1 + // forbidden zero bit
660 2 + // nal_ref_idc
661 5 + // nal_unit_type
662 8 + // profile_idc
663 8 + // 6 constraint_setn_flags + 2 reserved bits
664 8 + // level_idc
665 size_of_exp_golomb(self.seq_parameter_set_id as u64) +
666 self.ext.as_ref().map_or(0, |ext| ext.bitsize()) +
667 size_of_exp_golomb(self.log2_max_frame_num_minus4 as u64) +
668 size_of_exp_golomb(self.pic_order_cnt_type as u64) +
669 match self.pic_order_cnt_type {
670 0 => size_of_exp_golomb(self.log2_max_pic_order_cnt_lsb_minus4.unwrap() as u64),
671 1 => self.pic_order_cnt_type1.as_ref().unwrap().bitsize(),
672 _ => 0
673 } +
674 size_of_exp_golomb(self.max_num_ref_frames as u64) +
675 1 + // gaps_in_frame_num_value_allowed_flag
676 size_of_exp_golomb(self.pic_width_in_mbs_minus1) +
677 size_of_exp_golomb(self.pic_height_in_map_units_minus1) +
678 1 + // frame_mbs_only_flag
679 self.mb_adaptive_frame_field_flag.is_some() as u64 +
680 1 + // direct_8x8_inference_flag
681 1 + // frame_cropping_flag
682 self.frame_crop_info.as_ref().map_or(0, |frame| frame.bitsize()) +
683 1 + // vui_parameters_present_flag
684 if matches!(
685 (&self.sample_aspect_ratio, &self.overscan_appropriate_flag, &self.color_config, &self.chroma_sample_loc, &self.timing_info),
686 (None, None, None, None, None)
687 ) {
688 0
689 } else {
690 self.sample_aspect_ratio.as_ref().map_or(1, |sar| 1 + sar.bitsize()) +
691 self.overscan_appropriate_flag.map_or(1, |_| 2) +
692 self.color_config.as_ref().map_or(1, |color| 1 + color.bitsize()) +
693 self.chroma_sample_loc.as_ref().map_or(1, |chroma| 1 + chroma.bitsize()) +
694 self.timing_info.as_ref().map_or(1, |timing| 1 + timing.bitsize())
695 }).div_ceil(8)
696 }
697
698 /// The height as a u64. This is computed from other fields, and isn't directly set.
699 ///
700 /// `height = ((2 - frame_mbs_only_flag as u64) * (pic_height_in_map_units_minus1 + 1) * 16) -
701 /// frame_crop_bottom_offset * 2 - frame_crop_top_offset * 2`
702 ///
703 /// We don't directly store `frame_mbs_only_flag` since we can tell if it's set:
704 /// If `mb_adaptive_frame_field_flag` is None, then `frame_mbs_only_flag` is set (1).
705 /// Otherwise `mb_adaptive_frame_field_flag` unset (0).
706 pub fn height(&self) -> u64 {
707 let base_height =
708 (2 - self.mb_adaptive_frame_field_flag.is_none() as u64) * (self.pic_height_in_map_units_minus1 + 1) * 16;
709
710 self.frame_crop_info.as_ref().map_or(base_height, |crop| {
711 base_height - (crop.frame_crop_top_offset + crop.frame_crop_bottom_offset) * 2
712 })
713 }
714
715 /// The width as a u64. This is computed from other fields, and isn't directly set.
716 ///
717 /// `width = ((pic_width_in_mbs_minus1 + 1) * 16) - frame_crop_right_offset * 2 - frame_crop_left_offset * 2`
718 pub fn width(&self) -> u64 {
719 let base_width = (self.pic_width_in_mbs_minus1 + 1) * 16;
720
721 self.frame_crop_info.as_ref().map_or(base_width, |crop| {
722 base_width - (crop.frame_crop_left_offset + crop.frame_crop_right_offset) * 2
723 })
724 }
725
726 /// Returns the frame rate as a f64.
727 ///
728 /// If `timing_info_present_flag` is set, then the `frame_rate` will be computed, and
729 /// if `num_units_in_tick` is nonzero, then the framerate will be:
730 /// `frame_rate = time_scale as f64 / (2.0 * num_units_in_tick as f64)`
731 pub fn frame_rate(&self) -> Option<f64> {
732 self.timing_info.as_ref().map(|timing| timing.frame_rate())
733 }
734}
735
736#[cfg(test)]
737#[cfg_attr(all(test, coverage_nightly), coverage(off))]
738mod tests {
739 use std::io;
740
741 use scuffle_bytes_util::BitWriter;
742 use scuffle_expgolomb::{BitWriterExpGolombExt, size_of_exp_golomb, size_of_signed_exp_golomb};
743
744 use crate::sps::Sps;
745
746 #[test]
747 fn test_parse_sps_set_forbidden_bit() {
748 let mut sps = Vec::new();
749 let mut writer = BitWriter::new(&mut sps);
750
751 writer.write_bit(true).unwrap(); // sets the forbidden bit
752 writer.finish().unwrap();
753
754 let result = Sps::parse(std::io::Cursor::new(sps));
755
756 assert!(result.is_err());
757 let err = result.unwrap_err();
758
759 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
760 assert_eq!(err.to_string(), "Forbidden zero bit is set");
761 }
762
763 #[test]
764 fn test_parse_sps_invalid_nal() {
765 let mut sps = Vec::new();
766 let mut writer = BitWriter::new(&mut sps);
767
768 writer.write_bit(false).unwrap(); // forbidden zero bit must be unset
769 writer.write_bits(0b00, 2).unwrap(); // nal_ref_idc is 00
770 writer.write_bits(0b000, 3).unwrap(); // set nal_unit_type to something that isn't 7
771 writer.finish().unwrap();
772
773 let result = Sps::parse(std::io::Cursor::new(sps));
774
775 assert!(result.is_err());
776 let err = result.unwrap_err();
777
778 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
779 assert_eq!(err.to_string(), "NAL unit type is not SPS");
780 }
781
782 #[test]
783 fn test_parse_build_sps_4k_144fps() {
784 let mut sps = Vec::new();
785 let mut writer = BitWriter::new(&mut sps);
786
787 // forbidden zero bit must be unset
788 writer.write_bit(false).unwrap();
789 // nal_ref_idc is 0
790 writer.write_bits(0, 2).unwrap();
791 // nal_unit_type must be 7
792 writer.write_bits(7, 5).unwrap();
793
794 // profile_idc = 100
795 writer.write_bits(100, 8).unwrap();
796 // constraint_setn_flags all false
797 writer.write_bits(0, 8).unwrap();
798 // level_idc = 0
799 writer.write_bits(0, 8).unwrap();
800
801 // seq_parameter_set_id is expg
802 writer.write_exp_golomb(0).unwrap();
803
804 // sps ext
805 // chroma_format_idc is expg
806 writer.write_exp_golomb(0).unwrap();
807 // bit_depth_luma_minus8 is expg
808 writer.write_exp_golomb(0).unwrap();
809 // bit_depth_chroma_minus8 is expg
810 writer.write_exp_golomb(0).unwrap();
811 // qpprime
812 writer.write_bit(false).unwrap();
813 // seq_scaling_matrix_present_flag
814 writer.write_bit(false).unwrap();
815
816 // back to sps
817 // log2_max_frame_num_minus4 is expg
818 writer.write_exp_golomb(0).unwrap();
819 // pic_order_cnt_type is expg
820 writer.write_exp_golomb(0).unwrap();
821 // log2_max_pic_order_cnt_lsb_minus4 is expg
822 writer.write_exp_golomb(0).unwrap();
823
824 // max_num_ref_frames is expg
825 writer.write_exp_golomb(0).unwrap();
826 // gaps_in_frame_num_value_allowed_flag
827 writer.write_bit(false).unwrap();
828 // 3840 width:
829 // 3840 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
830 // we set offset1 and offset2 to both be 0 later
831 // 3840 = (p + 1) * 16
832 // p = 239
833 writer.write_exp_golomb(239).unwrap();
834 // we want 2160 height:
835 // 2160 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
836 // we set offset1 and offset2 to both be 0 later
837 // m is frame_mbs_only_flag which we set to 1 later
838 // 2160 = (2 - 1) * (p + 1) * 16
839 // 2160 = (p + 1) * 16
840 // p = 134
841 writer.write_exp_golomb(134).unwrap();
842
843 // frame_mbs_only_flag
844 writer.write_bit(true).unwrap();
845
846 // direct_8x8_inference_flag
847 writer.write_bit(false).unwrap();
848 // frame_cropping_flag
849 writer.write_bit(false).unwrap();
850
851 // vui_parameters_present_flag
852 writer.write_bit(true).unwrap();
853
854 // enter vui to set the framerate
855 // aspect_ratio_info_present_flag
856 writer.write_bit(true).unwrap();
857 // we want square (1:1) for 16:9 for 4k w/o overscan
858 // aspect_ratio_idc
859 writer.write_bits(1, 8).unwrap();
860
861 // overscan_info_present_flag
862 writer.write_bit(true).unwrap();
863 // we dont want overscan
864 // overscan_appropriate_flag
865 writer.write_bit(false).unwrap();
866
867 // video_signal_type_present_flag
868 writer.write_bit(false).unwrap();
869 // chroma_loc_info_present_flag
870 writer.write_bit(false).unwrap();
871
872 // timing_info_present_flag
873 writer.write_bit(true).unwrap();
874 // we can set this to 100 for example
875 // num_units_in_tick is a u32
876 writer.write_bits(100, 32).unwrap();
877 // fps = time_scale / (2 * num_units_in_tick)
878 // since we want 144 fps:
879 // 144 = time_scale / (2 * 100)
880 // 28800 = time_scale
881 // time_scale is a u32
882 writer.write_bits(28800, 32).unwrap();
883 writer.finish().unwrap();
884
885 let result = Sps::parse(std::io::Cursor::new(sps)).unwrap();
886
887 insta::assert_debug_snapshot!(result, @r"
888 Sps {
889 nal_ref_idc: 0,
890 nal_unit_type: NALUnitType::SPS,
891 profile_idc: 100,
892 constraint_set0_flag: false,
893 constraint_set1_flag: false,
894 constraint_set2_flag: false,
895 constraint_set3_flag: false,
896 constraint_set4_flag: false,
897 constraint_set5_flag: false,
898 level_idc: 0,
899 seq_parameter_set_id: 0,
900 ext: Some(
901 SpsExtended {
902 chroma_format_idc: 0,
903 separate_color_plane_flag: false,
904 bit_depth_luma_minus8: 0,
905 bit_depth_chroma_minus8: 0,
906 qpprime_y_zero_transform_bypass_flag: false,
907 scaling_matrix: [],
908 },
909 ),
910 log2_max_frame_num_minus4: 0,
911 pic_order_cnt_type: 0,
912 log2_max_pic_order_cnt_lsb_minus4: Some(
913 0,
914 ),
915 pic_order_cnt_type1: None,
916 max_num_ref_frames: 0,
917 gaps_in_frame_num_value_allowed_flag: false,
918 pic_width_in_mbs_minus1: 239,
919 pic_height_in_map_units_minus1: 134,
920 mb_adaptive_frame_field_flag: None,
921 direct_8x8_inference_flag: false,
922 frame_crop_info: None,
923 sample_aspect_ratio: Some(
924 SarDimensions {
925 aspect_ratio_idc: AspectRatioIdc::Square,
926 sar_width: 0,
927 sar_height: 0,
928 },
929 ),
930 overscan_appropriate_flag: Some(
931 false,
932 ),
933 color_config: None,
934 chroma_sample_loc: None,
935 timing_info: Some(
936 TimingInfo {
937 num_units_in_tick: 100,
938 time_scale: 28800,
939 },
940 ),
941 }
942 ");
943
944 assert_eq!(Some(144.0), result.frame_rate());
945 assert_eq!(3840, result.width());
946 assert_eq!(2160, result.height());
947
948 // create a writer for the builder
949 let mut buf = Vec::new();
950 let mut writer2 = BitWriter::new(&mut buf);
951
952 // build from the example sps
953 result.build(&mut writer2).unwrap();
954 writer2.finish().unwrap();
955
956 // sometimes bits can get lost because we save
957 // some space with how the SPS is rebuilt.
958 // so we can just confirm that they're the same
959 // by rebuilding it.
960 let reduced = Sps::parse(std::io::Cursor::new(&buf)).unwrap(); // <- this is where things break
961 assert_eq!(reduced, result);
962
963 // now we can check that the bitstream from
964 // the reduced version should be the same
965 let mut reduced_buf = Vec::new();
966 let mut writer3 = BitWriter::new(&mut reduced_buf);
967
968 reduced.build(&mut writer3).unwrap();
969 writer3.finish().unwrap();
970 assert_eq!(reduced_buf, buf);
971
972 // now we can check the size:
973 assert_eq!(reduced.size(), result.size());
974 }
975
976 #[test]
977 fn test_parse_build_sps_1080_480fps_scaling_matrix() {
978 let mut sps = Vec::new();
979 let mut writer = BitWriter::new(&mut sps);
980
981 // forbidden zero bit must be unset
982 writer.write_bit(false).unwrap();
983 // nal_ref_idc is 0
984 writer.write_bits(0, 2).unwrap();
985 // nal_unit_type must be 7
986 writer.write_bits(7, 5).unwrap();
987
988 // profile_idc = 44
989 writer.write_bits(44, 8).unwrap();
990 // constraint_setn_flags all false
991 writer.write_bits(0, 8).unwrap();
992 // level_idc = 0
993 writer.write_bits(0, 8).unwrap();
994 // seq_parameter_set_id is expg
995 writer.write_exp_golomb(0).unwrap();
996
997 // sps ext
998 // we want to try out chroma_format_idc = 3
999 // chroma_format_idc is expg
1000 writer.write_exp_golomb(3).unwrap();
1001 // separate_color_plane_flag
1002 writer.write_bit(false).unwrap();
1003 // bit_depth_luma_minus8 is expg
1004 writer.write_exp_golomb(0).unwrap();
1005 // bit_depth_chroma_minus8 is expg
1006 writer.write_exp_golomb(0).unwrap();
1007 // qpprime
1008 writer.write_bit(false).unwrap();
1009 // we want to simulate a scaling matrix
1010 // seq_scaling_matrix_present_flag
1011 writer.write_bit(true).unwrap();
1012
1013 // enter scaling matrix, we loop 12 times since
1014 // chroma_format_idc = 3.
1015 // loop 1 of 12
1016 // true to enter if statement
1017 writer.write_bit(true).unwrap();
1018 // i < 6, so size is 16, so we loop 16 times
1019 // sub-loop 1 of 16
1020 // delta_scale is a SIGNED expg so we can try out
1021 // entering -4 so next_scale becomes 8 + 4 = 12
1022 writer.write_signed_exp_golomb(4).unwrap();
1023 // sub-loop 2 of 16
1024 // delta_scale is a SIGNED expg so we can try out
1025 // entering -12 so next scale becomes 12 - 12 = 0
1026 writer.write_signed_exp_golomb(-12).unwrap();
1027 // at this point next_scale is 0, which means we break
1028 // loop 2 through 12
1029 // we don't need to try anything else so we can just skip through them by writing `0` bit 11 times.
1030 writer.write_bits(0, 11).unwrap();
1031
1032 // back to sps
1033 // log2_max_frame_num_minus4 is expg
1034 writer.write_exp_golomb(0).unwrap();
1035 // we can try setting pic_order_cnt_type to 1
1036 // pic_order_cnt_type is expg
1037 writer.write_exp_golomb(1).unwrap();
1038
1039 // delta_pic_order_always_zero_flag
1040 writer.write_bit(false).unwrap();
1041 // offset_for_non_ref_pic
1042 writer.write_bit(true).unwrap();
1043 // offset_for_top_to_bottom_field
1044 writer.write_bit(true).unwrap();
1045 // num_ref_frames_in_pic_order_cnt_cycle is expg
1046 writer.write_exp_golomb(1).unwrap();
1047 // loop num_ref_frames_in_pic_order_cnt_cycle times (1)
1048 // offset_for_ref_frame is expg
1049 writer.write_exp_golomb(0).unwrap();
1050
1051 // max_num_ref_frames is expg
1052 writer.write_exp_golomb(0).unwrap();
1053 // gaps_in_frame_num_value_allowed_flag
1054 writer.write_bit(false).unwrap();
1055 // 1920 width:
1056 // 1920 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
1057 // we set offset1 and offset2 to both be 4 later
1058 // 1920 = (p + 1) * 16 - 2 * 4 - 2 * 4
1059 // 1920 = (p + 1) * 16 - 16
1060 // p = 120
1061 // pic_width_in_mbs_minus1 is expg
1062 writer.write_exp_golomb(120).unwrap();
1063 // we want 1080 height:
1064 // 1080 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
1065 // we set offset1 and offset2 to both be 2 later
1066 // m is frame_mbs_only_flag which we set to 0 later
1067 // 1080 = (2 - 0) * (p + 1) * 16 - 2 * 2 - 2 * 2
1068 // 1080 = 2 * (p + 1) * 16 - 8
1069 // p = 33
1070 // pic_height_in_map_units_minus1 is expg
1071 writer.write_exp_golomb(33).unwrap();
1072
1073 // frame_mbs_only_flag
1074 writer.write_bit(false).unwrap();
1075 // mb_adaptive_frame_field_flag
1076 writer.write_bit(false).unwrap();
1077
1078 // direct_8x8_inference_flag
1079 writer.write_bit(false).unwrap();
1080 // frame_cropping_flag
1081 writer.write_bit(true).unwrap();
1082
1083 // frame_crop_left_offset is expg
1084 writer.write_exp_golomb(4).unwrap();
1085 // frame_crop_left_offset is expg
1086 writer.write_exp_golomb(4).unwrap();
1087 // frame_crop_left_offset is expg
1088 writer.write_exp_golomb(2).unwrap();
1089 // frame_crop_left_offset is expg
1090 writer.write_exp_golomb(2).unwrap();
1091
1092 // vui_parameters_present_flag
1093 writer.write_bit(true).unwrap();
1094
1095 // enter vui to set the framerate
1096 // aspect_ratio_info_present_flag
1097 writer.write_bit(true).unwrap();
1098 // we can try 255 to set the sar_width and sar_height
1099 // aspect_ratio_idc
1100 writer.write_bits(255, 8).unwrap();
1101 // sar_width
1102 writer.write_bits(0, 16).unwrap();
1103 // sar_height
1104 writer.write_bits(0, 16).unwrap();
1105
1106 // overscan_info_present_flag
1107 writer.write_bit(false).unwrap();
1108
1109 // video_signal_type_present_flag
1110 writer.write_bit(true).unwrap();
1111 // video_format
1112 writer.write_bits(0, 3).unwrap();
1113 // video_full_range_flag
1114 writer.write_bit(false).unwrap();
1115 // color_description_present_flag
1116 writer.write_bit(true).unwrap();
1117 // color_primaries
1118 writer.write_bits(1, 8).unwrap();
1119 // transfer_characteristics
1120 writer.write_bits(1, 8).unwrap();
1121 // matrix_coefficients
1122 writer.write_bits(1, 8).unwrap();
1123
1124 // chroma_loc_info_present_flag
1125 writer.write_bit(false).unwrap();
1126
1127 // timing_info_present_flag
1128 writer.write_bit(true).unwrap();
1129 // we can set this to 1000 for example
1130 // num_units_in_tick is a u32
1131 writer.write_bits(1000, 32).unwrap();
1132 // fps = time_scale / (2 * num_units_in_tick)
1133 // since we want 480 fps:
1134 // 480 = time_scale / (2 * 1000)
1135 // 960 000 = time_scale
1136 // time_scale is a u32
1137 writer.write_bits(960000, 32).unwrap();
1138 writer.finish().unwrap();
1139
1140 let result = Sps::parse(std::io::Cursor::new(&sps)).unwrap();
1141
1142 insta::assert_debug_snapshot!(result, @r"
1143 Sps {
1144 nal_ref_idc: 0,
1145 nal_unit_type: NALUnitType::SPS,
1146 profile_idc: 44,
1147 constraint_set0_flag: false,
1148 constraint_set1_flag: false,
1149 constraint_set2_flag: false,
1150 constraint_set3_flag: false,
1151 constraint_set4_flag: false,
1152 constraint_set5_flag: false,
1153 level_idc: 0,
1154 seq_parameter_set_id: 0,
1155 ext: Some(
1156 SpsExtended {
1157 chroma_format_idc: 3,
1158 separate_color_plane_flag: false,
1159 bit_depth_luma_minus8: 0,
1160 bit_depth_chroma_minus8: 0,
1161 qpprime_y_zero_transform_bypass_flag: false,
1162 scaling_matrix: [
1163 [
1164 4,
1165 -12,
1166 ],
1167 [],
1168 [],
1169 [],
1170 [],
1171 [],
1172 [],
1173 [],
1174 [],
1175 [],
1176 [],
1177 [],
1178 ],
1179 },
1180 ),
1181 log2_max_frame_num_minus4: 0,
1182 pic_order_cnt_type: 1,
1183 log2_max_pic_order_cnt_lsb_minus4: None,
1184 pic_order_cnt_type1: Some(
1185 PicOrderCountType1 {
1186 delta_pic_order_always_zero_flag: false,
1187 offset_for_non_ref_pic: 0,
1188 offset_for_top_to_bottom_field: 0,
1189 num_ref_frames_in_pic_order_cnt_cycle: 1,
1190 offset_for_ref_frame: [
1191 0,
1192 ],
1193 },
1194 ),
1195 max_num_ref_frames: 0,
1196 gaps_in_frame_num_value_allowed_flag: false,
1197 pic_width_in_mbs_minus1: 120,
1198 pic_height_in_map_units_minus1: 33,
1199 mb_adaptive_frame_field_flag: Some(
1200 false,
1201 ),
1202 direct_8x8_inference_flag: false,
1203 frame_crop_info: Some(
1204 FrameCropInfo {
1205 frame_crop_left_offset: 4,
1206 frame_crop_right_offset: 4,
1207 frame_crop_top_offset: 2,
1208 frame_crop_bottom_offset: 2,
1209 },
1210 ),
1211 sample_aspect_ratio: Some(
1212 SarDimensions {
1213 aspect_ratio_idc: AspectRatioIdc::ExtendedSar,
1214 sar_width: 0,
1215 sar_height: 0,
1216 },
1217 ),
1218 overscan_appropriate_flag: None,
1219 color_config: Some(
1220 ColorConfig {
1221 video_format: VideoFormat::Component,
1222 video_full_range_flag: false,
1223 color_primaries: 1,
1224 transfer_characteristics: 1,
1225 matrix_coefficients: 1,
1226 },
1227 ),
1228 chroma_sample_loc: None,
1229 timing_info: Some(
1230 TimingInfo {
1231 num_units_in_tick: 1000,
1232 time_scale: 960000,
1233 },
1234 ),
1235 }
1236 ");
1237
1238 assert_eq!(Some(480.0), result.frame_rate());
1239 assert_eq!(1920, result.width());
1240 assert_eq!(1080, result.height());
1241
1242 // create a writer for the builder
1243 let mut buf = Vec::new();
1244 result.build(&mut buf).unwrap();
1245
1246 assert_eq!(buf, sps);
1247 }
1248
1249 #[test]
1250 fn test_parse_build_sps_1280x800_0fps() {
1251 let mut sps = Vec::new();
1252 let mut writer = BitWriter::new(&mut sps);
1253
1254 // forbidden zero bit must be unset
1255 writer.write_bit(false).unwrap();
1256 // nal_ref_idc is 0
1257 writer.write_bits(0, 2).unwrap();
1258 // nal_unit_type must be 7
1259 writer.write_bits(7, 5).unwrap();
1260
1261 // profile_idc = 77
1262 writer.write_bits(77, 8).unwrap();
1263 // constraint_setn_flags all false
1264 writer.write_bits(0, 8).unwrap();
1265 // level_idc = 0
1266 writer.write_bits(0, 8).unwrap();
1267
1268 // seq_parameter_set_id is expg
1269 writer.write_exp_golomb(0).unwrap();
1270
1271 // profile_idc = 77 means we skip the sps_ext
1272 // log2_max_frame_num_minus4 is expg
1273 writer.write_exp_golomb(0).unwrap();
1274 // pic_order_cnt_type is expg
1275 writer.write_exp_golomb(0).unwrap();
1276 // log2_max_pic_order_cnt_lsb_minus4
1277 writer.write_exp_golomb(0).unwrap();
1278
1279 // max_num_ref_frames is expg
1280 writer.write_exp_golomb(0).unwrap();
1281 // gaps_in_frame_num_value_allowed_flag
1282 writer.write_bit(false).unwrap();
1283 // 1280 width:
1284 // 1280 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
1285 // we set offset1 and offset2 to both be 0 later
1286 // 1280 = (p + 1) * 16
1287 // p = 79
1288 writer.write_exp_golomb(79).unwrap();
1289 // we want 800 height:
1290 // 800 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
1291 // we set offset1 and offset2 to both be 0 later
1292 // m is frame_mbs_only_flag which we set to 1 later
1293 // 800 = (2 - 1) * (p + 1) * 16 - 2 * 0 - 2 * 0
1294 // 800 = (p + 1) * 16
1295 // p = 49
1296 writer.write_exp_golomb(49).unwrap();
1297
1298 // frame_mbs_only_flag
1299 writer.write_bit(true).unwrap();
1300
1301 // direct_8x8_inference_flag
1302 writer.write_bit(false).unwrap();
1303 // frame_cropping_flag
1304 writer.write_bit(false).unwrap();
1305
1306 // vui_parameters_present_flag
1307 writer.write_bit(true).unwrap();
1308
1309 // enter vui to set the framerate
1310 // aspect_ratio_info_present_flag
1311 writer.write_bit(false).unwrap();
1312
1313 // overscan_info_present_flag
1314 writer.write_bit(false).unwrap();
1315
1316 // video_signal_type_present_flag
1317 writer.write_bit(true).unwrap();
1318 // video_format
1319 writer.write_bits(0, 3).unwrap();
1320 // video_full_range_flag
1321 writer.write_bit(false).unwrap();
1322 // color_description_present_flag
1323 writer.write_bit(false).unwrap();
1324
1325 // chroma_loc_info_present_flag
1326 writer.write_bit(true).unwrap();
1327 // chroma_sample_loc_type_top_field is expg
1328 writer.write_exp_golomb(2).unwrap();
1329 // chroma_sample_loc_type_bottom_field is expg
1330 writer.write_exp_golomb(2).unwrap();
1331
1332 // timing_info_present_flag
1333 writer.write_bit(false).unwrap();
1334 writer.finish().unwrap();
1335
1336 let result = Sps::parse(std::io::Cursor::new(&sps)).unwrap();
1337
1338 insta::assert_debug_snapshot!(result, @r"
1339 Sps {
1340 nal_ref_idc: 0,
1341 nal_unit_type: NALUnitType::SPS,
1342 profile_idc: 77,
1343 constraint_set0_flag: false,
1344 constraint_set1_flag: false,
1345 constraint_set2_flag: false,
1346 constraint_set3_flag: false,
1347 constraint_set4_flag: false,
1348 constraint_set5_flag: false,
1349 level_idc: 0,
1350 seq_parameter_set_id: 0,
1351 ext: None,
1352 log2_max_frame_num_minus4: 0,
1353 pic_order_cnt_type: 0,
1354 log2_max_pic_order_cnt_lsb_minus4: Some(
1355 0,
1356 ),
1357 pic_order_cnt_type1: None,
1358 max_num_ref_frames: 0,
1359 gaps_in_frame_num_value_allowed_flag: false,
1360 pic_width_in_mbs_minus1: 79,
1361 pic_height_in_map_units_minus1: 49,
1362 mb_adaptive_frame_field_flag: None,
1363 direct_8x8_inference_flag: false,
1364 frame_crop_info: None,
1365 sample_aspect_ratio: None,
1366 overscan_appropriate_flag: None,
1367 color_config: Some(
1368 ColorConfig {
1369 video_format: VideoFormat::Component,
1370 video_full_range_flag: false,
1371 color_primaries: 2,
1372 transfer_characteristics: 2,
1373 matrix_coefficients: 2,
1374 },
1375 ),
1376 chroma_sample_loc: Some(
1377 ChromaSampleLoc {
1378 chroma_sample_loc_type_top_field: 2,
1379 chroma_sample_loc_type_bottom_field: 2,
1380 },
1381 ),
1382 timing_info: None,
1383 }
1384 ");
1385
1386 assert_eq!(None, result.frame_rate());
1387 assert_eq!(1280, result.width());
1388 assert_eq!(800, result.height());
1389
1390 // create a writer for the builder
1391 let mut buf = Vec::new();
1392 result.build(&mut buf).unwrap();
1393
1394 assert_eq!(buf, sps);
1395 }
1396
1397 #[test]
1398 fn test_parse_build_sps_pic_order_cnt_type_2() {
1399 let mut sps = Vec::new();
1400 let mut writer = BitWriter::new(&mut sps);
1401
1402 // forbidden zero bit must be unset
1403 writer.write_bit(false).unwrap();
1404 // nal_ref_idc is 0
1405 writer.write_bits(0, 2).unwrap();
1406 // nal_unit_type must be 7
1407 writer.write_bits(7, 5).unwrap();
1408
1409 // profile_idc = 77
1410 writer.write_bits(77, 8).unwrap();
1411 // constraint_setn_flags all false
1412 writer.write_bits(0, 8).unwrap();
1413 // level_idc = 0
1414 writer.write_bits(0, 8).unwrap();
1415
1416 // seq_parameter_set_id is expg
1417 writer.write_exp_golomb(0).unwrap();
1418
1419 // profile_idc = 77 means we skip the sps_ext
1420 // log2_max_frame_num_minus4 is expg
1421 writer.write_exp_golomb(0).unwrap();
1422 // pic_order_cnt_type is expg
1423 writer.write_exp_golomb(2).unwrap();
1424 // log2_max_pic_order_cnt_lsb_minus4
1425 writer.write_exp_golomb(0).unwrap();
1426
1427 // max_num_ref_frames is expg
1428 writer.write_exp_golomb(0).unwrap();
1429 // gaps_in_frame_num_value_allowed_flag
1430 writer.write_bit(false).unwrap();
1431 writer.write_exp_golomb(1).unwrap();
1432 writer.write_exp_golomb(2).unwrap();
1433
1434 // frame_mbs_only_flag
1435 writer.write_bit(true).unwrap();
1436
1437 // direct_8x8_inference_flag
1438 writer.write_bit(false).unwrap();
1439 // frame_cropping_flag
1440 writer.write_bit(false).unwrap();
1441
1442 // enter vui to set redundant parameters so they get reduced
1443 // vui_parameters_present_flag
1444 writer.write_bit(false).unwrap();
1445 writer.finish().unwrap();
1446
1447 let result = Sps::parse(std::io::Cursor::new(&sps)).unwrap();
1448
1449 insta::assert_debug_snapshot!(result, @r"
1450 Sps {
1451 nal_ref_idc: 0,
1452 nal_unit_type: NALUnitType::SPS,
1453 profile_idc: 77,
1454 constraint_set0_flag: false,
1455 constraint_set1_flag: false,
1456 constraint_set2_flag: false,
1457 constraint_set3_flag: false,
1458 constraint_set4_flag: false,
1459 constraint_set5_flag: false,
1460 level_idc: 0,
1461 seq_parameter_set_id: 0,
1462 ext: None,
1463 log2_max_frame_num_minus4: 0,
1464 pic_order_cnt_type: 2,
1465 log2_max_pic_order_cnt_lsb_minus4: None,
1466 pic_order_cnt_type1: None,
1467 max_num_ref_frames: 0,
1468 gaps_in_frame_num_value_allowed_flag: true,
1469 pic_width_in_mbs_minus1: 3,
1470 pic_height_in_map_units_minus1: 0,
1471 mb_adaptive_frame_field_flag: None,
1472 direct_8x8_inference_flag: true,
1473 frame_crop_info: None,
1474 sample_aspect_ratio: None,
1475 overscan_appropriate_flag: None,
1476 color_config: None,
1477 chroma_sample_loc: None,
1478 timing_info: None,
1479 }
1480 ");
1481
1482 assert_eq!(None, result.frame_rate());
1483 assert_eq!(result.size(), 7);
1484
1485 // create a writer for the builder
1486 let mut buf = Vec::new();
1487 result.build_with_emulation_prevention(&mut buf).unwrap();
1488
1489 assert_eq!(buf, sps);
1490 }
1491
1492 #[test]
1493 fn test_parse_sps_chroma_loc_info_error() {
1494 let mut sps = Vec::new();
1495 let mut writer = BitWriter::new(&mut sps);
1496
1497 // forbidden zero bit must be unset
1498 writer.write_bit(false).unwrap();
1499 // nal_ref_idc is 0
1500 writer.write_bits(0, 2).unwrap();
1501 // nal_unit_type must be 7
1502 writer.write_bits(7, 5).unwrap();
1503
1504 // profile_idc = 100
1505 writer.write_bits(100, 8).unwrap();
1506 // constraint_setn_flags all false
1507 writer.write_bits(0, 8).unwrap();
1508 // level_idc = 0
1509 writer.write_bits(0, 8).unwrap();
1510
1511 // seq_parameter_set_id is expg
1512 writer.write_exp_golomb(0).unwrap();
1513
1514 // ext
1515 // chroma_format_idc is expg
1516 writer.write_exp_golomb(0).unwrap();
1517 // bit_depth_luma_minus8 is expg
1518 writer.write_exp_golomb(0).unwrap();
1519 // bit_depth_chroma_minus8 is expg
1520 writer.write_exp_golomb(0).unwrap();
1521 // qpprime
1522 writer.write_bit(false).unwrap();
1523 // seq_scaling_matrix_present_flag
1524 writer.write_bit(false).unwrap();
1525
1526 // return to sps
1527 // log2_max_frame_num_minus4 is expg
1528 writer.write_exp_golomb(0).unwrap();
1529 // pic_order_cnt_type is expg
1530 writer.write_exp_golomb(0).unwrap();
1531 // log2_max_pic_order_cnt_lsb_minus4
1532 writer.write_exp_golomb(0).unwrap();
1533
1534 // max_num_ref_frames is expg
1535 writer.write_exp_golomb(0).unwrap();
1536 // gaps_in_frame_num_value_allowed_flag
1537 writer.write_bit(false).unwrap();
1538 // 1280 width:
1539 // 1280 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
1540 // we set offset1 and offset2 to both be 0 later
1541 // 1280 = (p + 1) * 16
1542 // p = 79
1543 writer.write_exp_golomb(79).unwrap();
1544 // we want 800 height:
1545 // 800 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
1546 // we set offset1 and offset2 to both be 0 later
1547 // m is frame_mbs_only_flag which we set to 1 later
1548 // 800 = (2 - 1) * (p + 1) * 16 - 2 * 0 - 2 * 0
1549 // 800 = 2 * (p + 1) * 16 - 8
1550 // p = 33
1551 writer.write_exp_golomb(33).unwrap();
1552
1553 // frame_mbs_only_flag
1554 writer.write_bit(false).unwrap();
1555 // mb_adaptive_frame_field_flag
1556 writer.write_bit(false).unwrap();
1557
1558 // direct_8x8_inference_flag
1559 writer.write_bit(false).unwrap();
1560 // frame_cropping_flag
1561 writer.write_bit(false).unwrap();
1562
1563 // vui_parameters_present_flag
1564 writer.write_bit(true).unwrap();
1565
1566 // enter vui to set the framerate
1567 // aspect_ratio_info_present_flag
1568 writer.write_bit(false).unwrap();
1569
1570 // overscan_info_present_flag
1571 writer.write_bit(false).unwrap();
1572
1573 // video_signal_type_present_flag
1574 writer.write_bit(true).unwrap();
1575 // video_format
1576 writer.write_bits(0, 3).unwrap();
1577 // video_full_range_flag
1578 writer.write_bit(false).unwrap();
1579 // color_description_present_flag
1580 writer.write_bit(false).unwrap();
1581
1582 // chroma_loc_info_present_flag
1583 writer.write_bit(true).unwrap();
1584 writer.finish().unwrap();
1585
1586 let result = Sps::parse(std::io::Cursor::new(&sps));
1587
1588 assert!(result.is_err());
1589 let err = result.unwrap_err();
1590 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
1591 assert_eq!(
1592 err.to_string(),
1593 "chroma_loc_info_present_flag cannot be set to 1 when chroma_format_idc is not 1"
1594 );
1595 }
1596
1597 #[test]
1598 fn test_invalid_num_units_in_tick() {
1599 let mut sps = Vec::new();
1600 let mut writer = BitWriter::new(&mut sps);
1601
1602 // forbidden zero bit must be unset
1603 writer.write_bit(false).unwrap();
1604 // nal_ref_idc is 0
1605 writer.write_bits(0, 2).unwrap();
1606 // nal_unit_type must be 7
1607 writer.write_bits(7, 5).unwrap();
1608
1609 // profile_idc = 100
1610 writer.write_bits(100, 8).unwrap();
1611 // constraint_setn_flags all false
1612 writer.write_bits(0, 8).unwrap();
1613 // level_idc = 0
1614 writer.write_bits(0, 8).unwrap();
1615
1616 // seq_parameter_set_id is expg
1617 writer.write_exp_golomb(0).unwrap();
1618
1619 // ext
1620 // chroma_format_idc is expg
1621 writer.write_exp_golomb(0).unwrap();
1622 // bit_depth_luma_minus8 is expg
1623 writer.write_exp_golomb(0).unwrap();
1624 // bit_depth_chroma_minus8 is expg
1625 writer.write_exp_golomb(0).unwrap();
1626 // qpprime
1627 writer.write_bit(false).unwrap();
1628 // seq_scaling_matrix_present_flag
1629 writer.write_bit(false).unwrap();
1630
1631 // return to sps
1632 // log2_max_frame_num_minus4 is expg
1633 writer.write_exp_golomb(0).unwrap();
1634 // pic_order_cnt_type is expg
1635 writer.write_exp_golomb(0).unwrap();
1636 // log2_max_pic_order_cnt_lsb_minus4
1637 writer.write_exp_golomb(0).unwrap();
1638
1639 // max_num_ref_frames is expg
1640 writer.write_exp_golomb(0).unwrap();
1641 // gaps_in_frame_num_value_allowed_flag
1642 writer.write_bit(false).unwrap();
1643 // 1280 width:
1644 // 1280 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
1645 // we set offset1 and offset2 to both be 0 later
1646 // 1280 = (p + 1) * 16
1647 // p = 79
1648 writer.write_exp_golomb(79).unwrap();
1649 // we want 800 height:
1650 // 800 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
1651 // we set offset1 and offset2 to both be 0 later
1652 // m is frame_mbs_only_flag which we set to 1 later
1653 // 800 = (2 - 1) * (p + 1) * 16 - 2 * 0 - 2 * 0
1654 // 800 = 2 * (p + 1) * 16 - 8
1655 // p = 33
1656 writer.write_exp_golomb(33).unwrap();
1657
1658 // frame_mbs_only_flag
1659 writer.write_bit(false).unwrap();
1660 // mb_adaptive_frame_field_flag
1661 writer.write_bit(false).unwrap();
1662
1663 // direct_8x8_inference_flag
1664 writer.write_bit(false).unwrap();
1665 // frame_cropping_flag
1666 writer.write_bit(false).unwrap();
1667
1668 // vui_parameters_present_flag
1669 writer.write_bit(true).unwrap();
1670
1671 // enter vui to set the framerate
1672 // aspect_ratio_info_present_flag
1673 writer.write_bit(false).unwrap();
1674
1675 // overscan_info_present_flag
1676 writer.write_bit(false).unwrap();
1677
1678 // video_signal_type_present_flag
1679 writer.write_bit(true).unwrap();
1680 // video_format
1681 writer.write_bits(0, 3).unwrap();
1682 // video_full_range_flag
1683 writer.write_bit(false).unwrap();
1684 // color_description_present_flag
1685 writer.write_bit(false).unwrap();
1686
1687 // chroma_loc_info_present_flag
1688 writer.write_bit(false).unwrap();
1689
1690 // timing_info_present_flag
1691 writer.write_bit(true).unwrap();
1692 // num_units_in_tick to 0 (invalid)
1693 writer.write_bits(0, 32).unwrap();
1694 writer.finish().unwrap();
1695
1696 let result = Sps::parse(std::io::Cursor::new(&sps));
1697
1698 assert!(result.is_err());
1699 let err = result.unwrap_err();
1700 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
1701 assert_eq!(err.to_string(), "num_units_in_tick cannot be 0");
1702 }
1703
1704 #[test]
1705 fn test_invalid_time_scale() {
1706 let mut sps = Vec::new();
1707 let mut writer = BitWriter::new(&mut sps);
1708
1709 // forbidden zero bit must be unset
1710 writer.write_bit(false).unwrap();
1711 // nal_ref_idc is 0
1712 writer.write_bits(0, 2).unwrap();
1713 // nal_unit_type must be 7
1714 writer.write_bits(7, 5).unwrap();
1715
1716 // profile_idc = 100
1717 writer.write_bits(100, 8).unwrap();
1718 // constraint_setn_flags all false
1719 writer.write_bits(0, 8).unwrap();
1720 // level_idc = 0
1721 writer.write_bits(0, 8).unwrap();
1722
1723 // seq_parameter_set_id is expg
1724 writer.write_exp_golomb(0).unwrap();
1725
1726 // ext
1727 // chroma_format_idc is expg
1728 writer.write_exp_golomb(0).unwrap();
1729 // bit_depth_luma_minus8 is expg
1730 writer.write_exp_golomb(0).unwrap();
1731 // bit_depth_chroma_minus8 is expg
1732 writer.write_exp_golomb(0).unwrap();
1733 // qpprime
1734 writer.write_bit(false).unwrap();
1735 // seq_scaling_matrix_present_flag
1736 writer.write_bit(false).unwrap();
1737
1738 // return to sps
1739 // log2_max_frame_num_minus4 is expg
1740 writer.write_exp_golomb(0).unwrap();
1741 // pic_order_cnt_type is expg
1742 writer.write_exp_golomb(0).unwrap();
1743 // log2_max_pic_order_cnt_lsb_minus4
1744 writer.write_exp_golomb(0).unwrap();
1745
1746 // max_num_ref_frames is expg
1747 writer.write_exp_golomb(0).unwrap();
1748 // gaps_in_frame_num_value_allowed_flag
1749 writer.write_bit(false).unwrap();
1750 // 1280 width:
1751 // 1280 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
1752 // we set offset1 and offset2 to both be 0 later
1753 // 1280 = (p + 1) * 16
1754 // p = 79
1755 writer.write_exp_golomb(79).unwrap();
1756 // we want 800 height:
1757 // 800 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
1758 // we set offset1 and offset2 to both be 0 later
1759 // m is frame_mbs_only_flag which we set to 1 later
1760 // 800 = (2 - 1) * (p + 1) * 16 - 2 * 0 - 2 * 0
1761 // 800 = 2 * (p + 1) * 16 - 8
1762 // p = 33
1763 writer.write_exp_golomb(33).unwrap();
1764
1765 // frame_mbs_only_flag
1766 writer.write_bit(false).unwrap();
1767 // mb_adaptive_frame_field_flag
1768 writer.write_bit(false).unwrap();
1769
1770 // direct_8x8_inference_flag
1771 writer.write_bit(false).unwrap();
1772 // frame_cropping_flag
1773 writer.write_bit(false).unwrap();
1774
1775 // vui_parameters_present_flag
1776 writer.write_bit(true).unwrap();
1777
1778 // enter vui to set the framerate
1779 // aspect_ratio_info_present_flag
1780 writer.write_bit(false).unwrap();
1781
1782 // overscan_info_present_flag
1783 writer.write_bit(false).unwrap();
1784
1785 // video_signal_type_present_flag
1786 writer.write_bit(true).unwrap();
1787 // video_format
1788 writer.write_bits(0, 3).unwrap();
1789 // video_full_range_flag
1790 writer.write_bit(false).unwrap();
1791 // color_description_present_flag
1792 writer.write_bit(false).unwrap();
1793
1794 // chroma_loc_info_present_flag
1795 writer.write_bit(false).unwrap();
1796
1797 // timing_info_present_flag
1798 writer.write_bit(true).unwrap();
1799 // num_units_in_tick to 0 (invalid)
1800 writer.write_bits(0, 32).unwrap();
1801 writer.finish().unwrap();
1802
1803 let result = Sps::parse(std::io::Cursor::new(&sps));
1804
1805 assert!(result.is_err());
1806 let err = result.unwrap_err();
1807 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
1808 assert_eq!(err.to_string(), "num_units_in_tick cannot be 0");
1809 }
1810
1811 #[test]
1812 fn test_parse_build_sps_no_vui() {
1813 let mut sps = Vec::new();
1814 let mut writer = BitWriter::new(&mut sps);
1815
1816 // forbidden zero bit must be unset
1817 writer.write_bit(false).unwrap();
1818 // nal_ref_idc is 0
1819 writer.write_bits(0, 2).unwrap();
1820 // nal_unit_type must be 7
1821 writer.write_bits(7, 5).unwrap();
1822
1823 // profile_idc = 77
1824 writer.write_bits(77, 8).unwrap();
1825 // constraint_setn_flags all false
1826 writer.write_bits(0, 8).unwrap();
1827 // level_idc = 0
1828 writer.write_bits(0, 8).unwrap();
1829
1830 // seq_parameter_set_id is expg so 0b1 (true) = false
1831 writer.write_exp_golomb(0).unwrap();
1832
1833 // skip sps ext since profile_idc = 77
1834 // log2_max_frame_num_minus4 is expg so 0b1 (true) = false
1835 writer.write_exp_golomb(0).unwrap();
1836 // we can try setting pic_order_cnt_type to 1
1837 writer.write_exp_golomb(1).unwrap();
1838
1839 // delta_pic_order_always_zero_flag
1840 writer.write_bit(false).unwrap();
1841 // offset_for_non_ref_pic
1842 writer.write_bit(true).unwrap();
1843 // offset_for_top_to_bottom_field
1844 writer.write_bit(true).unwrap();
1845 // num_ref_frames_in_pic_order_cnt_cycle is expg so 0b010 = 1
1846 writer.write_bits(0b010, 3).unwrap();
1847 // loop num_ref_frames_in_pic_order_cnt_cycle times (1)
1848 // offset_for_ref_frame is expg so 0b1 (true) = false
1849 writer.write_bit(true).unwrap();
1850
1851 // max_num_ref_frames is expg so 0b1 (true) = false
1852 writer.write_bit(true).unwrap();
1853 // gaps_in_frame_num_value_allowed_flag
1854 writer.write_bit(false).unwrap();
1855 // 1920 width:
1856 // 1920 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
1857 // we set offset1 and offset2 to both be 4 later
1858 // 1920 = (p + 1) * 16 - 2 * 4 - 2 * 4
1859 // 1920 = (p + 1) * 16 - 16
1860 // p = 120
1861 // pic_width_in_mbs_minus1 is expg so:
1862 // 0 0000 0111 1001
1863 writer.write_exp_golomb(999).unwrap();
1864 // we want 1080 height:
1865 // 1080 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
1866 // we set offset1 and offset2 to both be 2 later
1867 // m is frame_mbs_only_flag which we set to 0 later
1868 // 1080 = (2 - 0) * (p + 1) * 16 - 2 * 2 - 2 * 2
1869 // 1080 = 2 * (p + 1) * 16 - 8
1870 // p = 33
1871 // pic_height_in_map_units_minus1 is expg so:
1872 // 000 0010 0010
1873 writer.write_exp_golomb(899).unwrap();
1874
1875 // frame_mbs_only_flag
1876 writer.write_bit(false).unwrap();
1877 // mb_adaptive_frame_field_flag
1878 writer.write_bit(false).unwrap();
1879
1880 // direct_8x8_inference_flag
1881 writer.write_bit(false).unwrap();
1882 // frame_cropping_flag
1883 writer.write_bit(true).unwrap();
1884
1885 // frame_crop_left_offset is expg
1886 writer.write_exp_golomb(100).unwrap();
1887 // frame_crop_right_offset is expg
1888 writer.write_exp_golomb(200).unwrap();
1889 // frame_crop_top_offset is expg
1890 writer.write_exp_golomb(300).unwrap();
1891 // frame_crop_bottom_offset is expg
1892 writer.write_exp_golomb(400).unwrap();
1893
1894 // vui_parameters_present_flag
1895 writer.write_bit(false).unwrap();
1896 writer.finish().unwrap();
1897
1898 let result = Sps::parse(std::io::Cursor::new(&sps)).unwrap();
1899
1900 insta::assert_debug_snapshot!(result, @r"
1901 Sps {
1902 nal_ref_idc: 0,
1903 nal_unit_type: NALUnitType::SPS,
1904 profile_idc: 77,
1905 constraint_set0_flag: false,
1906 constraint_set1_flag: false,
1907 constraint_set2_flag: false,
1908 constraint_set3_flag: false,
1909 constraint_set4_flag: false,
1910 constraint_set5_flag: false,
1911 level_idc: 0,
1912 seq_parameter_set_id: 0,
1913 ext: None,
1914 log2_max_frame_num_minus4: 0,
1915 pic_order_cnt_type: 1,
1916 log2_max_pic_order_cnt_lsb_minus4: None,
1917 pic_order_cnt_type1: Some(
1918 PicOrderCountType1 {
1919 delta_pic_order_always_zero_flag: false,
1920 offset_for_non_ref_pic: 0,
1921 offset_for_top_to_bottom_field: 0,
1922 num_ref_frames_in_pic_order_cnt_cycle: 1,
1923 offset_for_ref_frame: [
1924 0,
1925 ],
1926 },
1927 ),
1928 max_num_ref_frames: 0,
1929 gaps_in_frame_num_value_allowed_flag: false,
1930 pic_width_in_mbs_minus1: 999,
1931 pic_height_in_map_units_minus1: 899,
1932 mb_adaptive_frame_field_flag: Some(
1933 false,
1934 ),
1935 direct_8x8_inference_flag: false,
1936 frame_crop_info: Some(
1937 FrameCropInfo {
1938 frame_crop_left_offset: 100,
1939 frame_crop_right_offset: 200,
1940 frame_crop_top_offset: 300,
1941 frame_crop_bottom_offset: 400,
1942 },
1943 ),
1944 sample_aspect_ratio: None,
1945 overscan_appropriate_flag: None,
1946 color_config: None,
1947 chroma_sample_loc: None,
1948 timing_info: None,
1949 }
1950 ");
1951
1952 // create a writer for the builder
1953 let mut buf = Vec::new();
1954 // build from the example sps
1955 result.build(&mut buf).unwrap();
1956
1957 assert_eq!(buf, sps);
1958 }
1959
1960 #[test]
1961 fn test_size_sps() {
1962 let mut bit_count = 0;
1963 let mut sps = Vec::new();
1964 let mut writer = BitWriter::new(&mut sps);
1965
1966 // forbidden zero bit must be unset
1967 writer.write_bit(false).unwrap();
1968 bit_count += 1;
1969 // nal_ref_idc is 0
1970 writer.write_bits(0, 2).unwrap();
1971 bit_count += 2;
1972 // nal_unit_type must be 7
1973 writer.write_bits(7, 5).unwrap();
1974 bit_count += 5;
1975
1976 // profile_idc = 44
1977 writer.write_bits(44, 8).unwrap();
1978 bit_count += 8;
1979 // constraint_setn_flags all false
1980 writer.write_bits(0, 8).unwrap();
1981 bit_count += 8;
1982 // level_idc = 0
1983 writer.write_bits(0, 8).unwrap();
1984 bit_count += 8;
1985 // seq_parameter_set_id is expg
1986 writer.write_exp_golomb(0).unwrap();
1987 bit_count += size_of_exp_golomb(0);
1988
1989 // sps ext
1990 // we want to try out chroma_format_idc = 3
1991 // chroma_format_idc is expg
1992 writer.write_exp_golomb(3).unwrap();
1993 bit_count += size_of_exp_golomb(3);
1994 // separate_color_plane_flag
1995 writer.write_bit(false).unwrap();
1996 bit_count += 1;
1997 // bit_depth_luma_minus8 is expg
1998 writer.write_exp_golomb(0).unwrap();
1999 bit_count += size_of_exp_golomb(0);
2000 // bit_depth_chroma_minus8 is expg
2001 writer.write_exp_golomb(0).unwrap();
2002 bit_count += size_of_exp_golomb(0);
2003 // qpprime
2004 writer.write_bit(false).unwrap();
2005 bit_count += 1;
2006 // we want to simulate a scaling matrix
2007 // seq_scaling_matrix_present_flag
2008 writer.write_bit(true).unwrap();
2009 bit_count += 1;
2010
2011 // enter scaling matrix, we loop 12 times since
2012 // chroma_format_idc = 3.
2013 // loop 1 of 12
2014 // true to enter if statement
2015 writer.write_bit(true).unwrap();
2016 bit_count += 1;
2017 // i < 6, so size is 16, so we loop 16 times
2018 // sub-loop 1 of 16
2019 // delta_scale is a SIGNED expg so we can try out
2020 // entering -4 so next_scale becomes 8 + 4 = 12
2021 writer.write_signed_exp_golomb(4).unwrap();
2022 bit_count += size_of_signed_exp_golomb(4);
2023 // sub-loop 2 of 16
2024 // delta_scale is a SIGNED expg so we can try out
2025 // entering -12 so next scale becomes 12 - 12 = 0
2026 writer.write_signed_exp_golomb(-12).unwrap();
2027 bit_count += size_of_signed_exp_golomb(-12);
2028 // at this point next_scale is 0, which means we break
2029 // loop 2 through 12
2030 // we don't need to try anything else so we can just skip through them by writing `0` bit 11 times.
2031 writer.write_bits(0, 11).unwrap();
2032 bit_count += 11;
2033
2034 // back to sps
2035 // log2_max_frame_num_minus4 is expg
2036 writer.write_exp_golomb(0).unwrap();
2037 bit_count += size_of_exp_golomb(0);
2038 // we can try setting pic_order_cnt_type to 1
2039 // pic_order_cnt_type is expg
2040 writer.write_exp_golomb(1).unwrap();
2041 bit_count += size_of_exp_golomb(1);
2042
2043 // delta_pic_order_always_zero_flag
2044 writer.write_bit(false).unwrap();
2045 bit_count += 1;
2046 // offset_for_non_ref_pic
2047 writer.write_bit(true).unwrap();
2048 bit_count += 1;
2049 // offset_for_top_to_bottom_field
2050 writer.write_bit(true).unwrap();
2051 bit_count += 1;
2052 // num_ref_frames_in_pic_order_cnt_cycle is expg
2053 writer.write_exp_golomb(1).unwrap();
2054 bit_count += size_of_exp_golomb(1);
2055 // loop num_ref_frames_in_pic_order_cnt_cycle times (1)
2056 // offset_for_ref_frame is expg
2057 writer.write_exp_golomb(0).unwrap();
2058 bit_count += size_of_exp_golomb(0);
2059
2060 // max_num_ref_frames is expg
2061 writer.write_exp_golomb(0).unwrap();
2062 bit_count += size_of_exp_golomb(0);
2063 // gaps_in_frame_num_value_allowed_flag
2064 writer.write_bit(false).unwrap();
2065 bit_count += 1;
2066 // 1920 width:
2067 // 1920 = (p + 1) * 16 - 2 * offset1 - 2 * offset2
2068 // we set offset1 and offset2 to both be 4 later
2069 // 1920 = (p + 1) * 16 - 2 * 4 - 2 * 4
2070 // 1920 = (p + 1) * 16 - 16
2071 // p = 120
2072 // pic_width_in_mbs_minus1 is expg
2073 writer.write_exp_golomb(120).unwrap();
2074 bit_count += size_of_exp_golomb(120);
2075 // we want 1080 height:
2076 // 1080 = ((2 - m) * (p + 1) * 16) - 2 * offset1 - 2 * offset2
2077 // we set offset1 and offset2 to both be 2 later
2078 // m is frame_mbs_only_flag which we set to 0 later
2079 // 1080 = (2 - 0) * (p + 1) * 16 - 2 * 2 - 2 * 2
2080 // 1080 = 2 * (p + 1) * 16 - 8
2081 // p = 33
2082 // pic_height_in_map_units_minus1 is expg
2083 writer.write_exp_golomb(33).unwrap();
2084 bit_count += size_of_exp_golomb(33);
2085
2086 // frame_mbs_only_flag
2087 writer.write_bit(false).unwrap();
2088 bit_count += 1;
2089 // mb_adaptive_frame_field_flag
2090 writer.write_bit(false).unwrap();
2091 bit_count += 1;
2092
2093 // direct_8x8_inference_flag
2094 writer.write_bit(false).unwrap();
2095 bit_count += 1;
2096 // frame_cropping_flag
2097 writer.write_bit(true).unwrap();
2098 bit_count += 1;
2099
2100 // frame_crop_left_offset is expg
2101 writer.write_exp_golomb(4).unwrap();
2102 bit_count += size_of_exp_golomb(4);
2103 // frame_crop_left_offset is expg
2104 writer.write_exp_golomb(4).unwrap();
2105 bit_count += size_of_exp_golomb(4);
2106 // frame_crop_left_offset is expg
2107 writer.write_exp_golomb(2).unwrap();
2108 bit_count += size_of_exp_golomb(2);
2109 // frame_crop_left_offset is expg
2110 writer.write_exp_golomb(2).unwrap();
2111 bit_count += size_of_exp_golomb(2);
2112
2113 // vui_parameters_present_flag
2114 writer.write_bit(true).unwrap();
2115 bit_count += 1;
2116
2117 // enter vui to set the framerate
2118 // aspect_ratio_info_present_flag
2119 writer.write_bit(true).unwrap();
2120 bit_count += 1;
2121 // we can try 255 to set the sar_width and sar_height
2122 // aspect_ratio_idc
2123 writer.write_bits(255, 8).unwrap();
2124 bit_count += 8;
2125 // sar_width
2126 writer.write_bits(0, 16).unwrap();
2127 bit_count += 16;
2128 // sar_height
2129 writer.write_bits(0, 16).unwrap();
2130 bit_count += 16;
2131
2132 // overscan_info_present_flag
2133 writer.write_bit(false).unwrap();
2134 bit_count += 1;
2135
2136 // video_signal_type_present_flag
2137 writer.write_bit(true).unwrap();
2138 bit_count += 1;
2139 // video_format
2140 writer.write_bits(0, 3).unwrap();
2141 bit_count += 3;
2142 // video_full_range_flag
2143 writer.write_bit(false).unwrap();
2144 bit_count += 1;
2145 // color_description_present_flag
2146 writer.write_bit(true).unwrap();
2147 bit_count += 1;
2148 // color_primaries
2149 writer.write_bits(1, 8).unwrap();
2150 bit_count += 8;
2151 // transfer_characteristics
2152 writer.write_bits(1, 8).unwrap();
2153 bit_count += 8;
2154 // matrix_coefficients
2155 writer.write_bits(1, 8).unwrap();
2156 bit_count += 8;
2157
2158 // chroma_loc_info_present_flag
2159 writer.write_bit(false).unwrap();
2160 bit_count += 1;
2161
2162 // timing_info_present_flag
2163 writer.write_bit(true).unwrap();
2164 bit_count += 1;
2165 // we can set this to 1000 for example
2166 // num_units_in_tick is a u32
2167 writer.write_bits(1000, 32).unwrap();
2168 bit_count += 32;
2169 // fps = time_scale / (2 * num_units_in_tick)
2170 // since we want 480 fps:
2171 // 480 = time_scale / (2 * 1000)
2172 // 960 000 = time_scale
2173 // time_scale is a u32
2174 writer.write_bits(960000, 32).unwrap();
2175 bit_count += 32;
2176 writer.finish().unwrap();
2177
2178 let result = Sps::parse(std::io::Cursor::new(&sps)).unwrap();
2179
2180 // now we can check the size:
2181 assert_eq!(result.size(), bit_count.div_ceil(8));
2182 }
2183
2184 #[test]
2185 fn test_reduce_color_config() {
2186 let mut sps = Vec::new();
2187 let mut writer = BitWriter::new(&mut sps);
2188
2189 // forbidden zero bit must be unset
2190 writer.write_bit(false).unwrap();
2191 // nal_ref_idc is 0
2192 writer.write_bits(0, 2).unwrap();
2193 // nal_unit_type must be 7
2194 writer.write_bits(7, 5).unwrap();
2195
2196 // profile_idc = 100
2197 writer.write_bits(100, 8).unwrap();
2198 // constraint_setn_flags all false
2199 writer.write_bits(0, 8).unwrap();
2200 // level_idc = 0
2201 writer.write_bits(0, 8).unwrap();
2202
2203 // seq_parameter_set_id is expg
2204 writer.write_exp_golomb(0).unwrap();
2205
2206 // sps ext
2207 // chroma_format_idc is expg
2208 writer.write_exp_golomb(0).unwrap();
2209 // bit_depth_luma_minus8 is expg
2210 writer.write_exp_golomb(0).unwrap();
2211 // bit_depth_chroma_minus8 is expg
2212 writer.write_exp_golomb(0).unwrap();
2213 // qpprime
2214 writer.write_bit(false).unwrap();
2215 // seq_scaling_matrix_present_flag
2216 writer.write_bit(false).unwrap();
2217
2218 // back to sps
2219 // log2_max_frame_num_minus4 is expg
2220 writer.write_exp_golomb(0).unwrap();
2221 // pic_order_cnt_type is expg
2222 writer.write_exp_golomb(0).unwrap();
2223 // log2_max_pic_order_cnt_lsb_minus4 is expg
2224 writer.write_exp_golomb(0).unwrap();
2225
2226 // max_num_ref_frames is expg
2227 writer.write_exp_golomb(0).unwrap();
2228 // gaps_in_frame_num_value_allowed_flag
2229 writer.write_bit(false).unwrap();
2230 // width
2231 writer.write_exp_golomb(0).unwrap();
2232 // height
2233 writer.write_exp_golomb(0).unwrap();
2234
2235 // frame_mbs_only_flag
2236 writer.write_bit(true).unwrap();
2237
2238 // direct_8x8_inference_flag
2239 writer.write_bit(false).unwrap();
2240 // frame_cropping_flag
2241 writer.write_bit(false).unwrap();
2242
2243 // vui_parameters_present_flag
2244 writer.write_bit(true).unwrap();
2245
2246 // aspect_ratio_info_present_flag
2247 writer.write_bit(false).unwrap();
2248
2249 // overscan_info_present_flag
2250 writer.write_bit(false).unwrap();
2251
2252 // we want to change the color_config
2253 // video_signal_type_present_flag
2254 writer.write_bit(true).unwrap();
2255
2256 // video_format
2257 writer.write_bits(1, 3).unwrap();
2258 // video_full_range_flag
2259 writer.write_bit(false).unwrap();
2260 // color_description_present_flag: we want this to be true
2261 writer.write_bit(true).unwrap();
2262
2263 // now we set these to redundant values (each should be 2)
2264 writer.write_bits(2, 8).unwrap();
2265 writer.write_bits(2, 8).unwrap();
2266 writer.write_bits(2, 8).unwrap();
2267
2268 // chroma_loc_info_present_flag
2269 writer.write_bit(false).unwrap();
2270
2271 // timing_info_present_flag
2272 writer.write_bit(false).unwrap();
2273 writer.finish().unwrap();
2274
2275 let reduced_sps = Sps::parse(std::io::Cursor::new(&sps)).unwrap();
2276
2277 let mut reduced_buf = Vec::new();
2278 reduced_sps.build(&mut reduced_buf).unwrap();
2279
2280 assert_ne!(sps, reduced_buf);
2281 }
2282
2283 #[test]
2284 fn test_reduce_vui() {
2285 let mut sps = Vec::new();
2286 let mut writer = BitWriter::new(&mut sps);
2287
2288 // forbidden zero bit must be unset
2289 writer.write_bit(false).unwrap();
2290 // nal_ref_idc is 0
2291 writer.write_bits(0, 2).unwrap();
2292 // nal_unit_type must be 7
2293 writer.write_bits(7, 5).unwrap();
2294
2295 // profile_idc = 100
2296 writer.write_bits(100, 8).unwrap();
2297 // constraint_setn_flags all false
2298 writer.write_bits(0, 8).unwrap();
2299 // level_idc = 0
2300 writer.write_bits(0, 8).unwrap();
2301
2302 // seq_parameter_set_id is expg
2303 writer.write_exp_golomb(0).unwrap();
2304
2305 // sps ext
2306 // chroma_format_idc is expg
2307 writer.write_exp_golomb(0).unwrap();
2308 // bit_depth_luma_minus8 is expg
2309 writer.write_exp_golomb(0).unwrap();
2310 // bit_depth_chroma_minus8 is expg
2311 writer.write_exp_golomb(0).unwrap();
2312 // qpprime
2313 writer.write_bit(false).unwrap();
2314 // seq_scaling_matrix_present_flag
2315 writer.write_bit(false).unwrap();
2316
2317 // back to sps
2318 // log2_max_frame_num_minus4 is expg
2319 writer.write_exp_golomb(0).unwrap();
2320 // pic_order_cnt_type is expg
2321 writer.write_exp_golomb(0).unwrap();
2322 // log2_max_pic_order_cnt_lsb_minus4 is expg
2323 writer.write_exp_golomb(0).unwrap();
2324
2325 // max_num_ref_frames is expg
2326 writer.write_exp_golomb(0).unwrap();
2327 // gaps_in_frame_num_value_allowed_flag
2328 writer.write_bit(false).unwrap();
2329 // width
2330 writer.write_exp_golomb(0).unwrap();
2331 // height
2332 writer.write_exp_golomb(0).unwrap();
2333
2334 // frame_mbs_only_flag
2335 writer.write_bit(true).unwrap();
2336
2337 // direct_8x8_inference_flag
2338 writer.write_bit(false).unwrap();
2339 // frame_cropping_flag
2340 writer.write_bit(false).unwrap();
2341
2342 // we want to set this flag to be true and all subsequent flags to be false.
2343 // vui_parameters_present_flag
2344 writer.write_bit(true).unwrap();
2345
2346 // aspect_ratio_info_present_flag
2347 writer.write_bit(false).unwrap();
2348
2349 // overscan_info_present_flag
2350 writer.write_bit(false).unwrap();
2351
2352 // video_signal_type_present_flag
2353 writer.write_bit(false).unwrap();
2354
2355 // chroma_loc_info_present_flag
2356 writer.write_bit(false).unwrap();
2357
2358 // timing_info_present_flag
2359 writer.write_bit(false).unwrap();
2360 writer.finish().unwrap();
2361
2362 let result = Sps::parse(std::io::Cursor::new(&sps)).unwrap();
2363
2364 let mut reduced_buf = Vec::new();
2365 result.build(&mut reduced_buf).unwrap();
2366
2367 let reduced_result = Sps::parse(std::io::Cursor::new(&reduced_buf)).unwrap();
2368 assert_eq!(result.size(), reduced_result.size());
2369
2370 insta::assert_debug_snapshot!(reduced_result, @r"
2371 Sps {
2372 nal_ref_idc: 0,
2373 nal_unit_type: NALUnitType::SPS,
2374 profile_idc: 100,
2375 constraint_set0_flag: false,
2376 constraint_set1_flag: false,
2377 constraint_set2_flag: false,
2378 constraint_set3_flag: false,
2379 constraint_set4_flag: false,
2380 constraint_set5_flag: false,
2381 level_idc: 0,
2382 seq_parameter_set_id: 0,
2383 ext: Some(
2384 SpsExtended {
2385 chroma_format_idc: 0,
2386 separate_color_plane_flag: false,
2387 bit_depth_luma_minus8: 0,
2388 bit_depth_chroma_minus8: 0,
2389 qpprime_y_zero_transform_bypass_flag: false,
2390 scaling_matrix: [],
2391 },
2392 ),
2393 log2_max_frame_num_minus4: 0,
2394 pic_order_cnt_type: 0,
2395 log2_max_pic_order_cnt_lsb_minus4: Some(
2396 0,
2397 ),
2398 pic_order_cnt_type1: None,
2399 max_num_ref_frames: 0,
2400 gaps_in_frame_num_value_allowed_flag: false,
2401 pic_width_in_mbs_minus1: 0,
2402 pic_height_in_map_units_minus1: 0,
2403 mb_adaptive_frame_field_flag: None,
2404 direct_8x8_inference_flag: false,
2405 frame_crop_info: None,
2406 sample_aspect_ratio: None,
2407 overscan_appropriate_flag: None,
2408 color_config: None,
2409 chroma_sample_loc: None,
2410 timing_info: None,
2411 }
2412 ");
2413 }
2414}