1use crate::rbsp::{BitRead, BitReaderError};
2use std::{
3 fmt::{self, Debug},
4 num::NonZeroU8,
5};
6
7#[derive(Debug, PartialEq)]
8pub enum SeqParamSetIdError {
9 IdTooLarge(u32),
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub struct SeqParamSetId(u8);
14impl SeqParamSetId {
15 pub fn from_u32(id: u32) -> Result<SeqParamSetId, SeqParamSetIdError> {
16 if id > 31 {
17 Err(SeqParamSetIdError::IdTooLarge(id))
18 } else {
19 Ok(SeqParamSetId(id as u8))
20 }
21 }
22 pub fn id(self) -> u8 {
23 self.0
24 }
25}
26
27#[derive(Debug)]
28pub enum SpsError {
29 BitDepthOutOfRange(u32),
31 RbspReaderError(BitReaderError),
32 PicOrderCnt(PicOrderCntError),
33 ScalingMatrix(ScalingMatrixError),
34 Log2MaxFrameNumMinus4OutOfRange(u32),
36 BadSeqParamSetId(SeqParamSetIdError),
37 UnknownSeqParamSetId(SeqParamSetId),
38 FieldValueTooLarge {
40 name: &'static str,
41 value: u32,
42 },
43 FieldValueTooSmall {
45 name: &'static str,
46 value: u32,
47 },
48 CroppingError(FrameCropping),
50 CpbCountOutOfRange(u32),
52}
53
54impl From<BitReaderError> for SpsError {
55 fn from(e: BitReaderError) -> Self {
56 SpsError::RbspReaderError(e)
57 }
58}
59
60#[derive(Debug)]
61pub enum Profile {
62 Unknown(u8),
63 Baseline,
64 Main,
65 High,
66 High422,
67 High10,
68 High444,
69 Extended,
70 ScalableBase,
71 ScalableHigh,
72 MultiviewHigh,
73 StereoHigh,
74 MFCDepthHigh,
75 MultiviewDepthHigh,
76 EnhancedMultiviewDepthHigh,
77}
78
79impl Profile {
80 pub fn from_profile_idc(profile_idc: ProfileIdc) -> Profile {
81 match profile_idc.0 {
83 66 => Profile::Baseline,
84 77 => Profile::Main,
85 100 => Profile::High,
86 122 => Profile::High422,
87 110 => Profile::High10,
88 244 => Profile::High444,
89 88 => Profile::Extended,
90 83 => Profile::ScalableBase,
91 86 => Profile::ScalableHigh,
92 118 => Profile::MultiviewHigh,
93 128 => Profile::StereoHigh,
94 135 => Profile::MFCDepthHigh,
95 138 => Profile::MultiviewDepthHigh,
96 139 => Profile::EnhancedMultiviewDepthHigh,
97 other => Profile::Unknown(other),
98 }
99 }
100 pub fn profile_idc(&self) -> u8 {
101 match *self {
102 Profile::Baseline => 66,
103 Profile::Main => 77,
104 Profile::High => 100,
105 Profile::High422 => 122,
106 Profile::High10 => 110,
107 Profile::High444 => 144,
108 Profile::Extended => 88,
109 Profile::ScalableBase => 83,
110 Profile::ScalableHigh => 86,
111 Profile::MultiviewHigh => 118,
112 Profile::StereoHigh => 128,
113 Profile::MFCDepthHigh => 135,
114 Profile::MultiviewDepthHigh => 138,
115 Profile::EnhancedMultiviewDepthHigh => 139,
116 Profile::Unknown(profile_idc) => profile_idc,
117 }
118 }
119}
120
121#[derive(Copy, Clone, PartialEq, Eq)]
122pub struct ConstraintFlags(u8);
123impl From<u8> for ConstraintFlags {
124 fn from(v: u8) -> Self {
125 ConstraintFlags(v)
126 }
127}
128impl From<ConstraintFlags> for u8 {
129 fn from(v: ConstraintFlags) -> Self {
130 v.0
131 }
132}
133impl ConstraintFlags {
134 pub fn flag0(self) -> bool {
135 self.0 & 0b1000_0000 != 0
136 }
137 pub fn flag1(self) -> bool {
138 self.0 & 0b0100_0000 != 0
139 }
140 pub fn flag2(self) -> bool {
141 self.0 & 0b0010_0000 != 0
142 }
143 pub fn flag3(self) -> bool {
144 self.0 & 0b0001_0000 != 0
145 }
146 pub fn flag4(self) -> bool {
147 self.0 & 0b0000_1000 != 0
148 }
149 pub fn flag5(self) -> bool {
150 self.0 & 0b0000_0100 != 0
151 }
152 pub fn reserved_zero_two_bits(self) -> u8 {
153 self.0 & 0b0000_0011
154 }
155}
156impl Debug for ConstraintFlags {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
158 f.debug_struct("ConstraintFlags")
159 .field("flag0", &self.flag0())
160 .field("flag1", &self.flag1())
161 .field("flag2", &self.flag2())
162 .field("flag3", &self.flag3())
163 .field("flag4", &self.flag4())
164 .field("flag5", &self.flag5())
165 .field("reserved_zero_two_bits", &self.reserved_zero_two_bits())
166 .finish()
167 }
168}
169
170#[derive(Debug, PartialEq, Hash, Eq)]
171#[allow(non_camel_case_types)]
172pub enum Level {
173 Unknown(u8),
174 L1,
175 L1_b,
176 L1_1,
177 L1_2,
178 L1_3,
179 L2,
180 L2_1,
181 L2_2,
182 L3,
183 L3_1,
184 L3_2,
185 L4,
186 L4_1,
187 L4_2,
188 L5,
189 L5_1,
190 L5_2,
191 L6,
192 L6_1,
193 L6_2,
194}
195impl Level {
196 pub fn from_constraint_flags_and_level_idc(
197 constraint_flags: ConstraintFlags,
198 level_idc: u8,
199 ) -> Level {
200 match level_idc {
201 10 => Level::L1,
202 11 => {
203 if constraint_flags.flag3() {
204 Level::L1_b
205 } else {
206 Level::L1_1
207 }
208 }
209 12 => Level::L1_2,
210 13 => Level::L1_3,
211 20 => Level::L2,
212 21 => Level::L2_1,
213 22 => Level::L2_2,
214 30 => Level::L3,
215 31 => Level::L3_1,
216 32 => Level::L3_2,
217 40 => Level::L4,
218 41 => Level::L4_1,
219 42 => Level::L4_2,
220 50 => Level::L5,
221 51 => Level::L5_1,
222 52 => Level::L5_2,
223 60 => Level::L6,
224 61 => Level::L6_1,
225 62 => Level::L6_2,
226 _ => Level::Unknown(level_idc),
227 }
228 }
229 pub fn level_idc(&self) -> u8 {
230 match *self {
231 Level::L1 => 10,
232 Level::L1_1 | Level::L1_b => 11,
233 Level::L1_2 => 12,
234 Level::L1_3 => 13,
235 Level::L2 => 20,
236 Level::L2_1 => 21,
237 Level::L2_2 => 22,
238 Level::L3 => 30,
239 Level::L3_1 => 31,
240 Level::L3_2 => 32,
241 Level::L4 => 40,
242 Level::L4_1 => 41,
243 Level::L4_2 => 42,
244 Level::L5 => 50,
245 Level::L5_1 => 51,
246 Level::L5_2 => 52,
247 Level::L6 => 60,
248 Level::L6_1 => 61,
249 Level::L6_2 => 62,
250 Level::Unknown(level_idc) => level_idc,
251 }
252 }
253}
254
255#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
256pub enum ChromaFormat {
257 Monochrome,
258 #[default]
259 YUV420,
260 YUV422,
261 YUV444,
262 Invalid(u32),
263}
264impl ChromaFormat {
265 fn from_chroma_format_idc(chroma_format_idc: u32) -> ChromaFormat {
266 match chroma_format_idc {
267 0 => ChromaFormat::Monochrome,
268 1 => ChromaFormat::YUV420,
269 2 => ChromaFormat::YUV422,
270 3 => ChromaFormat::YUV444,
271 _ => ChromaFormat::Invalid(chroma_format_idc),
272 }
273 }
274}
275
276#[derive(Copy, Clone, Debug, PartialEq, Eq)]
278pub struct ProfileIdc(u8);
279impl ProfileIdc {
280 pub fn has_chroma_info(self) -> bool {
281 match self.0 {
282 100 | 110 | 122 | 244 | 44 | 83 | 86 => true,
283 _ => false,
284 }
285 }
286}
287impl From<u8> for ProfileIdc {
288 fn from(v: u8) -> Self {
289 ProfileIdc(v)
290 }
291}
292impl From<ProfileIdc> for u8 {
293 fn from(v: ProfileIdc) -> Self {
294 v.0
295 }
296}
297
298#[derive(Clone, Debug, PartialEq, Eq)]
299pub enum ScalingList<const S: usize> {
300 NotPresent,
301 UseDefault,
302 List([NonZeroU8; S]),
303}
304
305fn fill_scaling_list<R: BitRead>(
307 r: &mut R,
308 scaling_list: &mut [NonZeroU8],
309) -> Result<bool, ScalingMatrixError> {
310 let mut last_scale = NonZeroU8::new(8).unwrap();
311 let mut next_scale = 8;
312 let mut use_default_scaling_matrix_flag = false;
313
314 for j in 0..scaling_list.len() {
315 if next_scale != 0 {
316 let delta_scale = r.read_se("delta_scale")?;
317 if delta_scale < -128 || delta_scale > 127 {
318 return Err(ScalingMatrixError::DeltaScaleOutOfRange(delta_scale));
319 }
320 next_scale = (last_scale.get() as i32 + delta_scale + 256) % 256;
321 use_default_scaling_matrix_flag = j == 0 && next_scale == 0;
322 }
323 let new_value = NonZeroU8::new(next_scale as u8).unwrap_or(last_scale);
324 scaling_list[j] = new_value;
325 last_scale = new_value;
326 }
327
328 Ok(use_default_scaling_matrix_flag)
329}
330
331impl<const S: usize> ScalingList<S> {
332 pub fn read<R: BitRead>(
333 r: &mut R,
334 present: bool,
335 ) -> Result<ScalingList<S>, ScalingMatrixError> {
336 if !present {
337 return Ok(ScalingList::NotPresent);
338 }
339 let mut scaling_list = [NonZeroU8::new(1).unwrap(); S];
340
341 let use_default_scaling_matrix_flag = fill_scaling_list(r, &mut scaling_list)?;
342 if use_default_scaling_matrix_flag {
343 Ok(ScalingList::UseDefault)
344 } else {
345 Ok(ScalingList::List(scaling_list))
346 }
347 }
348}
349
350#[derive(Debug)]
351pub enum ScalingMatrixError {
352 ReaderError(BitReaderError),
353 DeltaScaleOutOfRange(i32),
355}
356
357impl From<BitReaderError> for ScalingMatrixError {
358 fn from(e: BitReaderError) -> Self {
359 ScalingMatrixError::ReaderError(e)
360 }
361}
362
363#[derive(Clone, Debug, Default, PartialEq, Eq)]
364pub struct SeqScalingMatrix {
365 pub scaling_list4x4: Vec<ScalingList<16>>,
366 pub scaling_list8x8: Vec<ScalingList<64>>,
367}
368
369impl SeqScalingMatrix {
370 fn read<R: BitRead>(
371 r: &mut R,
372 chroma_format_idc: u32,
373 ) -> Result<SeqScalingMatrix, ScalingMatrixError> {
374 let count = if chroma_format_idc == 3 { 12 } else { 8 };
375
376 let mut scaling_list4x4 = Vec::with_capacity(6);
377 let mut scaling_list8x8 = Vec::with_capacity(count - 6);
378
379 for i in 0..count {
380 let seq_scaling_list_present_flag = r.read_bool("seq_scaling_list_present_flag")?;
381 if i < 6 {
382 scaling_list4x4.push(ScalingList::<16>::read(r, seq_scaling_list_present_flag)?);
383 } else {
384 scaling_list8x8.push(ScalingList::<64>::read(r, seq_scaling_list_present_flag)?);
385 }
386 }
387
388 Ok(SeqScalingMatrix {
389 scaling_list4x4,
390 scaling_list8x8,
391 })
392 }
393}
394
395#[derive(Debug, Default, Clone, PartialEq, Eq)]
396pub struct ChromaInfo {
397 pub chroma_format: ChromaFormat,
398 pub separate_colour_plane_flag: bool,
399 pub bit_depth_luma_minus8: u8,
400 pub bit_depth_chroma_minus8: u8,
401 pub qpprime_y_zero_transform_bypass_flag: bool,
402 pub scaling_matrix: Option<SeqScalingMatrix>,
403}
404impl ChromaInfo {
405 pub fn read<R: BitRead>(r: &mut R, profile_idc: ProfileIdc) -> Result<ChromaInfo, SpsError> {
406 if profile_idc.has_chroma_info() {
407 let chroma_format_idc = r.read_ue("chroma_format_idc")?;
408 Ok(ChromaInfo {
409 chroma_format: ChromaFormat::from_chroma_format_idc(chroma_format_idc),
410 separate_colour_plane_flag: if chroma_format_idc == 3 {
411 r.read_bool("separate_colour_plane_flag")?
412 } else {
413 false
414 },
415 bit_depth_luma_minus8: Self::read_bit_depth_minus8(r)?,
416 bit_depth_chroma_minus8: Self::read_bit_depth_minus8(r)?,
417 qpprime_y_zero_transform_bypass_flag: r
418 .read_bool("qpprime_y_zero_transform_bypass_flag")?,
419 scaling_matrix: Self::read_scaling_matrix(r, chroma_format_idc)?,
420 })
421 } else {
422 Ok(ChromaInfo::default())
423 }
424 }
425 fn read_bit_depth_minus8<R: BitRead>(r: &mut R) -> Result<u8, SpsError> {
426 let value = r.read_ue("read_bit_depth_minus8")?;
427 if value > 6 {
428 Err(SpsError::BitDepthOutOfRange(value))
429 } else {
430 Ok(value as u8)
431 }
432 }
433 fn read_scaling_matrix<R: BitRead>(
434 r: &mut R,
435 chroma_format_idc: u32,
436 ) -> Result<Option<SeqScalingMatrix>, SpsError> {
437 let scaling_matrix_present_flag = r.read_bool("scaling_matrix_present_flag")?;
438 if scaling_matrix_present_flag {
439 Ok(Some(
440 SeqScalingMatrix::read(r, chroma_format_idc).map_err(SpsError::ScalingMatrix)?,
441 ))
442 } else {
443 Ok(None)
444 }
445 }
446}
447
448#[derive(Debug)]
449pub enum PicOrderCntError {
450 InvalidPicOrderCountType(u32),
451 ReaderError(BitReaderError),
452 Log2MaxPicOrderCntLsbMinus4OutOfRange(u32),
454 NumRefFramesInPicOrderCntCycleOutOfRange(u32),
456}
457
458impl From<BitReaderError> for PicOrderCntError {
459 fn from(e: BitReaderError) -> Self {
460 PicOrderCntError::ReaderError(e)
461 }
462}
463
464#[derive(Clone, Debug, PartialEq, Eq)]
465pub enum PicOrderCntType {
466 TypeZero {
467 log2_max_pic_order_cnt_lsb_minus4: u8,
468 },
469 TypeOne {
470 delta_pic_order_always_zero_flag: bool,
471 offset_for_non_ref_pic: i32,
472 offset_for_top_to_bottom_field: i32,
473 offsets_for_ref_frame: Vec<i32>,
474 },
475 TypeTwo,
476}
477impl PicOrderCntType {
478 fn read<R: BitRead>(r: &mut R) -> Result<PicOrderCntType, PicOrderCntError> {
479 let pic_order_cnt_type = r.read_ue("pic_order_cnt_type")?;
480 match pic_order_cnt_type {
481 0 => Ok(PicOrderCntType::TypeZero {
482 log2_max_pic_order_cnt_lsb_minus4: Self::read_log2_max_pic_order_cnt_lsb_minus4(r)?,
483 }),
484 1 => Ok(PicOrderCntType::TypeOne {
485 delta_pic_order_always_zero_flag: r
486 .read_bool("delta_pic_order_always_zero_flag")?,
487 offset_for_non_ref_pic: r.read_se("offset_for_non_ref_pic")?,
488 offset_for_top_to_bottom_field: r.read_se("offset_for_top_to_bottom_field")?,
489 offsets_for_ref_frame: Self::read_offsets_for_ref_frame(r)?,
490 }),
491 2 => Ok(PicOrderCntType::TypeTwo),
492 _ => Err(PicOrderCntError::InvalidPicOrderCountType(
493 pic_order_cnt_type,
494 )),
495 }
496 }
497
498 fn read_log2_max_pic_order_cnt_lsb_minus4<R: BitRead>(
499 r: &mut R,
500 ) -> Result<u8, PicOrderCntError> {
501 let val = r.read_ue("log2_max_pic_order_cnt_lsb_minus4")?;
502 if val > 12 {
503 Err(PicOrderCntError::Log2MaxPicOrderCntLsbMinus4OutOfRange(val))
504 } else {
505 Ok(val as u8)
506 }
507 }
508
509 fn read_offsets_for_ref_frame<R: BitRead>(r: &mut R) -> Result<Vec<i32>, PicOrderCntError> {
510 let num_ref_frames_in_pic_order_cnt_cycle =
511 r.read_ue("num_ref_frames_in_pic_order_cnt_cycle")?;
512 if num_ref_frames_in_pic_order_cnt_cycle > 255 {
513 return Err(PicOrderCntError::NumRefFramesInPicOrderCntCycleOutOfRange(
514 num_ref_frames_in_pic_order_cnt_cycle,
515 ));
516 }
517 let mut offsets = Vec::with_capacity(num_ref_frames_in_pic_order_cnt_cycle as usize);
518 for _ in 0..num_ref_frames_in_pic_order_cnt_cycle {
519 offsets.push(r.read_se("offset_for_ref_frame")?);
520 }
521 Ok(offsets)
522 }
523}
524
525#[derive(Clone, Debug, PartialEq, Eq)]
526pub enum FrameMbsFlags {
527 Frames,
528 Fields { mb_adaptive_frame_field_flag: bool },
529}
530impl FrameMbsFlags {
531 fn read<R: BitRead>(r: &mut R) -> Result<FrameMbsFlags, BitReaderError> {
532 let frame_mbs_only_flag = r.read_bool("frame_mbs_only_flag")?;
533 if frame_mbs_only_flag {
534 Ok(FrameMbsFlags::Frames)
535 } else {
536 Ok(FrameMbsFlags::Fields {
537 mb_adaptive_frame_field_flag: r.read_bool("mb_adaptive_frame_field_flag")?,
538 })
539 }
540 }
541}
542
543#[derive(Clone, Debug, Default, PartialEq, Eq)]
544pub struct FrameCropping {
545 pub left_offset: u32,
546 pub right_offset: u32,
547 pub top_offset: u32,
548 pub bottom_offset: u32,
549}
550impl FrameCropping {
551 fn read<R: BitRead>(r: &mut R) -> Result<Option<FrameCropping>, BitReaderError> {
552 let frame_cropping_flag = r.read_bool("frame_cropping_flag")?;
553 Ok(if frame_cropping_flag {
554 Some(FrameCropping {
555 left_offset: r.read_ue("left_offset")?,
556 right_offset: r.read_ue("right_offset")?,
557 top_offset: r.read_ue("top_offset")?,
558 bottom_offset: r.read_ue("bottom_offset")?,
559 })
560 } else {
561 None
562 })
563 }
564}
565
566#[derive(Clone, Debug, Default, PartialEq, Eq)]
567pub enum AspectRatioInfo {
568 #[default]
569 Unspecified,
570 Ratio1_1,
571 Ratio12_11,
572 Ratio10_11,
573 Ratio16_11,
574 Ratio40_33,
575 Ratio24_11,
576 Ratio20_11,
577 Ratio32_11,
578 Ratio80_33,
579 Ratio18_11,
580 Ratio15_11,
581 Ratio64_33,
582 Ratio160_99,
583 Ratio4_3,
584 Ratio3_2,
585 Ratio2_1,
586 Reserved(u8),
587 Extended(u16, u16),
588}
589impl AspectRatioInfo {
590 fn read<R: BitRead>(r: &mut R) -> Result<Option<AspectRatioInfo>, BitReaderError> {
591 let aspect_ratio_info_present_flag = r.read_bool("aspect_ratio_info_present_flag")?;
592 Ok(if aspect_ratio_info_present_flag {
593 let aspect_ratio_idc = r.read(8, "aspect_ratio_idc")?;
594 Some(match aspect_ratio_idc {
595 0 => AspectRatioInfo::Unspecified,
596 1 => AspectRatioInfo::Ratio1_1,
597 2 => AspectRatioInfo::Ratio12_11,
598 3 => AspectRatioInfo::Ratio10_11,
599 4 => AspectRatioInfo::Ratio16_11,
600 5 => AspectRatioInfo::Ratio40_33,
601 6 => AspectRatioInfo::Ratio24_11,
602 7 => AspectRatioInfo::Ratio20_11,
603 8 => AspectRatioInfo::Ratio32_11,
604 9 => AspectRatioInfo::Ratio80_33,
605 10 => AspectRatioInfo::Ratio18_11,
606 11 => AspectRatioInfo::Ratio15_11,
607 12 => AspectRatioInfo::Ratio64_33,
608 13 => AspectRatioInfo::Ratio160_99,
609 14 => AspectRatioInfo::Ratio4_3,
610 15 => AspectRatioInfo::Ratio3_2,
611 16 => AspectRatioInfo::Ratio2_1,
612 255 => {
613 AspectRatioInfo::Extended(r.read(16, "sar_width")?, r.read(16, "sar_height")?)
614 }
615 _ => AspectRatioInfo::Reserved(aspect_ratio_idc),
616 })
617 } else {
618 None
619 })
620 }
621
622 pub fn get(&self) -> Option<(u16, u16)> {
624 match self {
625 AspectRatioInfo::Unspecified => None,
626 AspectRatioInfo::Ratio1_1 => Some((1, 1)),
627 AspectRatioInfo::Ratio12_11 => Some((12, 11)),
628 AspectRatioInfo::Ratio10_11 => Some((10, 11)),
629 AspectRatioInfo::Ratio16_11 => Some((16, 11)),
630 AspectRatioInfo::Ratio40_33 => Some((40, 33)),
631 AspectRatioInfo::Ratio24_11 => Some((24, 11)),
632 AspectRatioInfo::Ratio20_11 => Some((20, 11)),
633 AspectRatioInfo::Ratio32_11 => Some((32, 11)),
634 AspectRatioInfo::Ratio80_33 => Some((80, 33)),
635 AspectRatioInfo::Ratio18_11 => Some((18, 11)),
636 AspectRatioInfo::Ratio15_11 => Some((15, 11)),
637 AspectRatioInfo::Ratio64_33 => Some((64, 33)),
638 AspectRatioInfo::Ratio160_99 => Some((160, 99)),
639 AspectRatioInfo::Ratio4_3 => Some((4, 3)),
640 AspectRatioInfo::Ratio3_2 => Some((3, 2)),
641 AspectRatioInfo::Ratio2_1 => Some((2, 1)),
642 AspectRatioInfo::Reserved(_) => None,
643 &AspectRatioInfo::Extended(width, height) => {
644 if width == 0 || height == 0 {
648 None
649 } else {
650 Some((width, height))
651 }
652 }
653 }
654 }
655}
656
657#[derive(Clone, Debug, Default, PartialEq, Eq)]
658pub enum OverscanAppropriate {
659 #[default]
660 Unspecified,
661 Appropriate,
662 Inappropriate,
663}
664impl OverscanAppropriate {
665 fn read<R: BitRead>(r: &mut R) -> Result<OverscanAppropriate, BitReaderError> {
666 let overscan_info_present_flag = r.read_bool("overscan_info_present_flag")?;
667 Ok(if overscan_info_present_flag {
668 let overscan_appropriate_flag = r.read_bool("overscan_appropriate_flag")?;
669 if overscan_appropriate_flag {
670 OverscanAppropriate::Appropriate
671 } else {
672 OverscanAppropriate::Inappropriate
673 }
674 } else {
675 OverscanAppropriate::Unspecified
676 })
677 }
678}
679
680#[derive(Clone, Debug, Default, PartialEq, Eq)]
681pub enum VideoFormat {
682 #[default]
683 Component,
684 PAL,
685 NTSC,
686 SECAM,
687 MAC,
688 Unspecified,
689 Reserved(u8),
690}
691impl VideoFormat {
692 fn from(video_format: u8) -> VideoFormat {
693 match video_format {
694 0 => VideoFormat::Component,
695 1 => VideoFormat::PAL,
696 2 => VideoFormat::NTSC,
697 3 => VideoFormat::SECAM,
698 4 => VideoFormat::MAC,
699 5 => VideoFormat::Unspecified,
700 6 | 7 => VideoFormat::Reserved(video_format),
701 _ => panic!("unsupported video_format value {}", video_format),
702 }
703 }
704}
705
706#[derive(Clone, Debug, Default, PartialEq, Eq)]
707pub struct ColourDescription {
708 pub colour_primaries: u8,
709 pub transfer_characteristics: u8,
710 pub matrix_coefficients: u8,
711}
712impl ColourDescription {
713 fn read<R: BitRead>(r: &mut R) -> Result<Option<ColourDescription>, BitReaderError> {
714 let colour_description_present_flag = r.read_bool("colour_description_present_flag")?;
715 Ok(if colour_description_present_flag {
716 Some(ColourDescription {
717 colour_primaries: r.read(8, "colour_primaries")?,
718 transfer_characteristics: r.read(8, "transfer_characteristics")?,
719 matrix_coefficients: r.read(8, "matrix_coefficients")?,
720 })
721 } else {
722 None
723 })
724 }
725}
726
727#[derive(Clone, Debug, Default, PartialEq, Eq)]
728pub struct VideoSignalType {
729 pub video_format: VideoFormat,
730 pub video_full_range_flag: bool,
731 pub colour_description: Option<ColourDescription>,
732}
733impl VideoSignalType {
734 fn read<R: BitRead>(r: &mut R) -> Result<Option<VideoSignalType>, BitReaderError> {
735 let video_signal_type_present_flag = r.read_bool("video_signal_type_present_flag")?;
736 Ok(if video_signal_type_present_flag {
737 Some(VideoSignalType {
738 video_format: VideoFormat::from(r.read(3, "video_format")?),
739 video_full_range_flag: r.read_bool("video_full_range_flag")?,
740 colour_description: ColourDescription::read(r)?,
741 })
742 } else {
743 None
744 })
745 }
746}
747
748#[derive(Clone, Debug, Default, PartialEq, Eq)]
749pub struct ChromaLocInfo {
750 pub chroma_sample_loc_type_top_field: u32,
751 pub chroma_sample_loc_type_bottom_field: u32,
752}
753impl ChromaLocInfo {
754 fn read<R: BitRead>(r: &mut R) -> Result<Option<ChromaLocInfo>, BitReaderError> {
755 let chroma_loc_info_present_flag = r.read_bool("chroma_loc_info_present_flag")?;
756 Ok(if chroma_loc_info_present_flag {
757 Some(ChromaLocInfo {
758 chroma_sample_loc_type_top_field: r.read_ue("chroma_sample_loc_type_top_field")?,
759 chroma_sample_loc_type_bottom_field: r
760 .read_ue("chroma_sample_loc_type_bottom_field")?,
761 })
762 } else {
763 None
764 })
765 }
766}
767
768#[derive(Clone, Debug, Default, PartialEq, Eq)]
769pub struct TimingInfo {
770 pub num_units_in_tick: u32,
771 pub time_scale: u32,
772 pub fixed_frame_rate_flag: bool,
773}
774impl TimingInfo {
775 fn read<R: BitRead>(r: &mut R) -> Result<Option<TimingInfo>, BitReaderError> {
776 let timing_info_present_flag = r.read_bool("timing_info_present_flag")?;
777 Ok(if timing_info_present_flag {
778 Some(TimingInfo {
779 num_units_in_tick: r.read(32, "num_units_in_tick")?,
780 time_scale: r.read(32, "time_scale")?,
781 fixed_frame_rate_flag: r.read_bool("fixed_frame_rate_flag")?,
782 })
783 } else {
784 None
785 })
786 }
787}
788
789#[derive(Clone, Debug, Default, PartialEq, Eq)]
790pub struct CpbSpec {
791 pub bit_rate_value_minus1: u32,
792 pub cpb_size_value_minus1: u32,
793 pub cbr_flag: bool,
794}
795impl CpbSpec {
796 fn read<R: BitRead>(r: &mut R) -> Result<CpbSpec, BitReaderError> {
797 Ok(CpbSpec {
798 bit_rate_value_minus1: r.read_ue("bit_rate_value_minus1")?,
799 cpb_size_value_minus1: r.read_ue("cpb_size_value_minus1")?,
800 cbr_flag: r.read_bool("cbr_flag")?,
801 })
802 }
803}
804
805#[derive(Clone, Debug, Default, PartialEq, Eq)]
806pub struct HrdParameters {
807 pub bit_rate_scale: u8,
808 pub cpb_size_scale: u8,
809 pub cpb_specs: Vec<CpbSpec>,
810 pub initial_cpb_removal_delay_length_minus1: u8,
811 pub cpb_removal_delay_length_minus1: u8,
812 pub dpb_output_delay_length_minus1: u8,
813 pub time_offset_length: u8,
814}
815impl HrdParameters {
816 fn read<R: BitRead>(
817 r: &mut R,
818 hrd_parameters_present: &mut bool,
819 ) -> Result<Option<HrdParameters>, SpsError> {
820 let hrd_parameters_present_flag = r.read_bool("hrd_parameters_present_flag")?;
821 *hrd_parameters_present |= hrd_parameters_present_flag;
822 Ok(if hrd_parameters_present_flag {
823 let cpb_cnt_minus1 = r.read_ue("cpb_cnt_minus1")?;
824 if cpb_cnt_minus1 > 31 {
825 return Err(SpsError::CpbCountOutOfRange(cpb_cnt_minus1));
826 }
827 let cpb_cnt = cpb_cnt_minus1 + 1;
828 Some(HrdParameters {
829 bit_rate_scale: r.read(4, "bit_rate_scale")?,
830 cpb_size_scale: r.read(4, "cpb_size_scale")?,
831 cpb_specs: Self::read_cpb_specs(r, cpb_cnt)?,
832 initial_cpb_removal_delay_length_minus1: r
833 .read(5, "initial_cpb_removal_delay_length_minus1")?,
834 cpb_removal_delay_length_minus1: r.read(5, "cpb_removal_delay_length_minus1")?,
835 dpb_output_delay_length_minus1: r.read(5, "dpb_output_delay_length_minus1")?,
836 time_offset_length: r.read(5, "time_offset_length")?,
837 })
838 } else {
839 None
840 })
841 }
842 fn read_cpb_specs<R: BitRead>(r: &mut R, cpb_cnt: u32) -> Result<Vec<CpbSpec>, BitReaderError> {
843 let mut cpb_specs = Vec::with_capacity(cpb_cnt as usize);
844 for _ in 0..cpb_cnt {
845 cpb_specs.push(CpbSpec::read(r)?);
846 }
847 Ok(cpb_specs)
848 }
849}
850
851#[derive(Clone, Debug, Default, PartialEq, Eq)]
852pub struct BitstreamRestrictions {
853 pub motion_vectors_over_pic_boundaries_flag: bool,
854 pub max_bytes_per_pic_denom: u32,
855 pub max_bits_per_mb_denom: u32,
856 pub log2_max_mv_length_horizontal: u32,
857 pub log2_max_mv_length_vertical: u32,
858 pub max_num_reorder_frames: u32,
859 pub max_dec_frame_buffering: u32,
860}
861impl BitstreamRestrictions {
862 fn read<R: BitRead>(
863 r: &mut R,
864 sps: &SeqParameterSet,
865 ) -> Result<Option<BitstreamRestrictions>, SpsError> {
866 let bitstream_restriction_flag = r.read_bool("bitstream_restriction_flag")?;
867 Ok(if bitstream_restriction_flag {
868 let motion_vectors_over_pic_boundaries_flag =
869 r.read_bool("motion_vectors_over_pic_boundaries_flag")?;
870 let max_bytes_per_pic_denom = r.read_ue("max_bytes_per_pic_denom")?;
871 if max_bytes_per_pic_denom > 16 {
872 return Err(SpsError::FieldValueTooLarge {
873 name: "max_bytes_per_pic_denom",
874 value: max_bytes_per_pic_denom,
875 });
876 }
877 let max_bits_per_mb_denom = r.read_ue("max_bits_per_mb_denom")?;
878 if max_bits_per_mb_denom > 16 {
879 return Err(SpsError::FieldValueTooLarge {
880 name: "max_bits_per_mb_denom",
881 value: max_bits_per_mb_denom,
882 });
883 }
884 let log2_max_mv_length_horizontal = r.read_ue("log2_max_mv_length_horizontal")?;
889 if log2_max_mv_length_horizontal > 16 {
890 return Err(SpsError::FieldValueTooLarge {
891 name: "log2_max_mv_length_horizontal",
892 value: log2_max_mv_length_horizontal,
893 });
894 }
895 let log2_max_mv_length_vertical = r.read_ue("log2_max_mv_length_vertical")?;
896 if log2_max_mv_length_vertical > 16 {
897 return Err(SpsError::FieldValueTooLarge {
898 name: "log2_max_mv_length_vertical",
899 value: log2_max_mv_length_vertical,
900 });
901 }
902 let max_num_reorder_frames = r.read_ue("max_num_reorder_frames")?;
903 let max_dec_frame_buffering = r.read_ue("max_dec_frame_buffering")?;
904 if max_num_reorder_frames > max_dec_frame_buffering {
905 return Err(SpsError::FieldValueTooLarge {
906 name: "max_num_reorder_frames",
907 value: max_num_reorder_frames,
908 });
909 }
910 if max_dec_frame_buffering < sps.max_num_ref_frames {
913 return Err(SpsError::FieldValueTooSmall {
914 name: "max_dec_frame_buffering",
915 value: max_dec_frame_buffering,
916 });
917 }
918 Some(BitstreamRestrictions {
926 motion_vectors_over_pic_boundaries_flag,
927 max_bytes_per_pic_denom,
928 max_bits_per_mb_denom,
929 log2_max_mv_length_horizontal,
930 log2_max_mv_length_vertical,
931 max_num_reorder_frames,
932 max_dec_frame_buffering,
933 })
934 } else {
935 None
936 })
937 }
938}
939
940#[derive(Clone, Debug, Default, PartialEq, Eq)]
990pub struct VuiParameters {
991 pub aspect_ratio_info: Option<AspectRatioInfo>,
992 pub overscan_appropriate: OverscanAppropriate,
993 pub video_signal_type: Option<VideoSignalType>,
994 pub chroma_loc_info: Option<ChromaLocInfo>,
995 pub timing_info: Option<TimingInfo>,
996 pub nal_hrd_parameters: Option<HrdParameters>,
997 pub vcl_hrd_parameters: Option<HrdParameters>,
998 pub low_delay_hrd_flag: Option<bool>,
999 pub pic_struct_present_flag: bool,
1000 pub bitstream_restrictions: Option<BitstreamRestrictions>,
1001}
1002impl VuiParameters {
1003 fn read<R: BitRead>(
1004 r: &mut R,
1005 sps: &SeqParameterSet,
1006 ) -> Result<Option<VuiParameters>, SpsError> {
1007 let vui_parameters_present_flag = r.read_bool("vui_parameters_present_flag")?;
1008 Ok(if vui_parameters_present_flag {
1009 let mut hrd_parameters_present = false;
1010 Some(VuiParameters {
1011 aspect_ratio_info: AspectRatioInfo::read(r)?,
1012 overscan_appropriate: OverscanAppropriate::read(r)?,
1013 video_signal_type: VideoSignalType::read(r)?,
1014 chroma_loc_info: ChromaLocInfo::read(r)?,
1015 timing_info: TimingInfo::read(r)?,
1016 nal_hrd_parameters: HrdParameters::read(r, &mut hrd_parameters_present)?,
1017 vcl_hrd_parameters: HrdParameters::read(r, &mut hrd_parameters_present)?,
1018 low_delay_hrd_flag: if hrd_parameters_present {
1019 Some(r.read_bool("low_delay_hrd_flag")?)
1020 } else {
1021 None
1022 },
1023 pic_struct_present_flag: r.read_bool("pic_struct_present_flag")?,
1024 bitstream_restrictions: BitstreamRestrictions::read(r, sps)?,
1025 })
1026 } else {
1027 None
1028 })
1029 }
1030}
1031
1032#[derive(Clone, Debug, PartialEq, Eq)]
1033pub struct SeqParameterSet {
1034 pub profile_idc: ProfileIdc,
1035 pub constraint_flags: ConstraintFlags,
1036 pub level_idc: u8,
1037 pub seq_parameter_set_id: SeqParamSetId,
1038 pub chroma_info: ChromaInfo,
1039 pub log2_max_frame_num_minus4: u8,
1040 pub pic_order_cnt: PicOrderCntType,
1041 pub max_num_ref_frames: u32,
1042 pub gaps_in_frame_num_value_allowed_flag: bool,
1043 pub pic_width_in_mbs_minus1: u32,
1044 pub pic_height_in_map_units_minus1: u32,
1045 pub frame_mbs_flags: FrameMbsFlags,
1046 pub direct_8x8_inference_flag: bool,
1047 pub frame_cropping: Option<FrameCropping>,
1048 pub vui_parameters: Option<VuiParameters>,
1049}
1050impl SeqParameterSet {
1051 pub fn from_bits<R: BitRead>(mut r: R) -> Result<SeqParameterSet, SpsError> {
1052 let profile_idc = r.read::<u8>(8, "profile_idc")?.into();
1053 let constraint_flags = r.read::<u8>(8, "constraint_flags")?.into();
1054 let level_idc = r.read::<u8>(8, "level_idc")?;
1055 let mut sps = SeqParameterSet {
1056 profile_idc,
1057 constraint_flags,
1058 level_idc,
1059 seq_parameter_set_id: SeqParamSetId::from_u32(r.read_ue("seq_parameter_set_id")?)
1060 .map_err(SpsError::BadSeqParamSetId)?,
1061 chroma_info: ChromaInfo::read(&mut r, profile_idc)?,
1062 log2_max_frame_num_minus4: Self::read_log2_max_frame_num_minus4(&mut r)?,
1063 pic_order_cnt: PicOrderCntType::read(&mut r).map_err(SpsError::PicOrderCnt)?,
1064 max_num_ref_frames: r.read_ue("max_num_ref_frames")?,
1065 gaps_in_frame_num_value_allowed_flag: r
1066 .read_bool("gaps_in_frame_num_value_allowed_flag")?,
1067 pic_width_in_mbs_minus1: r.read_ue("pic_width_in_mbs_minus1")?,
1068 pic_height_in_map_units_minus1: r.read_ue("pic_height_in_map_units_minus1")?,
1069 frame_mbs_flags: FrameMbsFlags::read(&mut r)?,
1070 direct_8x8_inference_flag: r.read_bool("direct_8x8_inference_flag")?,
1071 frame_cropping: FrameCropping::read(&mut r)?,
1072 vui_parameters: None,
1076 };
1077 let vui_parameters = VuiParameters::read(&mut r, &sps)?;
1078 sps.vui_parameters = vui_parameters;
1079 r.finish_rbsp()?;
1080 Ok(sps)
1081 }
1082
1083 pub fn id(&self) -> SeqParamSetId {
1084 self.seq_parameter_set_id
1085 }
1086
1087 fn read_log2_max_frame_num_minus4<R: BitRead>(r: &mut R) -> Result<u8, SpsError> {
1088 let val = r.read_ue("log2_max_frame_num_minus4")?;
1089 if val > 12 {
1090 Err(SpsError::Log2MaxFrameNumMinus4OutOfRange(val))
1091 } else {
1092 Ok(val as u8)
1093 }
1094 }
1095
1096 pub fn profile(&self) -> Profile {
1097 Profile::from_profile_idc(self.profile_idc)
1098 }
1099
1100 pub fn level(&self) -> Level {
1101 Level::from_constraint_flags_and_level_idc(self.constraint_flags, self.level_idc)
1102 }
1103 pub fn log2_max_frame_num(&self) -> u8 {
1105 self.log2_max_frame_num_minus4 + 4
1106 }
1107
1108 pub fn pixel_dimensions(&self) -> Result<(u32, u32), SpsError> {
1111 let width = self
1112 .pic_width_in_mbs_minus1
1113 .checked_add(1)
1114 .and_then(|w| w.checked_mul(16))
1115 .ok_or_else(|| SpsError::FieldValueTooLarge {
1116 name: "pic_width_in_mbs_minus1",
1117 value: self.pic_width_in_mbs_minus1,
1118 })?;
1119 let mul = match self.frame_mbs_flags {
1120 FrameMbsFlags::Fields { .. } => 2,
1121 FrameMbsFlags::Frames => 1,
1122 };
1123 let vsub = if self.chroma_info.chroma_format == ChromaFormat::YUV420 {
1124 1
1125 } else {
1126 0
1127 };
1128 let hsub = if self.chroma_info.chroma_format == ChromaFormat::YUV420
1129 || self.chroma_info.chroma_format == ChromaFormat::YUV422
1130 {
1131 1
1132 } else {
1133 0
1134 };
1135
1136 let step_x = 1 << hsub;
1137 let step_y = mul << vsub;
1138
1139 let height = (self.pic_height_in_map_units_minus1 + 1)
1140 .checked_mul(mul * 16)
1141 .ok_or_else(|| SpsError::FieldValueTooLarge {
1142 name: "pic_height_in_map_units_minus1",
1143 value: self.pic_height_in_map_units_minus1,
1144 })?;
1145 if let Some(ref crop) = self.frame_cropping {
1146 let left_offset = crop.left_offset.checked_mul(step_x).ok_or_else(|| {
1147 SpsError::FieldValueTooLarge {
1148 name: "left_offset",
1149 value: crop.left_offset,
1150 }
1151 })?;
1152 let right_offset = crop.right_offset.checked_mul(step_x).ok_or_else(|| {
1153 SpsError::FieldValueTooLarge {
1154 name: "right_offset",
1155 value: crop.right_offset,
1156 }
1157 })?;
1158 let top_offset = crop.top_offset.checked_mul(step_y).ok_or_else(|| {
1159 SpsError::FieldValueTooLarge {
1160 name: "top_offset",
1161 value: crop.top_offset,
1162 }
1163 })?;
1164 let bottom_offset = crop.bottom_offset.checked_mul(step_y).ok_or_else(|| {
1165 SpsError::FieldValueTooLarge {
1166 name: "bottom_offset",
1167 value: crop.bottom_offset,
1168 }
1169 })?;
1170 let width = width
1171 .checked_sub(left_offset)
1172 .and_then(|w| w.checked_sub(right_offset));
1173 let height = height
1174 .checked_sub(top_offset)
1175 .and_then(|w| w.checked_sub(bottom_offset));
1176 if let (Some(width), Some(height)) = (width, height) {
1177 Ok((width, height))
1178 } else {
1179 Err(SpsError::CroppingError(crop.clone()))
1180 }
1181 } else {
1182 Ok((width, height))
1183 }
1184 }
1185
1186 pub fn rfc6381(&self) -> rfc6381_codec::Codec {
1187 rfc6381_codec::Codec::avc1(self.profile_idc.0, self.constraint_flags.0, self.level_idc)
1188 }
1189
1190 pub fn fps(&self) -> Option<f64> {
1191 let Some(vui) = &self.vui_parameters else {
1192 return None;
1193 };
1194 let Some(timing_info) = &vui.timing_info else {
1195 return None;
1196 };
1197
1198 Some((timing_info.time_scale as f64) / (2.0 * (timing_info.num_units_in_tick as f64)))
1199 }
1200
1201 pub fn pic_width_in_mbs(&self) -> u32 {
1202 self.pic_width_in_mbs_minus1 + 1
1203 }
1204
1205 pub fn pic_height_in_map_units(&self) -> u32 {
1207 self.pic_height_in_map_units_minus1 + 1
1208 }
1209
1210 pub fn pic_size_in_map_units(&self) -> u32 {
1212 self.pic_width_in_mbs() * self.pic_height_in_map_units()
1213 }
1214}
1215
1216#[cfg(test)]
1496mod test {
1497 use crate::rbsp::{self, decode_nal, BitReader};
1498
1499 use super::*;
1500 use hex_literal::*;
1501 use test_case::test_case;
1502
1503 #[test]
1504 fn test_it() {
1505 let data = hex!(
1506 "64 00 0A AC 72 84 44 26 84 00 00
1507 00 04 00 00 00 CA 3C 48 96 11 80"
1508 );
1509 let sps = SeqParameterSet::from_bits(rbsp::BitReader::new(&data[..])).unwrap();
1510 assert!(!format!("{:?}", sps).is_empty());
1511 assert_eq!(100, sps.profile_idc.0);
1512 assert_eq!(0, sps.constraint_flags.reserved_zero_two_bits());
1513 assert_eq!((64, 64), sps.pixel_dimensions().unwrap());
1514 assert!(!sps.rfc6381().to_string().is_empty())
1515 }
1516
1517 #[test]
1518 fn test_dahua() {
1519 let data = hex!(
1521 "64 00 16 AC 1B 1A 80 B0 3D FF FF
1522 00 28 00 21 6E 0C 0C 0C 80 00 01
1523 F4 00 00 27 10 74 30 07 D0 00 07
1524 A1 25 DE 5C 68 60 0F A0 00 0F 42
1525 4B BC B8 50"
1526 );
1527 let sps = SeqParameterSet::from_bits(rbsp::BitReader::new(&data[..])).unwrap();
1528 println!("sps: {:#?}", sps);
1529 assert_eq!(
1530 sps.vui_parameters.unwrap().aspect_ratio_info.unwrap().get(),
1531 Some((40, 33))
1532 );
1533 }
1534
1535 #[test]
1536 fn crop_removes_all_pixels() {
1537 let sps = SeqParameterSet {
1538 profile_idc: ProfileIdc(0),
1539 constraint_flags: ConstraintFlags(0),
1540 level_idc: 0,
1541 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1542 chroma_info: ChromaInfo {
1543 chroma_format: ChromaFormat::Monochrome,
1544 separate_colour_plane_flag: false,
1545 bit_depth_luma_minus8: 0,
1546 bit_depth_chroma_minus8: 0,
1547 qpprime_y_zero_transform_bypass_flag: false,
1548 scaling_matrix: Default::default(),
1549 },
1550 log2_max_frame_num_minus4: 0,
1551 pic_order_cnt: PicOrderCntType::TypeTwo,
1552 max_num_ref_frames: 0,
1553 frame_cropping: Some(FrameCropping {
1554 bottom_offset: 20,
1555 left_offset: 20,
1556 right_offset: 20,
1557 top_offset: 20,
1558 }),
1559 pic_width_in_mbs_minus1: 1,
1560 pic_height_in_map_units_minus1: 1,
1561 frame_mbs_flags: FrameMbsFlags::Frames,
1562 gaps_in_frame_num_value_allowed_flag: false,
1563 direct_8x8_inference_flag: false,
1564 vui_parameters: None,
1565 };
1566 let dim = sps.pixel_dimensions();
1568 assert!(matches!(dim, Err(SpsError::CroppingError(_))));
1569 }
1570
1571 #[test_case(
1572 vec![
1573 0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
1574 0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
1575 0x00, 0x03, 0x00, 0x3d, 0x08,
1576 ],
1577 SeqParameterSet{
1578 profile_idc: ProfileIdc::from(100),
1579 constraint_flags: ConstraintFlags::from(0),
1580 level_idc: 12,
1581 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1582 chroma_info: ChromaInfo{
1583 chroma_format: ChromaFormat::YUV420,
1584 ..ChromaInfo::default()
1585 },
1586 log2_max_frame_num_minus4: 6,
1587 pic_order_cnt: PicOrderCntType::TypeTwo,
1588 max_num_ref_frames: 1,
1589 gaps_in_frame_num_value_allowed_flag: true,
1590 pic_width_in_mbs_minus1: 21,
1591 pic_height_in_map_units_minus1: 17,
1592 frame_mbs_flags: FrameMbsFlags::Frames,
1593 direct_8x8_inference_flag: true,
1594 frame_cropping: None,
1595 vui_parameters: Some(VuiParameters{
1596 timing_info: Some(TimingInfo{
1597 num_units_in_tick: 1,
1598 time_scale: 30,
1599 fixed_frame_rate_flag: true,
1600 }),
1601 ..VuiParameters::default()
1602 }),
1603 },
1604 352,
1605 288,
1606 15.0; "352x288"
1607 )]
1608 #[test_case(
1609 vec![
1610 0x67, 0x64, 0x00, 0x1f, 0xac, 0xd9, 0x40, 0x50,
1611 0x05, 0xbb, 0x01, 0x6c, 0x80, 0x00, 0x00, 0x03,
1612 0x00, 0x80, 0x00, 0x00, 0x1e, 0x07, 0x8c, 0x18,
1613 0xcb,
1614 ],
1615 SeqParameterSet{
1616 profile_idc: ProfileIdc::from(100),
1617 constraint_flags: ConstraintFlags::from(0),
1618 level_idc: 31,
1619 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1620 chroma_info: ChromaInfo{
1621 chroma_format: ChromaFormat::YUV420,
1622 ..ChromaInfo::default()
1623 },
1624 log2_max_frame_num_minus4: 0,
1625 pic_order_cnt: PicOrderCntType::TypeZero {
1626 log2_max_pic_order_cnt_lsb_minus4: 2
1627 },
1628 max_num_ref_frames: 4,
1629 gaps_in_frame_num_value_allowed_flag: false,
1630 pic_width_in_mbs_minus1: 79,
1631 pic_height_in_map_units_minus1: 44,
1632 frame_mbs_flags: FrameMbsFlags::Frames,
1633 direct_8x8_inference_flag: true,
1634 frame_cropping: None,
1635 vui_parameters: Some(VuiParameters{
1636 aspect_ratio_info: Some(AspectRatioInfo::Ratio1_1),
1637 video_signal_type: Some(VideoSignalType{
1638 video_format: VideoFormat::Unspecified,
1639 video_full_range_flag: true,
1640 colour_description: None,
1641 }),
1642 timing_info: Some(TimingInfo{
1643 num_units_in_tick: 1,
1644 time_scale: 60,
1645 fixed_frame_rate_flag: false,
1646 }),
1647 bitstream_restrictions: Some(BitstreamRestrictions{
1648 motion_vectors_over_pic_boundaries_flag: true,
1649 log2_max_mv_length_horizontal: 11,
1650 log2_max_mv_length_vertical: 11,
1651 max_num_reorder_frames: 2,
1652 max_dec_frame_buffering: 4,
1653 ..BitstreamRestrictions::default()
1654 }),
1655 ..VuiParameters::default()
1656 }),
1657 },
1658 1280,
1659 720,
1660 30.0; "1280x720"
1661 )]
1662 #[test_case(
1663 vec![
1664 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02,
1665 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04,
1666 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, 0x20,
1667 ],
1668 SeqParameterSet{
1669 profile_idc: ProfileIdc::from(66),
1670 constraint_flags: ConstraintFlags::from(0b11000000),
1671 level_idc: 40,
1672 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1673 chroma_info: ChromaInfo{
1674 chroma_format: ChromaFormat::YUV420,
1675 ..ChromaInfo::default()
1676 },
1677 log2_max_frame_num_minus4: 0,
1678 pic_order_cnt: PicOrderCntType::TypeTwo,
1679 max_num_ref_frames: 3,
1680 gaps_in_frame_num_value_allowed_flag: false,
1681 pic_width_in_mbs_minus1: 119,
1682 pic_height_in_map_units_minus1: 67,
1683 frame_mbs_flags: FrameMbsFlags::Frames,
1684 direct_8x8_inference_flag: true,
1685 frame_cropping: Some(FrameCropping{
1686 bottom_offset: 4,
1687 ..FrameCropping::default()
1688 }),
1689 vui_parameters: Some(VuiParameters{
1690 timing_info: Some(TimingInfo{
1691 num_units_in_tick: 1,
1692 time_scale: 60,
1693 fixed_frame_rate_flag: false,
1694 }),
1695 bitstream_restrictions: Some(BitstreamRestrictions{
1696 motion_vectors_over_pic_boundaries_flag: true,
1697 log2_max_mv_length_horizontal: 11,
1698 log2_max_mv_length_vertical: 11,
1699 max_dec_frame_buffering: 3,
1700 ..BitstreamRestrictions::default()
1701 }),
1702 ..VuiParameters::default()
1703 }),
1704 },
1705 1920,
1706 1080,
1707 30.0; "1920x1080 baseline"
1708 )]
1709 #[test_case(
1710 vec![
1711 0x67, 0x64, 0x00, 0x28, 0xac, 0xd9, 0x40, 0x78,
1712 0x02, 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00,
1713 0x04, 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60,
1714 0xc6, 0x58,
1715 ],
1716 SeqParameterSet{
1717 profile_idc: ProfileIdc::from(100),
1718 constraint_flags: ConstraintFlags::from(0),
1719 level_idc: 40,
1720 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1721 chroma_info: ChromaInfo{
1722 chroma_format: ChromaFormat::YUV420,
1723 ..ChromaInfo::default()
1724 },
1725 log2_max_frame_num_minus4: 0,
1726 pic_order_cnt: PicOrderCntType::TypeZero {
1727 log2_max_pic_order_cnt_lsb_minus4: 2
1728 },
1729 max_num_ref_frames: 4,
1730 gaps_in_frame_num_value_allowed_flag: false,
1731 pic_width_in_mbs_minus1: 119,
1732 pic_height_in_map_units_minus1: 67,
1733 frame_mbs_flags: FrameMbsFlags::Frames,
1734 direct_8x8_inference_flag: true,
1735 frame_cropping: Some(FrameCropping{
1736 bottom_offset: 4,
1737 ..FrameCropping::default()
1738 }),
1739 vui_parameters: Some(VuiParameters{
1740 timing_info: Some(TimingInfo{
1741 num_units_in_tick: 1,
1742 time_scale: 60,
1743 fixed_frame_rate_flag: false,
1744 }),
1745 bitstream_restrictions: Some(BitstreamRestrictions{
1746 motion_vectors_over_pic_boundaries_flag: true,
1747 log2_max_mv_length_horizontal: 11,
1748 log2_max_mv_length_vertical: 11,
1749 max_num_reorder_frames: 2,
1750 max_dec_frame_buffering: 4,
1751 ..BitstreamRestrictions::default()
1752 }),
1753 ..VuiParameters::default()
1754 }),
1755 },
1756 1920,
1757 1080,
1758 30.0; "1920x1080 nvidia"
1759 )]
1760 #[test_case(
1825 vec![103, 100, 0, 32, 172, 23, 42, 1, 64, 30, 104, 64, 0, 1, 194, 0, 0, 87, 228, 33],
1826 SeqParameterSet{
1827 profile_idc: ProfileIdc::from(100),
1828 constraint_flags: ConstraintFlags::from(0),
1829 level_idc: 32,
1830 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1831 chroma_info: ChromaInfo{
1832 chroma_format: ChromaFormat::YUV420,
1833 ..ChromaInfo::default()
1834 },
1835 log2_max_frame_num_minus4: 10,
1836 pic_order_cnt: PicOrderCntType::TypeZero {
1837 log2_max_pic_order_cnt_lsb_minus4: 4
1838 },
1839 max_num_ref_frames: 1,
1840 gaps_in_frame_num_value_allowed_flag: false,
1841 pic_width_in_mbs_minus1: 79,
1842 pic_height_in_map_units_minus1: 59,
1843 frame_mbs_flags: FrameMbsFlags::Frames,
1844 direct_8x8_inference_flag: true,
1845 frame_cropping: None,
1846 vui_parameters: Some(VuiParameters{
1847 timing_info: Some(TimingInfo{
1848 num_units_in_tick: 1800,
1849 time_scale: 90000,
1850 fixed_frame_rate_flag: true,
1851 }),
1852 ..VuiParameters::default()
1853 }),
1854 },
1855 1280,
1856 960,
1857 25.0; "hikvision"
1858 )]
1859 #[test_case(
1860 vec![
1861 103, 100, 0, 50, 173, 132, 99, 210, 73, 36, 146, 73, 37, 8, 127,
1862 255, 132, 63, 255, 194, 31, 255, 225, 15, 255, 225, 218,
1863 128, 160, 2, 214, 155, 128, 128, 128, 160, 0, 0, 3, 0, 32, 0, 0, 5, 16, 128
1864 ],
1865 SeqParameterSet{
1866 profile_idc: ProfileIdc::from(100),
1867 constraint_flags: ConstraintFlags::from(0),
1868 level_idc: 50,
1869 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1870 chroma_info: ChromaInfo{
1871 chroma_format: ChromaFormat::YUV420,
1872 scaling_matrix: Some(SeqScalingMatrix {
1873 scaling_list4x4: vec![
1874 ScalingList::UseDefault,
1875 ScalingList::List([
1876 NonZeroU8::new(1).unwrap(),
1877 NonZeroU8::new(2).unwrap(),
1878 NonZeroU8::new(3).unwrap(),
1879 NonZeroU8::new(4).unwrap(),
1880 NonZeroU8::new(5).unwrap(),
1881 NonZeroU8::new(6).unwrap(),
1882 NonZeroU8::new(7).unwrap(),
1883 NonZeroU8::new(8).unwrap(),
1884 NonZeroU8::new(9).unwrap(),
1885 NonZeroU8::new(10).unwrap(),
1886 NonZeroU8::new(11).unwrap(),
1887 NonZeroU8::new(12).unwrap(),
1888 NonZeroU8::new(13).unwrap(),
1889 NonZeroU8::new(14).unwrap(),
1890 NonZeroU8::new(15).unwrap(),
1891 NonZeroU8::new(16).unwrap(),
1892 ]),
1893 ScalingList::List([NonZeroU8::new(16).unwrap(); 16]),
1894 ScalingList::List([NonZeroU8::new(16).unwrap(); 16]),
1895 ScalingList::List([NonZeroU8::new(16).unwrap(); 16]),
1896 ScalingList::List([NonZeroU8::new(16).unwrap(); 16]),
1897 ],
1898 scaling_list8x8: vec![
1899 ScalingList::NotPresent,
1900 ScalingList::NotPresent,
1901 ]
1902 }),
1903 ..ChromaInfo::default()
1904 },
1905 log2_max_frame_num_minus4: 6,
1936 pic_order_cnt: PicOrderCntType::TypeTwo,
1937 max_num_ref_frames: 1,
1938 gaps_in_frame_num_value_allowed_flag: true,
1939 pic_width_in_mbs_minus1: 159,
1940 pic_height_in_map_units_minus1: 89,
1941 frame_mbs_flags: FrameMbsFlags::Frames,
1942 direct_8x8_inference_flag: true,
1943 frame_cropping: None,
1944 vui_parameters: Some(VuiParameters{
1945 video_signal_type: Some(VideoSignalType{
1946 video_format: VideoFormat::Unspecified,
1947 video_full_range_flag: true,
1948 colour_description: Some(ColourDescription{
1949 colour_primaries: 1,
1950 transfer_characteristics: 1,
1951 matrix_coefficients: 1,
1952 }),
1953 }),
1954 timing_info: Some(TimingInfo{
1955 num_units_in_tick: 1,
1956 time_scale: 40,
1957 fixed_frame_rate_flag: true,
1958 }),
1959 ..VuiParameters::default()
1960 }),
1961 },
1962 2560,
1963 1440,
1964 20.0; "scaling matrix"
1965 )]
1966 #[test_case(
1967 vec![
1968 103, 100, 0, 42, 172, 44, 172, 7,
1969 128, 34, 126, 92, 5, 168, 8, 8,
1970 10, 0, 0, 7, 208, 0, 3, 169,
1971 129, 192, 0, 0, 76, 75, 0, 0,
1972 38, 37, 173, 222, 92, 20,
1973 ],
1974 SeqParameterSet{
1975 profile_idc: ProfileIdc::from(100),
1976 constraint_flags: ConstraintFlags::from(0),
1977 level_idc: 42,
1978 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1979 chroma_info: ChromaInfo{
1980 chroma_format: ChromaFormat::YUV420,
1981 ..ChromaInfo::default()
1982 },
1983 log2_max_frame_num_minus4: 4,
1984 pic_order_cnt: PicOrderCntType::TypeZero {
1985 log2_max_pic_order_cnt_lsb_minus4: 4
1986 },
1987 max_num_ref_frames: 2,
1988 gaps_in_frame_num_value_allowed_flag: false,
1989 pic_width_in_mbs_minus1: 119,
1990 pic_height_in_map_units_minus1: 67,
1991 frame_mbs_flags: FrameMbsFlags::Frames,
1992 direct_8x8_inference_flag: true,
1993 frame_cropping: Some(FrameCropping{
1994 bottom_offset: 4,
1995 ..FrameCropping::default()
1996 }),
1997 vui_parameters: Some(VuiParameters{
1998 aspect_ratio_info: Some(AspectRatioInfo::Ratio1_1),
1999 video_signal_type: Some(VideoSignalType{
2000 video_format: VideoFormat::Unspecified,
2001 video_full_range_flag: false,
2002 colour_description: Some(ColourDescription{
2003 colour_primaries: 1,
2004 transfer_characteristics: 1,
2005 matrix_coefficients: 1,
2006 }),
2007 }),
2008 timing_info: Some(TimingInfo{
2009 num_units_in_tick: 1000,
2010 time_scale: 120000,
2011 fixed_frame_rate_flag: true,
2012 }),
2013 nal_hrd_parameters: Some(HrdParameters{
2014 cpb_specs: vec![CpbSpec{
2015 bit_rate_value_minus1: 39061,
2016 cpb_size_value_minus1: 156249,
2017 cbr_flag: true,
2018 }],
2019 initial_cpb_removal_delay_length_minus1: 23,
2020 cpb_removal_delay_length_minus1: 15,
2021 dpb_output_delay_length_minus1: 5,
2022 time_offset_length: 24,
2023 ..HrdParameters::default()
2024 }),
2025 low_delay_hrd_flag: Some(false),
2026 pic_struct_present_flag: true,
2027 ..VuiParameters::default()
2028 }),
2029 },
2030 1920,
2031 1080,
2032 60.0; "1920x1080 nvenc hrd"
2033 )]
2034 #[test_case(
2035 vec![
2036 103, 77, 0, 41, 154, 100, 3, 192,
2037 17, 63, 46, 2, 220, 4, 4, 5,
2038 0, 0, 3, 3, 232, 0, 0, 195,
2039 80, 232, 96, 0, 186, 180, 0, 2,
2040 234, 196, 187, 203, 141, 12, 0, 23,
2041 86, 128, 0, 93, 88, 151, 121, 112,
2042 160,
2043 ],
2044 SeqParameterSet{
2045 profile_idc: ProfileIdc::from(77),
2046 constraint_flags: ConstraintFlags::from(0),
2047 level_idc: 41,
2048 seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
2049 chroma_info: ChromaInfo{
2050 chroma_format: ChromaFormat::YUV420,
2051 ..ChromaInfo::default()
2052 },
2053 log2_max_frame_num_minus4: 5,
2054 pic_order_cnt: PicOrderCntType::TypeZero {
2055 log2_max_pic_order_cnt_lsb_minus4: 5
2056 },
2057 max_num_ref_frames: 1,
2058 gaps_in_frame_num_value_allowed_flag: false,
2059 pic_width_in_mbs_minus1: 119,
2060 pic_height_in_map_units_minus1: 67,
2061 frame_mbs_flags: FrameMbsFlags::Frames,
2062 direct_8x8_inference_flag: true,
2063 frame_cropping: Some(FrameCropping{
2064 bottom_offset: 4,
2065 ..FrameCropping::default()
2066 }),
2067 vui_parameters: Some(VuiParameters{
2068 aspect_ratio_info: Some(AspectRatioInfo::Ratio1_1),
2069 video_signal_type: Some(VideoSignalType{
2070 video_format: VideoFormat::Unspecified,
2071 video_full_range_flag: true,
2072 colour_description: Some(ColourDescription{
2073 colour_primaries: 1,
2074 transfer_characteristics: 1,
2075 matrix_coefficients: 1,
2076 }),
2077 }),
2078 timing_info: Some(TimingInfo{
2079 num_units_in_tick: 1000,
2080 time_scale: 50000,
2081 fixed_frame_rate_flag: true,
2082 }),
2083 nal_hrd_parameters: Some(HrdParameters{
2084 bit_rate_scale: 4,
2085 cpb_size_scale: 3,
2086 cpb_specs: vec![CpbSpec{
2087 bit_rate_value_minus1: 11948,
2088 cpb_size_value_minus1: 95585,
2089 cbr_flag: false,
2090 }],
2091 initial_cpb_removal_delay_length_minus1: 23,
2092 cpb_removal_delay_length_minus1: 15,
2093 dpb_output_delay_length_minus1: 5,
2094 time_offset_length: 24,
2095 }),
2096 vcl_hrd_parameters: Some(HrdParameters{
2097 bit_rate_scale: 4,
2098 cpb_size_scale: 3,
2099 cpb_specs: vec![CpbSpec{
2100 bit_rate_value_minus1: 11948,
2101 cpb_size_value_minus1: 95585,
2102 cbr_flag: false,
2103 }],
2104 initial_cpb_removal_delay_length_minus1: 23,
2105 cpb_removal_delay_length_minus1: 15,
2106 dpb_output_delay_length_minus1: 5,
2107 time_offset_length: 24,
2108 ..HrdParameters::default()
2109 }),
2110 low_delay_hrd_flag: Some(false),
2111 pic_struct_present_flag: true,
2112 ..VuiParameters::default()
2113 }),
2114 },
2115 1920,
2116 1080,
2117 25.0; "1920x1080 hikvision nal hrd + vcl hrd"
2118 )]
2119 fn test_sps(byts: Vec<u8>, sps: SeqParameterSet, width: u32, height: u32, fps: f64) {
2120 let sps_rbsp = decode_nal(&byts).unwrap();
2121 let sps2 = SeqParameterSet::from_bits(BitReader::new(&*sps_rbsp)).unwrap();
2122
2123 let (width2, height2) = sps2.pixel_dimensions().unwrap();
2124 assert_eq!(sps, sps2);
2125 assert_eq!(width, width2);
2126 assert_eq!(height, height2);
2127 assert_eq!(fps, sps2.fps().unwrap());
2128 }
2129}