h264_reader/nal/
sps.rs

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    /// Signals that bit_depth_luma_minus8 was greater than the max value, 6
30    BitDepthOutOfRange(u32),
31    RbspReaderError(BitReaderError),
32    PicOrderCnt(PicOrderCntError),
33    ScalingMatrix(ScalingMatrixError),
34    /// log2_max_frame_num_minus4 must be between 0 and 12
35    Log2MaxFrameNumMinus4OutOfRange(u32),
36    BadSeqParamSetId(SeqParamSetIdError),
37    UnknownSeqParamSetId(SeqParamSetId),
38    /// A field in the bitstream had a value too large for a subsequent calculation
39    FieldValueTooLarge {
40        name: &'static str,
41        value: u32,
42    },
43    /// A field in the bitstream had a value that is too small
44    FieldValueTooSmall {
45        name: &'static str,
46        value: u32,
47    },
48    /// The frame-cropping values are too large vs. the coded picture size,
49    CroppingError(FrameCropping),
50    /// The `cpb_cnt_minus1` field must be between 0 and 31 inclusive.
51    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        // TODO: accept constraint_flags too, as Level does?
82        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// _Profile Indication_ value
277#[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
305/// returns 'use_default_scaling_matrix_flag'
306fn 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    /// The `delta_scale` field must be between -128 and 127 inclusive.
354    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    /// log2_max_pic_order_cnt_lsb_minus4 must be between 0 and 12
453    Log2MaxPicOrderCntLsbMinus4OutOfRange(u32),
454    /// num_ref_frames_in_pic_order_cnt_cycle must be between 0 and 255
455    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    /// Returns the aspect ratio as `(width, height)`, if specified.
623    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                // ISO/IEC 14496-10 section E.2.1: "When ... sar_width is equal to 0 or sar_height
645                // is equal to 0, the sample aspect ratio shall be considered unspecified by this
646                // Recommendation | International Standard."
647                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            // more recent versions of the spec say log2_max_mv_length_horizontal and
885            // log2_max_mv_length_vertical - "shall be in the range of 0 to 15, inclusive."
886            // However, older versions of the spec say 0 to 16, and real bitstreams present 16, so
887            // we apply the more-permissive check to avoid rejecting real files.
888            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            // "The value of max_dec_frame_buffering shall be greater than or equal to
911            // max_num_ref_frames."
912            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            /*let max = max_val_for_max_dec_frame_buffering(sps);
919            if max_dec_frame_buffering > max {
920                return Err(SpsError::FieldValueTooLarge {
921                    name: "max_dec_frame_buffering",
922                    value: max_dec_frame_buffering,
923                });
924            }*/
925            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// calculates the maximum allowed value for the max_dec_frame_buffering field
941/*fn max_val_for_max_dec_frame_buffering(sps: &SeqParameterSet) -> u32 {
942    let level = Level::from_constraint_flags_and_level_idc(
943        ConstraintFlags::from(sps.constraint_flags),
944        sps.level_idc,
945    );
946    let profile = Profile::from_profile_idc(sps.profile_idc);
947    let pic_width_in_mbs = sps.pic_width_in_mbs_minus1 + 1;
948    let pic_height_in_map_units = sps.pic_height_in_map_units_minus1 + 1;
949    let frame_height_in_mbs = if let FrameMbsFlags::Frames = sps.frame_mbs_flags {
950        1
951    } else {
952        2
953    } * pic_height_in_map_units;
954    let max_dpb_mbs = LEVEL_LIMITS.get(&level).unwrap().max_dpb_mbs;
955    match profile {
956        // "A.3.1 - Level limits common to the Baseline, Constrained Baseline, Main, and Extended
957        // profiles"
958        Profile::Baseline | Profile::Main | Profile::Extended => {
959            std::cmp::min(max_dpb_mbs / (pic_width_in_mbs * frame_height_in_mbs), 16)
960        }
961        // "A.3.2 - Level limits common to the High, Progressive High, Constrained High, High 10,
962        // Progressive High 10, High 4:2:2, High 4:4:4 Predictive, High 10 Intra, High 4:2:2 Intra,
963        // High 4:4:4 Intra, and CAVLC 4:4:4 Intra profiles"
964        Profile::High | Profile::High422 | Profile::High10 | Profile::High444 => {
965            std::cmp::min(max_dpb_mbs / (pic_width_in_mbs * frame_height_in_mbs), 16)
966        }
967
968        // "G.10.2.1 - Level limits common to Scalable Baseline, Scalable Constrained Baseline,
969        // Scalable High, Scalable Constrained High, and Scalable High Intra profiles"
970        Profile::ScalableBase | Profile::ScalableHigh => {
971            // Min( MaxDpbMbs / ( PicWidthInMbs * FrameHeightInMbs ), 16 )
972            std::cmp::min(max_dpb_mbs / (pic_width_in_mbs * frame_height_in_mbs), 16)
973        }
974
975        // "H.10.2.1 - Level limits common to Multiview High, Stereo High, and MFC High profiles"
976        //Profile::MultiviewHigh | Profile::StereoHigh | Profile::MFCDepthHigh => {
977        //    // Min( mvcScaleFactor * MaxDpbMbs / ( PicWidthInMbs * FrameHeightInMbs ), Max( 1, Ceil( log2( NumViews ) ) ) * 16 )
978        //}
979
980        // "I.10.2.1 - Level limits common to Multiview Depth High profiles"
981        //Profile::MultiviewDepthHigh | Profile::EnhancedMultiviewDepthHigh => {
982        //    let mvcd_scale_factor = 2.5;
983        //    std::cmp::min( mvcd_scale_factor * max_dpb_mbs / ( TotalPicSizeInMbs / NumViews ) ), std::cmp::max(1, Ceil( log2( NumViews ) ) ) * 16 )
984        //}
985        _ => unimplemented!("{:?}", profile),
986    }
987}*/
988
989#[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            // read the basic SPS data without reading VUI parameters yet, since checks of the
1073            // bitstream restriction fields within the VUI parameters will need access to the
1074            // initial SPS data
1075            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    /// returned value will be in the range 4 to 16 inclusive
1104    pub fn log2_max_frame_num(&self) -> u8 {
1105        self.log2_max_frame_num_minus4 + 4
1106    }
1107
1108    /// Helper to calculate the pixel-dimensions of the video image specified by this SPS, taking
1109    /// into account sample-format, interlacing and cropping.
1110    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    /// From the spec: `PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1`
1206    pub fn pic_height_in_map_units(&self) -> u32 {
1207        self.pic_height_in_map_units_minus1 + 1
1208    }
1209
1210    /// From the spec: `PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits`
1211    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/*struct LevelLimit {
1217    max_mbps: u32,
1218    max_fs: u32,
1219    max_dpb_mbs: u32,
1220    max_br: u32,
1221    max_cpb: u32,
1222    max_vmv_r: u32,
1223    min_cr: u8,
1224    max_mvs_per2mb: Option<NonZeroU8>,
1225}
1226
1227lazy_static! {
1228    // "Table A-1 – Level limits" from the spec
1229    static ref LEVEL_LIMITS: std::collections::HashMap<Level, LevelLimit> = {
1230        let mut m = std::collections::HashMap::new();
1231        m.insert(
1232            Level::L1,
1233            LevelLimit {
1234                max_mbps: 1485,
1235                max_fs: 99,
1236                max_dpb_mbs: 396,
1237                max_br: 64,
1238                max_cpb: 175,
1239                max_vmv_r: 64,
1240                min_cr: 2,
1241                max_mvs_per2mb: None,
1242            },
1243        );
1244        m.insert(
1245            Level::L1_b,
1246            LevelLimit {
1247                max_mbps: 1485,
1248                max_fs: 99,
1249                max_dpb_mbs: 396,
1250                max_br: 128,
1251                max_cpb: 350,
1252                max_vmv_r: 64,
1253                min_cr: 2,
1254                max_mvs_per2mb: None,
1255            },
1256        );
1257        m.insert(
1258            Level::L1_1,
1259            LevelLimit {
1260                max_mbps: 3000,
1261                max_fs: 396,
1262                max_dpb_mbs: 900,
1263                max_br: 192,
1264                max_cpb: 500,
1265                max_vmv_r: 128,
1266                min_cr: 2,
1267                max_mvs_per2mb: None,
1268            },
1269        );
1270        m.insert(
1271            Level::L1_2,
1272            LevelLimit {
1273                max_mbps: 6000,
1274                max_fs: 396,
1275                max_dpb_mbs: 2376,
1276                max_br: 384,
1277                max_cpb: 1000,
1278                max_vmv_r: 128,
1279                min_cr: 2,
1280                max_mvs_per2mb: None,
1281            },
1282        );
1283        m.insert(
1284            Level::L1_3,
1285            LevelLimit {
1286                max_mbps: 11880,
1287                max_fs: 396,
1288                max_dpb_mbs: 2376,
1289                max_br: 768,
1290                max_cpb: 2000,
1291                max_vmv_r: 128,
1292                min_cr: 2,
1293                max_mvs_per2mb: None,
1294            },
1295        );
1296        m.insert(
1297            Level::L2,
1298            LevelLimit {
1299                max_mbps: 11880,
1300                max_fs: 396,
1301                max_dpb_mbs: 2376,
1302                max_br: 2000,
1303                max_cpb: 2000,
1304                max_vmv_r: 128,
1305                min_cr: 2,
1306                max_mvs_per2mb: None,
1307            },
1308        );
1309        m.insert(
1310            Level::L2_1,
1311            LevelLimit {
1312                max_mbps: 19800,
1313                max_fs: 792,
1314                max_dpb_mbs: 4752,
1315                max_br: 4000,
1316                max_cpb: 4000,
1317                max_vmv_r: 256,
1318                min_cr: 2,
1319                max_mvs_per2mb: None,
1320            },
1321        );
1322        m.insert(
1323            Level::L2_2,
1324            LevelLimit {
1325                max_mbps: 20250,
1326                max_fs: 1620,
1327                max_dpb_mbs: 8100,
1328                max_br: 4000,
1329                max_cpb: 4000,
1330                max_vmv_r: 256,
1331                min_cr: 2,
1332                max_mvs_per2mb: None,
1333            },
1334        );
1335        m.insert(
1336            Level::L3,
1337            LevelLimit {
1338                max_mbps: 40500,
1339                max_fs: 1620,
1340                max_dpb_mbs: 8100,
1341                max_br: 10000,
1342                max_cpb: 10000,
1343                max_vmv_r: 256,
1344                min_cr: 2,
1345                max_mvs_per2mb: NonZeroU8::new(32),
1346            },
1347        );
1348        m.insert(
1349            Level::L3_1,
1350            LevelLimit {
1351                max_mbps: 108000,
1352                max_fs: 3600,
1353                max_dpb_mbs: 18000,
1354                max_br: 14000,
1355                max_cpb: 14000,
1356                max_vmv_r: 512,
1357                min_cr: 4,
1358                max_mvs_per2mb: NonZeroU8::new(16),
1359            },
1360        );
1361        m.insert(
1362            Level::L3_2,
1363            LevelLimit {
1364                max_mbps: 216000,
1365                max_fs: 5120,
1366                max_dpb_mbs: 20480,
1367                max_br: 20000,
1368                max_cpb: 20000,
1369                max_vmv_r: 512,
1370                min_cr: 4,
1371                max_mvs_per2mb: NonZeroU8::new(16),
1372            },
1373        );
1374        m.insert(
1375            Level::L4,
1376            LevelLimit {
1377                max_mbps: 245760,
1378                max_fs: 8192,
1379                max_dpb_mbs: 32768,
1380                max_br: 20000,
1381                max_cpb: 25000,
1382                max_vmv_r: 512,
1383                min_cr: 4,
1384                max_mvs_per2mb: NonZeroU8::new(16),
1385            },
1386        );
1387        m.insert(
1388            Level::L4_1,
1389            LevelLimit {
1390                max_mbps: 245760,
1391                max_fs: 8192,
1392                max_dpb_mbs: 32768,
1393                max_br: 50000,
1394                max_cpb: 62500,
1395                max_vmv_r: 512,
1396                min_cr: 2,
1397                max_mvs_per2mb: NonZeroU8::new(16),
1398            },
1399        );
1400        m.insert(
1401            Level::L4_2,
1402            LevelLimit {
1403                max_mbps: 522240,
1404                max_fs: 8704,
1405                max_dpb_mbs: 34816,
1406                max_br: 50000,
1407                max_cpb: 62500,
1408                max_vmv_r: 512,
1409                min_cr: 2,
1410                max_mvs_per2mb: NonZeroU8::new(16),
1411            },
1412        );
1413        m.insert(
1414            Level::L5,
1415            LevelLimit {
1416                max_mbps: 589824,
1417                max_fs: 22080,
1418                max_dpb_mbs: 110400,
1419                max_br: 135000,
1420                max_cpb: 135000,
1421                max_vmv_r: 512,
1422                min_cr: 2,
1423                max_mvs_per2mb: NonZeroU8::new(16),
1424            },
1425        );
1426        m.insert(
1427            Level::L5_1,
1428            LevelLimit {
1429                max_mbps: 983040,
1430                max_fs: 36864,
1431                max_dpb_mbs: 184320,
1432                max_br: 240000,
1433                max_cpb: 240000,
1434                max_vmv_r: 512,
1435                min_cr: 2,
1436                max_mvs_per2mb: NonZeroU8::new(16),
1437            },
1438        );
1439        m.insert(
1440            Level::L5_2,
1441            LevelLimit {
1442                max_mbps: 2073600,
1443                max_fs: 36864,
1444                max_dpb_mbs: 184320,
1445                max_br: 240000,
1446                max_cpb: 240000,
1447                max_vmv_r: 512,
1448                min_cr: 2,
1449                max_mvs_per2mb: NonZeroU8::new(16),
1450            },
1451        );
1452        m.insert(
1453            Level::L6,
1454            LevelLimit {
1455                max_mbps: 4177920,
1456                max_fs: 139264,
1457                max_dpb_mbs: 696320,
1458                max_br: 240000,
1459                max_cpb: 240000,
1460                max_vmv_r: 8192,
1461                min_cr: 2,
1462                max_mvs_per2mb: NonZeroU8::new(16),
1463            },
1464        );
1465        m.insert(
1466            Level::L6_1,
1467            LevelLimit {
1468                max_mbps: 8355840,
1469                max_fs: 139264,
1470                max_dpb_mbs: 696320,
1471                max_br: 480000,
1472                max_cpb: 480000,
1473                max_vmv_r: 8192,
1474                min_cr: 2,
1475                max_mvs_per2mb: NonZeroU8::new(16),
1476            },
1477        );
1478        m.insert(
1479            Level::L6_2,
1480            LevelLimit {
1481                max_mbps: 16711680,
1482                max_fs: 139264,
1483                max_dpb_mbs: 696320,
1484                max_br: 800000,
1485                max_cpb: 800000,
1486                max_vmv_r: 8192,
1487                min_cr: 2,
1488                max_mvs_per2mb: NonZeroU8::new(16),
1489            },
1490        );
1491        m
1492    };
1493}*/
1494
1495#[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        // From a Dahua IPC-HDW5231R-Z's sub stream, which is anamorphic.
1520        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        // should return Err, rather than assert due to integer underflow for example,
1567        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    // This fails.
1761
1762    /*#[test_case(
1763        vec![
1764            0x67, 0x64, 0x00, 0x29, 0xac, 0x13, 0x31, 0x40,
1765            0x78, 0x04, 0x47, 0xde, 0x03, 0xea, 0x02, 0x02,
1766            0x03, 0xe0, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00,
1767            0x00, 0x06, 0x52, // 0x80,
1768        ],
1769        SeqParameterSet{
1770            profile_idc: ProfileIdc::from(100),
1771            constraint_flags: ConstraintFlags::from(0),
1772            level_idc: 41,
1773            seq_parameter_set_id: SeqParamSetId::from_u32(0).unwrap(),
1774            chroma_info: ChromaInfo{
1775                chroma_format: ChromaFormat::YUV420,
1776                ..ChromaInfo::default()
1777            },
1778            log2_max_frame_num_minus4: 8,
1779            pic_order_cnt: PicOrderCntType::TypeZero {
1780                log2_max_pic_order_cnt_lsb_minus4: 5
1781            },
1782            max_num_ref_frames: 4,
1783            gaps_in_frame_num_value_allowed_flag: false,
1784            pic_width_in_mbs_minus1: 119,
1785            pic_height_in_map_units_minus1: 33,
1786            frame_mbs_flags: FrameMbsFlags::Fields{
1787                mb_adaptive_frame_field_flag: false,
1788            },
1789            direct_8x8_inference_flag: true,
1790            frame_cropping: Some(FrameCropping{
1791                bottom_offset: 2,
1792                ..FrameCropping::default()
1793            }),
1794            vui_parameters: Some(VuiParameters{
1795                aspect_ratio_info: Some(AspectRatioInfo::Ratio1_1),
1796                overscan_appropriate: OverscanAppropriate::Appropriate,
1797                video_signal_type: Some(VideoSignalType{
1798                    video_format: VideoFormat::Unspecified,
1799                    video_full_range_flag: false,
1800                    colour_description: Some(ColourDescription{
1801                        colour_primaries: 1,
1802                        transfer_characteristics: 1,
1803                        matrix_coefficients: 1,
1804                    }),
1805                }),
1806                chroma_loc_info: Some(ChromaLocInfo{
1807                    chroma_sample_loc_type_top_field: 0,
1808                    chroma_sample_loc_type_bottom_field: 0,
1809                }),
1810                timing_info: Some(TimingInfo{
1811                    num_units_in_tick: 1,
1812                    time_scale: 50,
1813                    fixed_frame_rate_flag: true,
1814                }),
1815                pic_struct_present_flag: true,
1816                ..VuiParameters::default()
1817            }),
1818        },
1819        1920,
1820        1084,
1821        25.0; "1920x1080"
1822    )]
1823    */
1824    #[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            /*seq_scaling_list: Some(SeqScalingList{
1906                scaling_list_4x4: vec![
1907                    vec![
1908                        16, 16, 16, 16, 16, 16, 16, 16,
1909                        16, 16, 16, 16, 16, 16, 16, 16,
1910                    ],
1911                    vec![
1912                        16, 16, 16, 16, 16, 16, 16, 16,
1913                        16, 16, 16, 16, 16, 16, 16, 16,
1914                    ],
1915                    vec![
1916                        16, 16, 16, 16, 16, 16, 16, 16,
1917                        16, 16, 16, 16, 16, 16, 16, 16,
1918                    ],
1919                    vec![
1920                        16, 16, 16, 16, 16, 16, 16, 16,
1921                        16, 16, 16, 16, 16, 16, 16, 16,
1922                    ],
1923                    vec![
1924                        16, 16, 16, 16, 16, 16, 16, 16,
1925                        16, 16, 16, 16, 16, 16, 16, 16,
1926                    ],
1927                    vec![
1928                        16, 16, 16, 16, 16, 16, 16, 16,
1929                        16, 16, 16, 16, 16, 16, 16, 16,
1930                    ],
1931                ],
1932                use_default_scaling_matrix_4x4_flag: vec![false, false, false, false, false, false],
1933                ..SeqScalingList::default()
1934            }),*/
1935            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}