cros_codecs/codec/h264/
parser.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Can't reasonably expect client code to consume everything that has been parsed.
6#![allow(dead_code)]
7
8use std::collections::BTreeMap;
9use std::io::Cursor;
10use std::rc::Rc;
11
12use anyhow::anyhow;
13use anyhow::Context;
14use bytes::Buf;
15use enumn::N;
16
17use crate::codec::h264::nalu;
18use crate::codec::h264::nalu::Header;
19use crate::codec::h264::nalu_reader::NaluReader;
20use crate::codec::h264::picture::Field;
21
22pub type Nalu<'a> = nalu::Nalu<'a, NaluHeader>;
23
24pub(super) const DEFAULT_4X4_INTRA: [u8; 16] = [
25    6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42,
26];
27
28pub(super) const DEFAULT_4X4_INTER: [u8; 16] = [
29    10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34,
30];
31
32pub(super) const DEFAULT_8X8_INTRA: [u8; 64] = [
33    6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23, 23, 23, 23, 23, 23, 25, 25, 25,
34    25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31,
35    31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42,
36];
37
38pub(super) const DEFAULT_8X8_INTER: [u8; 64] = [
39    9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21, 21, 21, 21, 21, 21, 22, 22, 22,
40    22, 22, 22, 22, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27,
41    27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35,
42];
43
44const MAX_PPS_COUNT: u16 = 256;
45const MAX_SPS_COUNT: u8 = 32;
46
47/// The maximum number of pictures in the DPB, as per A.3.1, clause h)
48const DPB_MAX_SIZE: usize = 16;
49
50#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
51pub struct Point<T> {
52    pub x: T,
53    pub y: T,
54}
55
56#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
57pub struct Rect<T> {
58    pub min: Point<T>,
59    pub max: Point<T>,
60}
61
62#[derive(N, Debug, PartialEq, Eq, Clone, Copy)]
63pub enum NaluType {
64    Unknown = 0,
65    Slice = 1,
66    SliceDpa = 2,
67    SliceDpb = 3,
68    SliceDpc = 4,
69    SliceIdr = 5,
70    Sei = 6,
71    Sps = 7,
72    Pps = 8,
73    AuDelimiter = 9,
74    SeqEnd = 10,
75    StreamEnd = 11,
76    FillerData = 12,
77    SpsExt = 13,
78    PrefixUnit = 14,
79    SubsetSps = 15,
80    DepthSps = 16,
81    SliceAux = 19,
82    SliceExt = 20,
83    SliceDepth = 21,
84}
85
86#[derive(Clone, Debug, Default, PartialEq, Eq)]
87pub struct RefPicListModification {
88    pub modification_of_pic_nums_idc: u8,
89    /* if modification_of_pic_nums_idc == 0 || 1 */
90    pub abs_diff_pic_num_minus1: u32,
91    /* if modification_of_pic_nums_idc == 2 */
92    pub long_term_pic_num: u32,
93    /* if modification_of_pic_nums_idc == 4 || 5 */
94    pub abs_diff_view_idx_minus1: u32,
95}
96
97#[derive(Clone, Debug, Default, PartialEq, Eq)]
98pub struct PredWeightTable {
99    pub luma_log2_weight_denom: u8,
100    pub chroma_log2_weight_denom: u8,
101
102    pub luma_weight_l0: [i16; 32],
103    pub luma_offset_l0: [i8; 32],
104
105    /* if seq->ChromaArrayType != 0 */
106    pub chroma_weight_l0: [[i16; 2]; 32],
107    pub chroma_offset_l0: [[i8; 2]; 32],
108
109    /* if slice->slice_type % 5 == 1 */
110    pub luma_weight_l1: [i16; 32],
111    pub luma_offset_l1: [i16; 32],
112
113    /* and if seq->ChromaArrayType != 0 */
114    pub chroma_weight_l1: [[i16; 2]; 32],
115    pub chroma_offset_l1: [[i8; 2]; 32],
116}
117
118/// Representation of `MaxLongTermFrameIdx`.
119///
120/// `MaxLongTermFrameIdx` is derived from `max_long_term_frame_idx_plus1`, an unsigned integer with
121/// a special value indicating "no long-term frame indices". This type allows easy conversion
122/// between the actual and "plus1" representation, while ensuring that the special value is always
123/// handled by the code.
124#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
125pub enum MaxLongTermFrameIdx {
126    #[default]
127    NoLongTermFrameIndices,
128    Idx(u32),
129}
130
131impl MaxLongTermFrameIdx {
132    /// Create a value from `max_long_term_frame_idx_plus1`.
133    pub fn from_value_plus1(max_long_term_frame_idx_plus1: u32) -> Self {
134        match max_long_term_frame_idx_plus1 {
135            0 => Self::NoLongTermFrameIndices,
136            i @ 1.. => Self::Idx(i - 1),
137        }
138    }
139
140    /// Convert this value to the representation used by `max_long_term_frame_idx_plus1`.
141    pub fn to_value_plus1(self) -> u32 {
142        match self {
143            Self::NoLongTermFrameIndices => 0,
144            Self::Idx(i) => i + 1,
145        }
146    }
147}
148
149impl PartialEq<u32> for MaxLongTermFrameIdx {
150    fn eq(&self, other: &u32) -> bool {
151        match self {
152            MaxLongTermFrameIdx::NoLongTermFrameIndices => false,
153            MaxLongTermFrameIdx::Idx(idx) => idx.eq(other),
154        }
155    }
156}
157
158impl PartialOrd<u32> for MaxLongTermFrameIdx {
159    fn partial_cmp(&self, other: &u32) -> Option<std::cmp::Ordering> {
160        match self {
161            MaxLongTermFrameIdx::NoLongTermFrameIndices => Some(std::cmp::Ordering::Less),
162            MaxLongTermFrameIdx::Idx(idx) => Some(idx.cmp(other)),
163        }
164    }
165}
166
167#[derive(Clone, Debug, Default, PartialEq, Eq)]
168pub struct RefPicMarkingInner {
169    /// Specifies a control operation to be applied to affect the reference
170    /// picture marking. The `memory_management_control_operation` syntax element
171    /// is followed by data necessary for the operation specified by the value
172    /// of `memory_management_control_operation`. The values and control
173    /// operations associated with `memory_management_control_operation` are
174    /// specified in Table 7-9
175    pub memory_management_control_operation: u8,
176
177    /// Used (with memory_management_control_operation equal to 3 or 1) to
178    /// assign a long-term frame index to a short-term reference picture or to
179    /// mark a short-term reference picture as "unused for reference".
180    pub difference_of_pic_nums_minus1: u32,
181
182    /// Used (with memory_management_control_operation equal to 2) to mark a
183    /// long-term reference picture as "unused for reference".
184    pub long_term_pic_num: u32,
185
186    /// Used (with memory_management_control_operation equal to 3 or 6) to
187    /// assign a long-term frame index to a picture.
188    pub long_term_frame_idx: u32,
189
190    /// Specifies the maximum value of long-term frame index allowed for
191    /// long-term reference pictures (until receipt of another value of
192    /// `max_long_term_frame_idx_plus1`).
193    pub max_long_term_frame_idx: MaxLongTermFrameIdx,
194}
195
196#[derive(Clone, Debug, Default, PartialEq, Eq)]
197pub struct RefPicMarking {
198    /// Specifies how the previously-decoded pictures in the decoded picture
199    /// buffer are treated after decoding of an IDR picture. See Annex C.
200    pub no_output_of_prior_pics_flag: bool,
201
202    /// If unset, specifies that the MaxLongTermFrameIdx variable is set equal
203    /// to "no long-term frame indices" and that the IDR picture is marked as
204    /// "used for short-term reference". If set, specifies that the
205    /// MaxLongTermFrameIdx variable is set equal to 0 and that the current IDR
206    /// picture is marked "used for long-term reference" and is assigned
207    /// LongTermFrameIdx equal to 0.
208    pub long_term_reference_flag: bool,
209
210    /// Selects the reference picture marking mode of the currently decoded
211    /// picture as specified in Table 7-8.
212    pub adaptive_ref_pic_marking_mode_flag: bool,
213
214    /// An Vec with additional data used in the marking process.
215    pub inner: Vec<RefPicMarkingInner>,
216}
217
218#[derive(Clone, Debug, Default, PartialEq, Eq)]
219pub struct SliceHeader {
220    /// Specifies the address of the first macroblock in the slice.
221    pub first_mb_in_slice: u32,
222
223    /// Specifies the coding type of the slice according to Table 7-6.
224    pub slice_type: SliceType,
225
226    // Specifies the picture parameter set in use
227    pub pic_parameter_set_id: u8,
228
229    /// Specifies the colour plane associated with the current slice RBSP when
230    /// `separate_colour_plane_flag` is set.
231    pub colour_plane_id: u8,
232
233    /// Used as an identifier for pictures and shall be represented by
234    /// `log2_max_frame_num_minus4 + 4` bits in the bitstream.
235    pub frame_num: u16,
236
237    /// If set, specifies that the slice is a slice of a coded field. If not
238    /// set, specifies that the slice is a slice of a coded frame.
239    pub field_pic_flag: bool,
240
241    /// If set, specifies that the slice is part of a coded bottom field. If not
242    /// set, specifies that the picture is a coded top field.
243    pub bottom_field_flag: bool,
244
245    /// Identifies an IDR picture. The values of `idr_pic_id` in all the slices
246    /// of an IDR picture shall remain unchanged. When two consecutive access
247    /// units in decoding order are both IDR access units, the value of
248    /// `idr_pic_id` in the slices of the first such IDR access unit shall
249    /// differ from the `idr_pic_id` in the second such IDR access unit
250    pub idr_pic_id: u16,
251
252    /// Specifies the picture order count modulo `MaxPicOrderCntLsb` for the top
253    /// field of a coded frame or for a coded field. The length of the
254    /// `pic_order_cnt_lsb` syntax element is
255    /// `log2_max_pic_order_cnt_lsb_minus4` + 4 bits.
256    pub pic_order_cnt_lsb: u16,
257
258    ///  Specifies the picture order count difference between the bottom field
259    ///  and the top field of a coded frame as follows
260    pub delta_pic_order_cnt_bottom: i32,
261
262    /// The first entry specifies the picture order count difference from the
263    /// expected picture order count for the top field of a coded frame or for a
264    /// coded field as specified in clause 8.2.1 The second entry  specifies the
265    /// picture order count difference from the expected picture order count for
266    /// the bottom field of a coded frame specified in clause 8.2.1.
267    pub delta_pic_order_cnt: [i32; 2],
268
269    /// Shall be equal to 0 for slices and slice data partitions belonging to
270    /// the primary coded picture. The value of `redundant_pic_cnt shall` be
271    /// greater than 0 for coded slices or coded slice data partitions of a
272    /// redundant coded picture
273    pub redundant_pic_cnt: u8,
274
275    /// Specifies the method used in the decoding process to derive motion
276    /// vectors and reference indices for inter prediction >
277    pub direct_spatial_mv_pred_flag: bool,
278
279    /// If set, specifies that the syntax element `num_ref_idx_l0_active_minus1`
280    /// is present for P, SP, and B slices and that the syntax element
281    /// `num_ref_idx_l1_active_minus1` is present for B slices. If not set,
282    /// specifies that the syntax elements `num_ref_idx_l0_active_minus1` and
283    /// `num_ref_idx_l1_active_minus1` are not present.
284    pub num_ref_idx_active_override_flag: bool,
285
286    /// Specifies the maximum reference index for reference picture list 0 that
287    /// shall be used to decode the slice.
288    pub num_ref_idx_l0_active_minus1: u8,
289
290    /// Specifies the maximum reference index for reference picture list 1 that
291    /// shall be used to decode the slice.
292    pub num_ref_idx_l1_active_minus1: u8,
293
294    /// If set, specifies that the syntax element `modification_of_pic_nums_idc`
295    /// is present for specifying reference picture list 0. If not set,
296    /// specifies that this syntax element is not present.
297    pub ref_pic_list_modification_flag_l0: bool,
298
299    /// Reference picture list 0 modification as parsed with the
300    /// `ref_pic_list_modification()` process.
301    pub ref_pic_list_modification_l0: Vec<RefPicListModification>,
302
303    /// If set, specifies that the syntax element `modification_of_pic_nums_idc`
304    /// is present for specifying reference picture list 1. If not set,
305    /// specifies that this syntax element is not present.
306    pub ref_pic_list_modification_flag_l1: bool,
307
308    /// Reference picture list 1 modification as parsed with the
309    /// `ref_pic_list_modification()` process.
310    pub ref_pic_list_modification_l1: Vec<RefPicListModification>,
311
312    /// Prediction weight table as parsed using 7.3.3.2
313    pub pred_weight_table: PredWeightTable,
314
315    /// Decoded reference picture marking parsed using 7.3.3.3
316    pub dec_ref_pic_marking: RefPicMarking,
317
318    /// Specifies the index for determining the initialization table used in the
319    /// initialization process for context variables.
320    pub cabac_init_idc: u8,
321
322    /// Specifies the initial value of QP Y to be used for all the macroblocks
323    /// in the slice until modified by the value of `mb_qp_delta` in the
324    /// macroblock layer. The initial QPY quantization parameter for the slice
325    /// is computed using 7-30.
326    pub slice_qp_delta: i8,
327
328    /// Specifies the decoding process to be used to decode P macroblocks in an
329    /// SP slice.
330    pub sp_for_switch_flag: bool,
331
332    /// Specifies the value of QSY for all the macroblocks in SP and SI slices.
333    /// The QSY quantization parameter for the slice is computed using 7-31.
334    pub slice_qs_delta: i8,
335
336    /// Specifies whether the operation of the deblocking filter shall be
337    /// disabled across some block edges of the slice and specifies for which
338    /// edges the filtering is disabled.
339    pub disable_deblocking_filter_idc: u8,
340
341    /// Specifies the offset used in accessing the α and tC0 deblocking filter
342    /// tables for filtering operations controlled by the macroblocks within the
343    /// slice. From this value, the offset that shall be applied when addressing
344    /// these tables shall be computed using 7-32.
345    pub slice_alpha_c0_offset_div2: i8,
346
347    /// Specifies the offset used in accessing the β deblocking filter table for
348    /// filtering operations controlled by the macroblocks within the slice.
349    /// From this value, the offset that is applied when addressing the β table
350    /// of the deblocking filter shall be computed using 7-33.
351    pub slice_beta_offset_div2: i8,
352
353    /// Same as `MaxPicNum` in the specification.
354    pub max_pic_num: u32,
355
356    /// Size of the slice_header() in bits
357    pub header_bit_size: usize,
358
359    /// Number of emulation prevention bytes (EPB) in this slice_header()
360    pub n_emulation_prevention_bytes: usize,
361}
362
363impl SliceHeader {
364    /// Returns the field that is coded by this header.
365    pub fn field(&self) -> Field {
366        if self.field_pic_flag {
367            if self.bottom_field_flag {
368                Field::Bottom
369            } else {
370                Field::Top
371            }
372        } else {
373            Field::Frame
374        }
375    }
376}
377
378pub struct SliceHeaderBuilder(SliceHeader);
379
380impl SliceHeaderBuilder {
381    pub fn new(pps: &Pps) -> Self {
382        SliceHeaderBuilder(SliceHeader {
383            pic_parameter_set_id: pps.pic_parameter_set_id,
384            ..Default::default()
385        })
386    }
387
388    pub fn slice_type(mut self, type_: SliceType) -> Self {
389        self.0.slice_type = type_;
390        self
391    }
392
393    pub fn first_mb_in_slice(mut self, value: u32) -> Self {
394        self.0.first_mb_in_slice = value;
395        self
396    }
397
398    pub fn pic_order_cnt_lsb(mut self, value: u16) -> Self {
399        self.0.pic_order_cnt_lsb = value;
400        self
401    }
402
403    pub fn idr_pic_id(mut self, value: u16) -> Self {
404        self.0.idr_pic_id = value;
405        self
406    }
407
408    pub fn num_ref_idx_active_override_flag(mut self, value: bool) -> Self {
409        self.0.num_ref_idx_active_override_flag = value;
410        self
411    }
412
413    pub fn num_ref_idx_l0_active_minus1(mut self, value: u8) -> Self {
414        self = self.num_ref_idx_active_override_flag(true);
415        self.0.num_ref_idx_l0_active_minus1 = value;
416        self
417    }
418
419    pub fn num_ref_idx_l0_active(self, value: u8) -> Self {
420        self.num_ref_idx_l0_active_minus1(value - 1)
421    }
422
423    pub fn num_ref_idx_l1_active_minus1(mut self, value: u8) -> Self {
424        self = self.num_ref_idx_active_override_flag(true);
425        self.0.num_ref_idx_l1_active_minus1 = value;
426        self
427    }
428
429    pub fn num_ref_idx_l1_active(self, value: u8) -> Self {
430        self.num_ref_idx_l1_active_minus1(value - 1)
431    }
432
433    pub fn build(self) -> SliceHeader {
434        self.0
435    }
436}
437
438/// A H264 slice. An integer number of macroblocks or macroblock pairs ordered
439/// consecutively in the raster scan within a particular slice group
440pub struct Slice<'a> {
441    /// The slice header.
442    pub header: SliceHeader,
443    /// The NAL unit backing this slice.
444    pub nalu: Nalu<'a>,
445}
446
447#[derive(N, Clone, Copy, Debug, PartialEq, Eq)]
448/// See table 7-6 in the specification.
449pub enum SliceType {
450    P = 0,
451    B = 1,
452    I = 2,
453    Sp = 3,
454    Si = 4,
455}
456
457impl SliceType {
458    /// Whether this is a P slice. See table 7-6 in the specification.
459    pub fn is_p(&self) -> bool {
460        matches!(self, SliceType::P)
461    }
462
463    /// Whether this is a B slice. See table 7-6 in the specification.
464    pub fn is_b(&self) -> bool {
465        matches!(self, SliceType::B)
466    }
467
468    /// Whether this is an I slice. See table 7-6 in the specification.
469    pub fn is_i(&self) -> bool {
470        matches!(self, SliceType::I)
471    }
472
473    /// Whether this is a SP slice. See table 7-6 in the specification.
474    pub fn is_sp(&self) -> bool {
475        matches!(self, SliceType::Sp)
476    }
477
478    /// Whether this is a SI slice. See table 7-6 in the specification.
479    pub fn is_si(&self) -> bool {
480        matches!(self, SliceType::Si)
481    }
482}
483
484impl Default for SliceType {
485    fn default() -> Self {
486        Self::P
487    }
488}
489
490#[derive(N, Clone, Copy)]
491#[repr(u8)]
492pub enum Profile {
493    Baseline = 66,
494    Main = 77,
495    Extended = 88,
496    High = 100,
497    High10 = 110,
498    High422P = 122,
499}
500
501#[derive(N, Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
502pub enum Level {
503    #[default]
504    L1 = 10,
505    L1B = 9,
506    L1_1 = 11,
507    L1_2 = 12,
508    L1_3 = 13,
509    L2_0 = 20,
510    L2_1 = 21,
511    L2_2 = 22,
512    L3 = 30,
513    L3_1 = 31,
514    L3_2 = 32,
515    L4 = 40,
516    L4_1 = 41,
517    L4_2 = 42,
518    L5 = 50,
519    L5_1 = 51,
520    L5_2 = 52,
521    L6 = 60,
522    L6_1 = 61,
523    L6_2 = 62,
524}
525
526/// A H264 Sequence Parameter Set. A syntax structure containing syntax elements
527/// that apply to zero or more entire coded video sequences as determined by the
528/// content of a seq_parameter_set_id syntax element found in the picture
529/// parameter set referred to by the pic_parameter_set_id syntax element found
530/// in each slice header.
531#[derive(Debug, PartialEq, Eq)]
532pub struct Sps {
533    /// Identifies the sequence parameter set that is referred to by the picture
534    /// parameter set
535    pub seq_parameter_set_id: u8,
536
537    /// Profile to which the coded video sequence conforms
538    pub profile_idc: u8,
539
540    /// Retains the same meaning as in the specification. See 7.4.2.1.1
541    pub constraint_set0_flag: bool,
542    /// Retains the same meaning as in the specification. See 7.4.2.1.1
543    pub constraint_set1_flag: bool,
544    /// Retains the same meaning as in the specification. See 7.4.2.1.1
545    pub constraint_set2_flag: bool,
546    /// Retains the same meaning as in the specification. See 7.4.2.1.1
547    pub constraint_set3_flag: bool,
548    /// Retains the same meaning as in the specification. See 7.4.2.1.1
549    pub constraint_set4_flag: bool,
550    /// Retains the same meaning as in the specification. See 7.4.2.1.1
551    pub constraint_set5_flag: bool,
552
553    /// Level to which the coded video sequence conforms
554    pub level_idc: Level,
555
556    /// Specifies the chroma sampling relative to the luma sampling as specified
557    /// in clause 6.2.
558    pub chroma_format_idc: u8,
559
560    /// Specifies whether the three colour components of the 4:4:4 chroma format
561    /// are coded separately.
562    pub separate_colour_plane_flag: bool,
563
564    /// Specifies the bit depth of the samples of the luma array and the value
565    /// of the luma quantization parameter range offset QpBdOffsetY. See 7-3 and
566    /// 7-4.
567    pub bit_depth_luma_minus8: u8,
568
569    /// Specifies the bit depth of the samples of the chroma arrays and the
570    /// value of the chroma quantization parameter range offset QpBdOffsetC. See
571    /// 7-5 and 7-6.
572    pub bit_depth_chroma_minus8: u8,
573
574    /// qpprime_y_zero_transform_bypass_flag equal to 1 specifies that, when
575    /// QP′Y is equal to 0, a transform bypass operation for the transform
576    /// coefficient decoding process and picture construction process prior to
577    /// deblocking filter process as specified in clause 8.5 shall be applied.
578    /// qpprime_y_zero_transform_bypass_flag equal to 0 specifies that the
579    /// transform coefficient decoding process and picture construction process
580    /// prior to deblocking filter process shall not use the transform bypass
581    /// operation
582    /// QP′Y is defined in 7-38 as QP′Y = QPY + QpBdOffsetY
583    pub qpprime_y_zero_transform_bypass_flag: bool,
584
585    /// Whether `seq_scaling_list_present_flag[i]` for i = 0..7 or i = 0..11 is
586    /// present or whether the sequence level scaling list shall be specified by
587    /// Flat_4x4_16 for i = 0..5 and flat_8x8_16 for i = 6..11
588    pub seq_scaling_matrix_present_flag: bool,
589
590    /// 4x4 Scaling list as read with 7.3.2.1.1.1
591    pub scaling_lists_4x4: [[u8; 16]; 6],
592    /// 8x8 Scaling list as read with 7.3.2.1.1.1
593    pub scaling_lists_8x8: [[u8; 64]; 6],
594
595    /// Specifies the value of the variable MaxFrameNum that is used in
596    /// frame_num related derivations as follows: MaxFrameNum = 2 ^
597    /// (log2_max_frame_num_minus4 + 4 )
598    pub log2_max_frame_num_minus4: u8,
599
600    /// Specifies the method to decode picture order count (as specified in
601    /// clause 8.2.1)
602    pub pic_order_cnt_type: u8,
603
604    /// Specifies the value of the variable MaxPicOrderCntLsb that is used in
605    /// the decoding process for picture order count as specified in clause
606    /// 8.2.1 as follows: MaxPicOrderCntLsb = 2 ^ (
607    /// log2_max_pic_order_cnt_lsb_minus4 + 4 ).
608    pub log2_max_pic_order_cnt_lsb_minus4: u8,
609
610    /// If true, specifies that `delta_pic_order_cnt[0]` and
611    /// `delta_pic_order_cnt[1]` are not present in the slice headers of the
612    /// sequence and shall be inferred to be equal to 0.
613    /// If false, specifies that `delta_pic_order_cnt[0]` is present in the
614    /// slice headers of the sequence and `delta_pic_order_cnt[1]` may be
615    /// present in the slice headers of the sequence.
616    pub delta_pic_order_always_zero_flag: bool,
617
618    /// Used to calculate the picture order count of a non-reference picture as
619    /// specified in clause 8.2.1.
620    pub offset_for_non_ref_pic: i32,
621
622    /// Used to calculate the picture order count of a bottom field as specified
623    /// in clause 8.2.1.
624    pub offset_for_top_to_bottom_field: i32,
625
626    /// Used in the decoding process for picture order count as specified in
627    /// clause 8.2.1
628    pub num_ref_frames_in_pic_order_cnt_cycle: u8,
629
630    /// An element of a list of num_ref_frames_in_pic_order_cnt_cycle values
631    /// used in the decoding process for picture order count as specified in
632    /// clause 8.2.
633    pub offset_for_ref_frame: [i32; 255],
634
635    /// Specifies the maximum number of short-term and long-term reference
636    /// frames, complementary reference field pairs, and non-paired reference
637    /// fields that may be used by the decoding process for inter prediction of
638    /// any picture in the coded video sequence. Also
639    /// determines the size of the sliding window operation as specified in
640    /// clause 8.2.5.3.
641    pub max_num_ref_frames: u8,
642
643    /// Specifies the allowed values of frame_num as specified in clause 7.4.3
644    /// and the decoding process in case of an inferred gap between values of
645    /// frame_num as specified in clause 8.2.5.2
646    pub gaps_in_frame_num_value_allowed_flag: bool,
647
648    /// Plus 1 specifies the width of each decoded picture in units of
649    /// macroblocks.
650    pub pic_width_in_mbs_minus1: u16,
651    /// Plus 1 specifies the height in slice group map units of a decoded frame
652    /// or field.
653    pub pic_height_in_map_units_minus1: u16,
654
655    /// If true,  specifies that every coded picture of the coded video sequence
656    /// is a coded frame containing only frame macroblocks, else specifies that
657    /// coded pictures of the coded video sequence may either be coded fields or
658    /// coded frames.
659    pub frame_mbs_only_flag: bool,
660
661    /// If true, specifies the possible use of switching between frame and field
662    /// macroblocks within frames, else, specifies no switching between frame
663    /// and field macroblocks within a picture.
664    pub mb_adaptive_frame_field_flag: bool,
665
666    /// Specifies the method used in the derivation process for luma motion
667    /// vectors for B_Skip, B_Direct_16x16 and B_Direct_8x8 as specified in
668    /// clause 8.4.1.2.
669    pub direct_8x8_inference_flag: bool,
670
671    /// If true, specifies that the frame cropping offset parameters follow next
672    /// in the sequence parameter, else specifies that the frame cropping offset
673    /// parameters are not present
674    pub frame_cropping_flag: bool,
675
676    /// Specify the samples of the pictures in the coded video sequence that are
677    /// output from the decoding process, in terms of a rectangular region
678    /// specified in frame coordinates for output.
679    pub frame_crop_left_offset: u32,
680    /// Specify the samples of the pictures in the coded video sequence that are
681    /// output from the decoding process, in terms of a rectangular region
682    /// specified in frame coordinates for output.
683    pub frame_crop_right_offset: u32,
684    /// Specify the samples of the pictures in the coded video sequence that are
685    /// output from the decoding process, in terms of a rectangular region
686    /// specified in frame coordinates for output.
687    pub frame_crop_top_offset: u32,
688    /// Specify the samples of the pictures in the coded video sequence that are
689    /// output from the decoding process, in terms of a rectangular region
690    /// specified in frame coordinates for output.
691    pub frame_crop_bottom_offset: u32,
692
693    // Calculated
694    /// Same as ExpectedDeltaPerPicOrderCntCycle, see 7-12 in the specification.
695    pub expected_delta_per_pic_order_cnt_cycle: i32,
696
697    pub vui_parameters_present_flag: bool,
698    pub vui_parameters: VuiParams,
699}
700
701impl Sps {
702    /// Returns the coded width of the stream.
703    ///
704    /// See 7-13 through 7-17 in the specification.
705    pub const fn width(&self) -> u32 {
706        (self.pic_width_in_mbs_minus1 as u32 + 1) * 16
707    }
708
709    /// Returns the coded height of the stream.
710    ///
711    /// See 7-13 through 7-17 in the specification.
712    pub const fn height(&self) -> u32 {
713        (self.pic_height_in_map_units_minus1 as u32 + 1)
714            * 16
715            * (2 - self.frame_mbs_only_flag as u32)
716    }
717
718    /// Returns `ChromaArrayType`, as computed in the specification.
719    pub const fn chroma_array_type(&self) -> u8 {
720        match self.separate_colour_plane_flag {
721            false => self.chroma_format_idc,
722            true => 0,
723        }
724    }
725
726    /// Returns `SubWidthC` and `SubHeightC`.
727    ///
728    /// See table 6-1 in the specification.
729    fn sub_width_height_c(&self) -> (u32, u32) {
730        match (self.chroma_format_idc, self.separate_colour_plane_flag) {
731            (1, false) => (2, 2),
732            (2, false) => (2, 1),
733            (3, false) => (1, 1),
734            // undefined.
735            _ => (1, 1),
736        }
737    }
738
739    /// Returns `CropUnitX` and `CropUnitY`.
740    ///
741    /// See 7-19 through 7-22 in the specification.
742    fn crop_unit_x_y(&self) -> (u32, u32) {
743        match self.chroma_array_type() {
744            0 => (1, 2 - u32::from(self.frame_mbs_only_flag)),
745            _ => {
746                let (sub_width_c, sub_height_c) = self.sub_width_height_c();
747                (
748                    sub_width_c,
749                    sub_height_c * (2 - u32::from(self.frame_mbs_only_flag)),
750                )
751            }
752        }
753    }
754
755    /// Same as MaxFrameNum. See 7-10 in the specification.
756    pub fn max_frame_num(&self) -> u32 {
757        1 << (self.log2_max_frame_num_minus4 + 4)
758    }
759
760    pub fn visible_rectangle(&self) -> Rect<u32> {
761        if !self.frame_cropping_flag {
762            return Rect {
763                min: Point { x: 0, y: 0 },
764                max: Point {
765                    x: self.width(),
766                    y: self.height(),
767                },
768            };
769        }
770
771        let (crop_unit_x, crop_unit_y) = self.crop_unit_x_y();
772
773        let crop_left = crop_unit_x * self.frame_crop_left_offset;
774        let crop_right = crop_unit_x * self.frame_crop_right_offset;
775        let crop_top = crop_unit_y * self.frame_crop_top_offset;
776        let crop_bottom = crop_unit_y * self.frame_crop_bottom_offset;
777
778        Rect {
779            min: Point {
780                x: crop_left,
781                y: crop_top,
782            },
783            max: Point {
784                x: self.width() - crop_left - crop_right,
785                y: self.height() - crop_top - crop_bottom,
786            },
787        }
788    }
789
790    pub fn max_dpb_frames(&self) -> usize {
791        let profile = self.profile_idc;
792        let mut level = self.level_idc;
793
794        // A.3.1 and A.3.2: Level 1b for Baseline, Constrained Baseline and Main
795        // profile if level_idc == 11 and constraint_set3_flag == 1
796        if matches!(level, Level::L1_1)
797            && (profile == Profile::Baseline as u8 || profile == Profile::Main as u8)
798            && self.constraint_set3_flag
799        {
800            level = Level::L1B;
801        };
802
803        // Table A.1
804        let max_dpb_mbs = match level {
805            Level::L1 => 396,
806            Level::L1B => 396,
807            Level::L1_1 => 900,
808            Level::L1_2 => 2376,
809            Level::L1_3 => 2376,
810            Level::L2_0 => 2376,
811            Level::L2_1 => 4752,
812            Level::L2_2 => 8100,
813            Level::L3 => 8100,
814            Level::L3_1 => 18000,
815            Level::L3_2 => 20480,
816            Level::L4 => 32768,
817            Level::L4_1 => 32768,
818            Level::L4_2 => 34816,
819            Level::L5 => 110400,
820            Level::L5_1 => 184320,
821            Level::L5_2 => 184320,
822            Level::L6 => 696320,
823            Level::L6_1 => 696320,
824            Level::L6_2 => 696320,
825        };
826
827        let width_mb = self.width() / 16;
828        let height_mb = self.height() / 16;
829
830        let max_dpb_frames =
831            std::cmp::min(max_dpb_mbs / (width_mb * height_mb), DPB_MAX_SIZE as u32) as usize;
832
833        let mut max_dpb_frames = std::cmp::max(max_dpb_frames, self.max_num_ref_frames as usize);
834
835        if self.vui_parameters_present_flag && self.vui_parameters.bitstream_restriction_flag {
836            max_dpb_frames = std::cmp::max(1, self.vui_parameters.max_dec_frame_buffering as usize);
837        }
838
839        max_dpb_frames
840    }
841
842    pub fn max_num_order_frames(&self) -> u32 {
843        let vui = &self.vui_parameters;
844        let present = self.vui_parameters_present_flag && vui.bitstream_restriction_flag;
845
846        if present {
847            vui.max_num_reorder_frames
848        } else {
849            let profile = self.profile_idc;
850            if (profile == 44
851                || profile == 86
852                || profile == 100
853                || profile == 110
854                || profile == 122
855                || profile == 244)
856                && self.constraint_set3_flag
857            {
858                0
859            } else {
860                self.max_dpb_frames() as u32
861            }
862        }
863    }
864}
865
866// TODO: Replace with builder
867impl Default for Sps {
868    fn default() -> Self {
869        Self {
870            scaling_lists_4x4: [[0; 16]; 6],
871            scaling_lists_8x8: [[0; 64]; 6],
872            offset_for_ref_frame: [0; 255],
873            seq_parameter_set_id: Default::default(),
874            profile_idc: Default::default(),
875            constraint_set0_flag: Default::default(),
876            constraint_set1_flag: Default::default(),
877            constraint_set2_flag: Default::default(),
878            constraint_set3_flag: Default::default(),
879            constraint_set4_flag: Default::default(),
880            constraint_set5_flag: Default::default(),
881            level_idc: Default::default(),
882            chroma_format_idc: Default::default(),
883            separate_colour_plane_flag: Default::default(),
884            bit_depth_luma_minus8: Default::default(),
885            bit_depth_chroma_minus8: Default::default(),
886            qpprime_y_zero_transform_bypass_flag: Default::default(),
887            seq_scaling_matrix_present_flag: Default::default(),
888            log2_max_frame_num_minus4: Default::default(),
889            pic_order_cnt_type: Default::default(),
890            log2_max_pic_order_cnt_lsb_minus4: Default::default(),
891            delta_pic_order_always_zero_flag: Default::default(),
892            offset_for_non_ref_pic: Default::default(),
893            offset_for_top_to_bottom_field: Default::default(),
894            num_ref_frames_in_pic_order_cnt_cycle: Default::default(),
895            max_num_ref_frames: Default::default(),
896            gaps_in_frame_num_value_allowed_flag: Default::default(),
897            pic_width_in_mbs_minus1: Default::default(),
898            pic_height_in_map_units_minus1: Default::default(),
899            frame_mbs_only_flag: Default::default(),
900            mb_adaptive_frame_field_flag: Default::default(),
901            direct_8x8_inference_flag: Default::default(),
902            frame_cropping_flag: Default::default(),
903            frame_crop_left_offset: Default::default(),
904            frame_crop_right_offset: Default::default(),
905            frame_crop_top_offset: Default::default(),
906            frame_crop_bottom_offset: Default::default(),
907            expected_delta_per_pic_order_cnt_cycle: Default::default(),
908            vui_parameters_present_flag: Default::default(),
909            vui_parameters: Default::default(),
910        }
911    }
912}
913
914#[derive(Default)]
915pub struct SpsBuilder(Sps);
916
917impl SpsBuilder {
918    pub fn new() -> Self {
919        Default::default()
920    }
921
922    pub fn seq_parameter_set_id(mut self, value: u8) -> Self {
923        self.0.seq_parameter_set_id = value;
924        self
925    }
926
927    pub fn profile_idc(mut self, value: Profile) -> Self {
928        self.0.profile_idc = value as u8;
929        self
930    }
931
932    pub fn level_idc(mut self, value: Level) -> Self {
933        self.0.level_idc = value;
934        self
935    }
936
937    pub fn frame_crop_offsets(mut self, top: u32, bottom: u32, left: u32, right: u32) -> Self {
938        self.0.frame_cropping_flag = true;
939        self.0.frame_crop_top_offset = top;
940        self.0.frame_crop_bottom_offset = bottom;
941        self.0.frame_crop_left_offset = left;
942        self.0.frame_crop_right_offset = right;
943        self
944    }
945
946    pub fn frame_crop(self, top: u32, bottom: u32, left: u32, right: u32) -> Self {
947        let sub_width_c = if self.0.chroma_format_idc > 2 { 1 } else { 2 };
948        let sub_height_c = if self.0.chroma_format_idc > 1 { 1 } else { 2 };
949
950        let crop_unit_x = sub_width_c;
951        let crop_unit_y = sub_height_c * (if self.0.frame_mbs_only_flag { 1 } else { 2 });
952
953        self.frame_crop_offsets(
954            top / crop_unit_y,
955            bottom / crop_unit_y,
956            left / crop_unit_x,
957            right / crop_unit_x,
958        )
959    }
960
961    pub fn resolution(mut self, width: u32, height: u32) -> Self {
962        const MB_SIZE: u32 = 16;
963
964        let mb_width = (width + MB_SIZE - 1) / MB_SIZE;
965        let mb_height = (height + MB_SIZE - 1) / MB_SIZE;
966
967        self.0.pic_width_in_mbs_minus1 = (mb_width - 1) as u16;
968        self.0.pic_height_in_map_units_minus1 = (mb_height - 1) as u16;
969
970        let compressed_width = mb_width * MB_SIZE;
971        let compressed_height = mb_height * MB_SIZE;
972
973        if compressed_width != width || compressed_height != height {
974            self = self.frame_crop(0, compressed_height - height, 0, compressed_width - width);
975        }
976
977        self
978    }
979
980    pub fn chroma_format_idc(mut self, value: u8) -> Self {
981        self.0.chroma_format_idc = value;
982        self
983    }
984
985    pub fn max_num_ref_frames(mut self, value: u8) -> Self {
986        self.0.max_num_ref_frames = value;
987        self
988    }
989
990    pub fn frame_mbs_only_flag(mut self, value: bool) -> Self {
991        self.0.frame_mbs_only_flag = value;
992        self
993    }
994
995    pub fn mb_adaptive_frame_field_flag(mut self, value: bool) -> Self {
996        self.0.mb_adaptive_frame_field_flag = value;
997        self
998    }
999
1000    pub fn seq_scaling_matrix_present_flag(mut self, value: bool) -> Self {
1001        self.0.seq_scaling_matrix_present_flag = value;
1002        self
1003    }
1004
1005    pub fn direct_8x8_inference_flag(mut self, value: bool) -> Self {
1006        self.0.direct_8x8_inference_flag = value;
1007        self
1008    }
1009
1010    pub fn vui_parameters_present(mut self) -> Self {
1011        if self.0.vui_parameters_present_flag {
1012            return self;
1013        }
1014
1015        self.0.vui_parameters_present_flag = true;
1016        // Disable all options at default
1017        self.0.vui_parameters.aspect_ratio_info_present_flag = false;
1018        self.0.vui_parameters.overscan_info_present_flag = false;
1019        self.0.vui_parameters.video_signal_type_present_flag = false;
1020        self.0.vui_parameters.colour_description_present_flag = false;
1021        self.0.vui_parameters.chroma_loc_info_present_flag = false;
1022        self.0.vui_parameters.timing_info_present_flag = false;
1023        self.0.vui_parameters.nal_hrd_parameters_present_flag = false;
1024        self.0.vui_parameters.vcl_hrd_parameters_present_flag = false;
1025        self.0.vui_parameters.pic_struct_present_flag = false;
1026        self.0.vui_parameters.bitstream_restriction_flag = false;
1027        self
1028    }
1029
1030    pub fn aspect_ratio_idc(mut self, value: u8) -> Self {
1031        self = self.vui_parameters_present();
1032        self.0.vui_parameters.aspect_ratio_info_present_flag = true;
1033        self.0.vui_parameters.aspect_ratio_idc = value;
1034        self
1035    }
1036
1037    pub fn sar_resolution(mut self, width: u16, height: u16) -> Self {
1038        self = self.aspect_ratio_idc(255);
1039        self.0.vui_parameters.sar_width = width;
1040        self.0.vui_parameters.sar_height = height;
1041        self
1042    }
1043
1044    pub fn aspect_ratio(self, width_ratio: u16, height_ratio: u16) -> Self {
1045        // H.264 Table E-1
1046        match (width_ratio, height_ratio) {
1047            (1, 1) => self.aspect_ratio_idc(1),
1048            (12, 11) => self.aspect_ratio_idc(2),
1049            (10, 11) => self.aspect_ratio_idc(3),
1050            (16, 11) => self.aspect_ratio_idc(4),
1051            (40, 33) => self.aspect_ratio_idc(5),
1052            (24, 11) => self.aspect_ratio_idc(6),
1053            (20, 11) => self.aspect_ratio_idc(7),
1054            (32, 11) => self.aspect_ratio_idc(8),
1055            (80, 33) => self.aspect_ratio_idc(9),
1056            (18, 11) => self.aspect_ratio_idc(10),
1057            (15, 11) => self.aspect_ratio_idc(11),
1058            (64, 33) => self.aspect_ratio_idc(12),
1059            (160, 99) => self.aspect_ratio_idc(13),
1060            (4, 3) => self.aspect_ratio_idc(14),
1061            (3, 2) => self.aspect_ratio_idc(15),
1062            (2, 1) => self.aspect_ratio_idc(16),
1063
1064            _ => self.sar_resolution(width_ratio, height_ratio),
1065        }
1066    }
1067
1068    pub fn timing_info(
1069        mut self,
1070        num_units_in_tick: u32,
1071        time_scale: u32,
1072        fixed_frame_rate_flag: bool,
1073    ) -> Self {
1074        self = self.vui_parameters_present();
1075        self.0.vui_parameters.timing_info_present_flag = true;
1076        self.0.vui_parameters.num_units_in_tick = num_units_in_tick;
1077        self.0.vui_parameters.time_scale = time_scale;
1078        self.0.vui_parameters.fixed_frame_rate_flag = fixed_frame_rate_flag;
1079        self
1080    }
1081
1082    pub fn log2_max_frame_num_minus4(mut self, value: u8) -> Self {
1083        self.0.log2_max_frame_num_minus4 = value;
1084        self
1085    }
1086
1087    pub fn max_frame_num(self, value: u32) -> Self {
1088        self.log2_max_frame_num_minus4(value.ilog2() as u8 - 4u8)
1089    }
1090
1091    pub fn pic_order_cnt_type(mut self, value: u8) -> Self {
1092        self.0.pic_order_cnt_type = value;
1093        self
1094    }
1095
1096    pub fn log2_max_pic_order_cnt_lsb_minus4(mut self, value: u8) -> Self {
1097        self.0.log2_max_pic_order_cnt_lsb_minus4 = value;
1098        self
1099    }
1100
1101    pub fn max_pic_order_cnt_lsb(self, value: u32) -> Self {
1102        self.log2_max_pic_order_cnt_lsb_minus4(value.ilog2() as u8 - 4u8)
1103    }
1104
1105    pub fn delta_pic_order_always_zero_flag(mut self, value: bool) -> Self {
1106        self.0.delta_pic_order_always_zero_flag = value;
1107        self
1108    }
1109
1110    pub fn bit_depth_chroma_minus8(mut self, value: u8) -> Self {
1111        self.0.bit_depth_chroma_minus8 = value;
1112        self
1113    }
1114
1115    pub fn bit_depth_chroma(self, value: u8) -> Self {
1116        self.bit_depth_luma_minus8(value - 8u8)
1117    }
1118
1119    pub fn bit_depth_luma_minus8(mut self, value: u8) -> Self {
1120        self.0.bit_depth_luma_minus8 = value;
1121        self
1122    }
1123
1124    pub fn bit_depth_luma(self, value: u8) -> Self {
1125        self.bit_depth_luma_minus8(value - 8u8)
1126    }
1127
1128    pub fn build(self) -> Rc<Sps> {
1129        Rc::new(self.0)
1130    }
1131}
1132
1133#[derive(Clone, Debug, Default, PartialEq, Eq)]
1134pub struct HrdParams {
1135    /// Plus 1 specifies the number of alternative CPB specifications in the
1136    /// bitstream. The value of `cpb_cnt_minus1` shall be in the range of 0 to 31,
1137    /// inclusive
1138    pub cpb_cnt_minus1: u8,
1139    /// Together with `bit_rate_value_minus1[ SchedSelIdx ]` specifies the
1140    /// maximum input bit rate of the `SchedSelIdx`-th CPB.
1141    pub bit_rate_scale: u8,
1142    /// Together with `cpb_size_value_minus1[ SchedSelIdx ]` specifies the CPB
1143    /// size of the SchedSelIdx-th CPB.
1144    pub cpb_size_scale: u8,
1145
1146    /// `[ SchedSelIdx ]` (together with bit_rate_scale) specifies the maximum
1147    /// input bit rate for the SchedSelIdx-th CPB.
1148    pub bit_rate_value_minus1: [u32; 32],
1149    /// `[ SchedSelIdx ]` is used together with cpb_size_scale to specify the
1150    /// SchedSelIdx-th CPB size.
1151    pub cpb_size_value_minus1: [u32; 32],
1152    /// `[ SchedSelIdx ]` equal to 0 specifies that to decode this bitstream by
1153    /// the HRD using the `SchedSelIdx`-th CPB specification, the hypothetical
1154    /// stream delivery scheduler (HSS) operates in an intermittent bit rate
1155    /// mode. `cbr_flag[ SchedSelIdx ]` equal to 1 specifies that the HSS operates
1156    /// in a constant bit rate (CBR) mode
1157    pub cbr_flag: [bool; 32],
1158
1159    /// Specifies the length in bits of the `initial_cpb_removal_delay[
1160    /// SchedSelIdx ]` and `initial_cpb_removal_delay_offset[ SchedSelIdx ]` syntax
1161    /// elements of the buffering period SEI message.
1162    pub initial_cpb_removal_delay_length_minus1: u8,
1163    /// Specifies the length in bits of the `cpb_removal_delay` syntax element.
1164    pub cpb_removal_delay_length_minus1: u8,
1165    /// Specifies the length in bits of the `dpb_output_delay` syntax element.
1166    pub dpb_output_delay_length_minus1: u8,
1167    /// If greater than 0, specifies the length in bits of the `time_offset`
1168    /// syntax element. `time_offset_length` equal to 0 specifies that the
1169    /// `time_offset` syntax element is not present
1170    pub time_offset_length: u8,
1171}
1172
1173#[derive(Clone, Debug, PartialEq, Eq)]
1174pub struct VuiParams {
1175    /// Specifies whether `aspect_ratio_idc` is present.
1176    pub aspect_ratio_info_present_flag: bool,
1177    /// Specifies the value of the sample aspect ratio of the luma samples.
1178    /// Table E-1 shows the meaning of the code. When aspect_ratio_idc indicates
1179    /// Extended_SAR, the sample aspect ratio is represented by sar_width :
1180    /// sar_height. When the aspect_ratio_idc syntax element is not present,
1181    /// aspect_ratio_idc value shall be inferred to be equal to 0
1182    pub aspect_ratio_idc: u8,
1183
1184    /* if aspect_ratio_idc == 255 */
1185    /// Indicates the horizontal size of the sample aspect ratio (in arbitrary
1186    /// units)
1187    pub sar_width: u16,
1188    /// Indicates the vertical size of the sample aspect ratio (in the same
1189    /// arbitrary units as sar_width).
1190    pub sar_height: u16,
1191
1192    /// If true specifies that the overscan_appropriate_flag is present. Else,
1193    /// the preferred display method for the video signal is unspecified
1194    pub overscan_info_present_flag: bool,
1195    /* if overscan_info_present_flag */
1196    /// If true, indicates that the cropped decoded pictures output are suitable
1197    /// for display using overscan. Else, indicates that the cropped decoded
1198    /// pictures output contain visually important information in the entire
1199    /// region out to the edges of the cropping rectangle of the picture, such
1200    /// that the cropped decoded pictures output should not be displayed using
1201    /// overscan.
1202    pub overscan_appropriate_flag: bool,
1203
1204    /// Specifies that video_format, video_full_range_flag and
1205    /// colour_description_present_flag are present
1206    pub video_signal_type_present_flag: bool,
1207    /// Indicates the representation of the pictures as specified in Table E-2,
1208    /// before being coded in accordance with this Recommendation |
1209    /// International Standard. When the video_format syntax element is not
1210    /// present, video_format value shall be inferred to be equal to 5.
1211    pub video_format: u8,
1212    /// Indicates the black level and range of the luma and chroma signals as
1213    /// derived from E′Y, E′PB, and E′PR or E′ R, E′G, and E′B real-valued
1214    /// component signals.
1215    pub video_full_range_flag: bool,
1216    /// Specifies that colour_primaries, transfer_characteristics and
1217    /// matrix_coefficients are present.
1218    pub colour_description_present_flag: bool,
1219    /// Indicates the chromaticity coordinates of the source primaries as
1220    /// specified in Table E-3 in terms of the CIE 1931 definition of x and y as
1221    /// specified by ISO 11664-1.
1222    pub colour_primaries: u8,
1223    /// Retains same meaning as in the specification.
1224    pub transfer_characteristics: u8,
1225    /// Describes the matrix coefficients used in deriving luma and chroma
1226    /// signals from the green, blue, and red, or Y, Z, and X primaries, as
1227    /// specified in Table E-5.
1228    pub matrix_coefficients: u8,
1229
1230    /// Specifies that chroma_sample_loc_type_top_field and
1231    /// chroma_sample_loc_type_bottom_field are present
1232    pub chroma_loc_info_present_flag: bool,
1233    /// Specify the location of chroma samples. See the spec for more details.
1234    pub chroma_sample_loc_type_top_field: u8,
1235    /// Specify the location of chroma samples. See the spec for more details.
1236    pub chroma_sample_loc_type_bottom_field: u8,
1237
1238    /// Specifies that num_units_in_tick, time_scale and fixed_frame_rate_flag
1239    /// are present in the bitstream
1240    pub timing_info_present_flag: bool,
1241    /* if timing_info_present_flag */
1242    /// The number of time units of a clock operating at the frequency
1243    /// time_scale Hz that corresponds to one increment (called a clock tick) of
1244    /// a clock tick counter
1245    pub num_units_in_tick: u32,
1246    /// The number of time units that pass in one second. For example, a time
1247    /// coordinate system that measures time using a 27 MHz clock has a
1248    /// time_scale of 27 000 000. time_scale shall be greater than 0.
1249    pub time_scale: u32,
1250    /// Retains the same meaning as the specification.
1251    pub fixed_frame_rate_flag: bool,
1252
1253    /// Specifies that NAL HRD parameters (pertaining to Type II bitstream
1254    /// conformance) are present.
1255    pub nal_hrd_parameters_present_flag: bool,
1256    /* if nal_hrd_parameters_present_flag */
1257    /// The NAL HDR parameters
1258    pub nal_hrd_parameters: HrdParams,
1259    /// Specifies that VCL HRD parameters (pertaining to all bitstream
1260    /// conformance) are present.
1261    pub vcl_hrd_parameters_present_flag: bool,
1262    /* if vcl_hrd_parameters_present_flag */
1263    /// The VCL HRD parameters
1264    pub vcl_hrd_parameters: HrdParams,
1265
1266    /// Specifies the HRD operational mode as specified in Annex C.
1267    pub low_delay_hrd_flag: bool,
1268
1269    /// Specifies that picture timing SEI messages (clause D.2.3) are present
1270    /// that include the pic_struct syntax element.
1271    pub pic_struct_present_flag: bool,
1272
1273    /// Specifies that the following coded video sequence bitstream restriction
1274    /// parameters are present
1275    pub bitstream_restriction_flag: bool,
1276    /*  if bitstream_restriction_flag */
1277    /// If false, indicates that no sample outside the picture boundaries and no
1278    /// sample at a fractional sample position for which the sample value is
1279    /// derived using one or more samples outside the picture boundaries is used
1280    /// for inter prediction of any sample. If true, indicates that one or more
1281    /// samples outside picture boundaries may be used in inter prediction. When
1282    /// the motion_vectors_over_pic_boundaries_flag syntax element is not
1283    /// present, motion_vectors_over_pic_boundaries_flag value shall be inferred
1284    /// to be true.
1285    pub motion_vectors_over_pic_boundaries_flag: bool,
1286    /// Indicates a number of bytes not exceeded by the sum of the sizes of the
1287    /// VCL NAL units associated with any coded picture in the coded video
1288    /// sequence.
1289    pub max_bytes_per_pic_denom: u32,
1290    /// Indicates an upper bound for the number of coded bits of
1291    /// macroblock_layer( ) data for any macroblock in any picture of the coded
1292    /// video sequence
1293    pub max_bits_per_mb_denom: u32,
1294    /// Retains the same meaning as the specification.
1295    pub log2_max_mv_length_horizontal: u32,
1296    /// Retains the same meaning as the specification.
1297    pub log2_max_mv_length_vertical: u32,
1298    /// Indicates an upper bound for the number of frames buffers, in the
1299    /// decoded picture buffer (DPB), that are required for storing frames,
1300    /// complementary field pairs, and non-paired fields before output. It is a
1301    /// requirement of bitstream conformance that the maximum number of frames,
1302    /// complementary field pairs, or non-paired fields that precede any frame,
1303    /// complementary field pair, or non-paired field in the coded video
1304    /// sequence in decoding order and follow it in output order shall be less
1305    /// than or equal to max_num_reorder_frames. The value of
1306    /// max_num_reorder_frames shall be in the range of 0 to
1307    /// max_dec_frame_buffering, inclusive.
1308    ///
1309    /// When the max_num_reorder_frames syntax element is not present, the value
1310    /// of max_num_reorder_frames value shall be inferred as follows:
1311    /// If profile_idc is equal to 44, 86, 100, 110, 122, or 244 and
1312    /// constraint_set3_flag is equal to 1, the value of max_num_reorder_frames
1313    /// shall be inferred to be equal to 0.
1314    ///
1315    /// Otherwise (profile_idc is not equal to 44, 86, 100, 110, 122, or 244 or
1316    /// constraint_set3_flag is equal to 0), the value of max_num_reorder_frames
1317    /// shall be inferred to be equal to MaxDpbFrames.
1318    pub max_num_reorder_frames: u32,
1319    /// Specifies the required size of the HRD decoded picture buffer (DPB) in
1320    /// units of frame buffers. It is a requirement of bitstream conformance
1321    /// that the coded video sequence shall not require a decoded picture buffer
1322    /// with size of more than Max( 1, max_dec_frame_buffering ) frame buffers
1323    /// to enable the output of decoded pictures at the output times specified
1324    /// by dpb_output_delay of the picture timing SEI messages. The value of
1325    /// max_dec_frame_buffering shall be greater than or equal to
1326    /// max_num_ref_frames. An upper bound for the value of
1327    /// max_dec_frame_buffering is specified by the level limits in clauses
1328    /// A.3.1, A.3.2, G.10.2.1, and H.10.2.
1329    ///
1330    /// When the max_dec_frame_buffering syntax element is not present, the
1331    /// value of max_dec_frame_buffering shall be inferred as follows:
1332    ///
1333    /// If profile_idc is equal to 44, 86, 100, 110, 122, or 244 and
1334    /// constraint_set3_flag is equal to 1, the value of max_dec_frame_buffering
1335    /// shall be inferred to be equal to 0.
1336    ///
1337    /// Otherwise (profile_idc is not equal to 44, 86, 100, 110, 122, or 244 or
1338    /// constraint_set3_flag is equal to 0), the value of
1339    /// max_dec_frame_buffering shall be inferred to be equal to MaxDpbFrames.
1340    pub max_dec_frame_buffering: u32,
1341}
1342
1343impl Default for VuiParams {
1344    fn default() -> Self {
1345        Self {
1346            aspect_ratio_info_present_flag: Default::default(),
1347            aspect_ratio_idc: Default::default(),
1348            sar_width: Default::default(),
1349            sar_height: Default::default(),
1350            overscan_info_present_flag: Default::default(),
1351            overscan_appropriate_flag: Default::default(),
1352            video_signal_type_present_flag: Default::default(),
1353            video_format: 5,
1354            video_full_range_flag: Default::default(),
1355            colour_description_present_flag: Default::default(),
1356            colour_primaries: 2,
1357            transfer_characteristics: 2,
1358            matrix_coefficients: 2,
1359            chroma_loc_info_present_flag: Default::default(),
1360            chroma_sample_loc_type_top_field: Default::default(),
1361            chroma_sample_loc_type_bottom_field: Default::default(),
1362            timing_info_present_flag: Default::default(),
1363            num_units_in_tick: Default::default(),
1364            time_scale: Default::default(),
1365            fixed_frame_rate_flag: Default::default(),
1366            nal_hrd_parameters_present_flag: Default::default(),
1367            nal_hrd_parameters: Default::default(),
1368            vcl_hrd_parameters_present_flag: Default::default(),
1369            vcl_hrd_parameters: Default::default(),
1370            low_delay_hrd_flag: Default::default(),
1371            pic_struct_present_flag: Default::default(),
1372            bitstream_restriction_flag: Default::default(),
1373            motion_vectors_over_pic_boundaries_flag: Default::default(),
1374            max_bytes_per_pic_denom: Default::default(),
1375            max_bits_per_mb_denom: Default::default(),
1376            log2_max_mv_length_horizontal: Default::default(),
1377            log2_max_mv_length_vertical: Default::default(),
1378            max_num_reorder_frames: Default::default(),
1379            max_dec_frame_buffering: Default::default(),
1380        }
1381    }
1382}
1383
1384/// A H264 Picture Parameter Set. A syntax structure containing syntax elements
1385/// that apply to zero or more entire coded pictures as determined by the
1386/// `pic_parameter_set_id` syntax element found in each slice header.
1387#[derive(Debug, PartialEq, Eq)]
1388pub struct Pps {
1389    /// Identifies the picture parameter set that is referred to in the slice header.
1390    pub pic_parameter_set_id: u8,
1391
1392    /// Refers to the active sequence parameter set.
1393    pub seq_parameter_set_id: u8,
1394
1395    /// Selects the entropy decoding method to be applied for the syntax
1396    /// elements for which two descriptors appear in the syntax tables as
1397    /// follows: If `entropy_coding_mode_flag` is false, the method specified by
1398    /// the left descriptor in the syntax table is applied (Exp-Golomb coded,
1399    /// see clause 9.1 or CAVLC, see clause 9.2). Otherwise
1400    /// (`entropy_coding_mode_flag` is true), the method specified by the right
1401    /// descriptor in the syntax table is applied (CABAC, see clause 9.3).
1402    pub entropy_coding_mode_flag: bool,
1403
1404    /// If true, specifies that the syntax elements delta_pic_order_cnt_bottom
1405    /// (when `pic_order_cnt_type` is equal to 0) or `delta_pic_order_cnt[1]`
1406    /// (when `pic_order_cnt_type` is equal to 1), which are related to picture
1407    /// order counts for the bottom field of a coded frame, are present in the
1408    /// slice headers for coded frames as specified in clause 7.3.3. Otherwise,
1409    /// specifies that the syntax elements `delta_pic_order_cnt_bottom` and
1410    /// `delta_pic_order_cnt[1]` are not present in the slice headers.
1411    pub bottom_field_pic_order_in_frame_present_flag: bool,
1412
1413    /// Plus 1 specifies the number of slice groups for a picture. When
1414    /// `num_slice_groups_minus1` is equal to 0, all slices of the picture
1415    /// belong to the same slice group. The allowed range of
1416    /// `num_slice_groups_minus1` is specified in Annex A.
1417    pub num_slice_groups_minus1: u32,
1418
1419    /// Specifies how `num_ref_idx_l0_active_minus1` is inferred for P, SP, and
1420    /// B slices with `num_ref_idx_active_override_flag` not set.
1421    pub num_ref_idx_l0_default_active_minus1: u8,
1422
1423    /// Specifies how `num_ref_idx_l1_active_minus1` is inferred for B slices
1424    /// with `num_ref_idx_active_override_flag` not set.
1425    pub num_ref_idx_l1_default_active_minus1: u8,
1426
1427    /// If not set, specifies that the default weighted prediction shall be
1428    /// applied to P and SP slices. If set, specifies that explicit weighted
1429    /// prediction shall be applied to P and SP slices.
1430    pub weighted_pred_flag: bool,
1431
1432    /// `weighted_bipred_idc` equal to 0 specifies that the default weighted
1433    /// prediction shall be applied to B slices. `weighted_bipred_idc` equal to
1434    /// 1 specifies that explicit weighted prediction shall be applied to B
1435    /// slices. `weighted_bipred_idc` equal to 2 specifies that implicit
1436    /// weighted prediction shall be applied to B slices
1437    pub weighted_bipred_idc: u8,
1438
1439    /// Specifies the initial value minus 26 of SliceQPY for each slice. The
1440    /// initial value is modified at the slice layer when a non-zero value of
1441    /// `slice_qp_delta` is decoded, and is modified further when a non-zero
1442    /// value of `mb_qp_delta` is decoded at the macroblock layer.
1443    pub pic_init_qp_minus26: i8,
1444
1445    /// Specifies the initial value minus 26 of SliceQSY for all macroblocks in
1446    /// SP or SI slices. The initial value is modified at the slice layer when a
1447    /// non-zero value of `slice_qs_delta` is decoded.
1448    pub pic_init_qs_minus26: i8,
1449
1450    /// Specifies the offset that shall be added to QP Y and QSY for addressing
1451    /// the table of QPC values for the Cb chroma component.
1452    pub chroma_qp_index_offset: i8,
1453
1454    /// If set, specifies that a set of syntax elements controlling the
1455    /// characteristics of the deblocking filter is present in the slice header.
1456    /// If not set, specifies that the set of syntax elements controlling the
1457    /// characteristics of the deblocking filter is not present in the slice
1458    /// headers and their inferred values are in effect.
1459    pub deblocking_filter_control_present_flag: bool,
1460
1461    /// If not set, specifies that intra prediction allows usage of residual
1462    /// data and decoded samples of neighbouring macroblocks coded using Inter
1463    /// macroblock prediction modes for the prediction of macroblocks coded
1464    /// using Intra macroblock prediction modes. If set, specifies constrained
1465    /// intra prediction, in which case prediction of macroblocks coded using
1466    /// Intra macroblock prediction modes only uses residual data and decoded
1467    /// samples from I or SI macroblock types.
1468    pub constrained_intra_pred_flag: bool,
1469
1470    /// If not set, specifies that the `redundant_pic_cnt` syntax element is not
1471    /// present in slice headers, coded slice data partition B NAL units, and
1472    /// coded slice data partition C NAL units that refer (either directly or by
1473    /// association with a corresponding coded slice data partition A NAL unit)
1474    /// to the picture parameter set. If set, specifies that the
1475    /// `redundant_pic_cnt` syntax element is present in all slice headers,
1476    /// coded slice data partition B NAL units, and coded slice data partition C
1477    /// NAL units that refer (either directly or by association with a
1478    /// corresponding coded slice data partition A NAL unit) to the picture
1479    /// parameter set.
1480    pub redundant_pic_cnt_present_flag: bool,
1481
1482    /// If set, specifies that the 8x8 transform decoding process may be in use
1483    /// (see clause 8.5). If not set, specifies that the 8x8 transform decoding
1484    /// process is not in use.
1485    pub transform_8x8_mode_flag: bool,
1486
1487    ///  If set, specifies that parameters are present to modify the scaling
1488    ///  lists specified in the sequence parameter set. If not set, specifies
1489    ///  that the scaling lists used for the picture shall be inferred to be
1490    ///  equal to those specified by the sequence parameter set.
1491    pub pic_scaling_matrix_present_flag: bool,
1492
1493    /// 4x4 Scaling list as read with 7.3.2.1.1.1
1494    pub scaling_lists_4x4: [[u8; 16]; 6],
1495    /// 8x8 Scaling list as read with 7.3.2.1.1.1
1496    pub scaling_lists_8x8: [[u8; 64]; 6],
1497
1498    /// Specifies the offset that shall be added to QPY and QSY for addressing
1499    /// the table of QPC values for the Cr chroma component. When
1500    /// `second_chroma_qp_index_offset` is not present, it shall be inferred to be
1501    /// equal to `chroma_qp_index_offset`.
1502    pub second_chroma_qp_index_offset: i8,
1503
1504    /// The SPS referenced by this PPS.
1505    pub sps: Rc<Sps>,
1506}
1507
1508pub struct PpsBuilder(Pps);
1509
1510impl PpsBuilder {
1511    pub fn new(sps: Rc<Sps>) -> Self {
1512        PpsBuilder(Pps {
1513            pic_parameter_set_id: 0,
1514            seq_parameter_set_id: sps.seq_parameter_set_id,
1515            entropy_coding_mode_flag: false,
1516            bottom_field_pic_order_in_frame_present_flag: false,
1517            num_slice_groups_minus1: 0,
1518            num_ref_idx_l0_default_active_minus1: 0,
1519            num_ref_idx_l1_default_active_minus1: 0,
1520            weighted_pred_flag: false,
1521            weighted_bipred_idc: 0,
1522            pic_init_qp_minus26: 0,
1523            pic_init_qs_minus26: 0,
1524            chroma_qp_index_offset: 0,
1525            deblocking_filter_control_present_flag: false,
1526            constrained_intra_pred_flag: false,
1527            redundant_pic_cnt_present_flag: false,
1528            transform_8x8_mode_flag: false,
1529            pic_scaling_matrix_present_flag: false,
1530            scaling_lists_4x4: [[0; 16]; 6],
1531            scaling_lists_8x8: [[0; 64]; 6],
1532            second_chroma_qp_index_offset: 0,
1533            sps,
1534        })
1535    }
1536
1537    pub fn pic_parameter_set_id(mut self, value: u8) -> Self {
1538        self.0.pic_parameter_set_id = value;
1539        self
1540    }
1541
1542    pub fn pic_init_qp_minus26(mut self, value: i8) -> Self {
1543        self.0.pic_init_qp_minus26 = value;
1544        self
1545    }
1546
1547    pub fn pic_init_qp(self, value: u8) -> Self {
1548        self.pic_init_qp_minus26(value as i8 - 26)
1549    }
1550
1551    pub fn deblocking_filter_control_present_flag(mut self, value: bool) -> Self {
1552        self.0.deblocking_filter_control_present_flag = value;
1553        self
1554    }
1555
1556    pub fn num_ref_idx_l0_default_active_minus1(mut self, value: u8) -> Self {
1557        self.0.num_ref_idx_l0_default_active_minus1 = value;
1558        self
1559    }
1560
1561    pub fn num_ref_idx_l0_default_active(self, value: u8) -> Self {
1562        self.num_ref_idx_l0_default_active_minus1(value - 1)
1563    }
1564
1565    pub fn num_ref_idx_l1_default_active_minus1(mut self, value: u8) -> Self {
1566        self.0.num_ref_idx_l1_default_active_minus1 = value;
1567        self
1568    }
1569
1570    pub fn num_ref_idx_l1_default_active(self, value: u8) -> Self {
1571        self.num_ref_idx_l1_default_active_minus1(value - 1)
1572    }
1573
1574    pub fn build(self) -> Rc<Pps> {
1575        Rc::new(self.0)
1576    }
1577}
1578
1579#[derive(Debug, Default)]
1580pub struct Parser {
1581    active_spses: BTreeMap<u8, Rc<Sps>>,
1582    active_ppses: BTreeMap<u8, Rc<Pps>>,
1583}
1584
1585impl Parser {
1586    fn fill_default_scaling_list_4x4(scaling_list4x4: &mut [u8; 16], i: usize) {
1587        // See table 7.2 in the spec.
1588        assert!(i < 6);
1589        if i < 3 {
1590            *scaling_list4x4 = DEFAULT_4X4_INTRA;
1591        } else if i < 6 {
1592            *scaling_list4x4 = DEFAULT_4X4_INTER;
1593        }
1594    }
1595
1596    fn fill_default_scaling_list_8x8(scaling_list8x8: &mut [u8; 64], i: usize) {
1597        assert!(i < 6);
1598        if i % 2 == 0 {
1599            *scaling_list8x8 = DEFAULT_8X8_INTRA;
1600        } else {
1601            *scaling_list8x8 = DEFAULT_8X8_INTER;
1602        }
1603    }
1604
1605    fn fill_fallback_scaling_list_4x4(
1606        scaling_list4x4: &mut [[u8; 16]; 6],
1607        i: usize,
1608        default_scaling_list_intra: &[u8; 16],
1609        default_scaling_list_inter: &[u8; 16],
1610    ) {
1611        // See table 7.2 in the spec.
1612        scaling_list4x4[i] = match i {
1613            0 => *default_scaling_list_intra,
1614            1 => scaling_list4x4[0],
1615            2 => scaling_list4x4[1],
1616            3 => *default_scaling_list_inter,
1617            4 => scaling_list4x4[3],
1618            5 => scaling_list4x4[4],
1619            _ => panic!("Unexpected value {}", i),
1620        }
1621    }
1622
1623    fn fill_fallback_scaling_list_8x8(
1624        scaling_list8x8: &mut [[u8; 64]; 6],
1625        i: usize,
1626        default_scaling_list_intra: &[u8; 64],
1627        default_scaling_list_inter: &[u8; 64],
1628    ) {
1629        // See table 7.2 in the spec.
1630        scaling_list8x8[i] = match i {
1631            0 => *default_scaling_list_intra,
1632            1 => *default_scaling_list_inter,
1633            2 => scaling_list8x8[0],
1634            3 => scaling_list8x8[1],
1635            4 => scaling_list8x8[2],
1636            5 => scaling_list8x8[3],
1637            _ => panic!("Unexpected value {}", i),
1638        }
1639    }
1640
1641    fn fill_scaling_list_flat(
1642        scaling_list4x4: &mut [[u8; 16]; 6],
1643        scaling_list8x8: &mut [[u8; 64]; 6],
1644    ) {
1645        // (7-8) in the spec.
1646        for outer in scaling_list4x4 {
1647            for inner in outer {
1648                *inner = 16;
1649            }
1650        }
1651
1652        // (7-9) in the spec.
1653        for outer in scaling_list8x8 {
1654            for inner in outer {
1655                *inner = 16;
1656            }
1657        }
1658    }
1659
1660    fn parse_scaling_list<U: AsMut<[u8]>>(
1661        r: &mut NaluReader,
1662        scaling_list: &mut U,
1663        use_default: &mut bool,
1664    ) -> anyhow::Result<()> {
1665        // 7.3.2.1.1.1
1666        let mut last_scale = 8u8;
1667        let mut next_scale = 8u8;
1668
1669        for j in 0..scaling_list.as_mut().len() {
1670            if next_scale != 0 {
1671                let delta_scale = r.read_se::<i32>()?;
1672                next_scale = ((last_scale as i32 + delta_scale + 256) % 256) as u8;
1673                *use_default = j == 0 && next_scale == 0;
1674                if *use_default {
1675                    return Ok(());
1676                }
1677            }
1678
1679            scaling_list.as_mut()[j] = if next_scale == 0 {
1680                last_scale
1681            } else {
1682                next_scale
1683            };
1684
1685            last_scale = scaling_list.as_mut()[j];
1686        }
1687
1688        Ok(())
1689    }
1690
1691    fn parse_sps_scaling_lists(r: &mut NaluReader, sps: &mut Sps) -> anyhow::Result<()> {
1692        let scaling_lists4x4 = &mut sps.scaling_lists_4x4;
1693        let scaling_lisst8x8 = &mut sps.scaling_lists_8x8;
1694
1695        // Parse scaling_list4x4
1696        for i in 0..6 {
1697            let seq_scaling_list_present_flag = r.read_bit()?;
1698            if seq_scaling_list_present_flag {
1699                let mut use_default = false;
1700
1701                Parser::parse_scaling_list(r, &mut scaling_lists4x4[i], &mut use_default)?;
1702
1703                if use_default {
1704                    Parser::fill_default_scaling_list_4x4(&mut scaling_lists4x4[i], i);
1705                }
1706            } else {
1707                Parser::fill_fallback_scaling_list_4x4(
1708                    scaling_lists4x4,
1709                    i,
1710                    &DEFAULT_4X4_INTRA,
1711                    &DEFAULT_4X4_INTER,
1712                );
1713            }
1714        }
1715
1716        // Parse scaling_list8x8
1717        let num_8x8 = if sps.chroma_format_idc != 3 { 2 } else { 6 };
1718        for i in 0..num_8x8 {
1719            let seq_scaling_list_present_flag = r.read_bit()?;
1720            if seq_scaling_list_present_flag {
1721                let mut use_default = false;
1722                Parser::parse_scaling_list(r, &mut scaling_lisst8x8[i], &mut use_default)?;
1723
1724                if use_default {
1725                    Parser::fill_default_scaling_list_8x8(&mut scaling_lisst8x8[i], i);
1726                }
1727            } else {
1728                Parser::fill_fallback_scaling_list_8x8(
1729                    scaling_lisst8x8,
1730                    i,
1731                    &DEFAULT_8X8_INTRA,
1732                    &DEFAULT_8X8_INTER,
1733                );
1734            }
1735        }
1736        Ok(())
1737    }
1738
1739    fn parse_pps_scaling_lists(r: &mut NaluReader, pps: &mut Pps, sps: &Sps) -> anyhow::Result<()> {
1740        let scaling_lists4x4 = &mut pps.scaling_lists_4x4;
1741        let scaling_lists8x8 = &mut pps.scaling_lists_8x8;
1742
1743        for i in 0..6 {
1744            let pic_scaling_list_present_flag = r.read_bit()?;
1745            if pic_scaling_list_present_flag {
1746                let mut use_default = false;
1747
1748                Parser::parse_scaling_list(r, &mut scaling_lists4x4[i], &mut use_default)?;
1749
1750                if use_default {
1751                    Parser::fill_default_scaling_list_4x4(&mut scaling_lists4x4[i], i);
1752                }
1753            } else if !sps.seq_scaling_matrix_present_flag {
1754                // Table 7-2: Fallback rule A
1755                Parser::fill_fallback_scaling_list_4x4(
1756                    scaling_lists4x4,
1757                    i,
1758                    &DEFAULT_4X4_INTRA,
1759                    &DEFAULT_4X4_INTER,
1760                );
1761            } else {
1762                // Table 7-2: Fallback rule B
1763                Parser::fill_fallback_scaling_list_4x4(
1764                    scaling_lists4x4,
1765                    i,
1766                    &sps.scaling_lists_4x4[0],
1767                    &sps.scaling_lists_4x4[3],
1768                );
1769            }
1770        }
1771
1772        if pps.transform_8x8_mode_flag {
1773            let num8x8 = if sps.chroma_format_idc != 3 { 2 } else { 6 };
1774
1775            for i in 0..num8x8 {
1776                let pic_scaling_list_present_flag = r.read_bit()?;
1777                if pic_scaling_list_present_flag {
1778                    let mut use_default = false;
1779
1780                    Parser::parse_scaling_list(r, &mut scaling_lists8x8[i], &mut use_default)?;
1781
1782                    if use_default {
1783                        Parser::fill_default_scaling_list_4x4(&mut scaling_lists4x4[i], i);
1784                    }
1785                } else if !sps.seq_scaling_matrix_present_flag {
1786                    // Table 7-2: Fallback rule A
1787                    Parser::fill_fallback_scaling_list_8x8(
1788                        scaling_lists8x8,
1789                        i,
1790                        &DEFAULT_8X8_INTRA,
1791                        &DEFAULT_8X8_INTER,
1792                    );
1793                } else {
1794                    // Table 7-2: Fallback rule B
1795                    Parser::fill_fallback_scaling_list_8x8(
1796                        scaling_lists8x8,
1797                        i,
1798                        &sps.scaling_lists_8x8[0],
1799                        &sps.scaling_lists_8x8[1],
1800                    );
1801                }
1802            }
1803        }
1804
1805        Ok(())
1806    }
1807
1808    fn parse_hrd(r: &mut NaluReader, hrd: &mut HrdParams) -> anyhow::Result<()> {
1809        hrd.cpb_cnt_minus1 = r.read_ue_max(31)?;
1810        hrd.bit_rate_scale = r.read_bits(4)?;
1811        hrd.cpb_size_scale = r.read_bits(4)?;
1812
1813        for sched_sel_idx in 0..=usize::from(hrd.cpb_cnt_minus1) {
1814            hrd.bit_rate_value_minus1[sched_sel_idx] = r.read_ue()?;
1815            hrd.cpb_size_value_minus1[sched_sel_idx] = r.read_ue()?;
1816            hrd.cbr_flag[sched_sel_idx] = r.read_bit()?;
1817        }
1818
1819        hrd.initial_cpb_removal_delay_length_minus1 = r.read_bits(5)?;
1820        hrd.cpb_removal_delay_length_minus1 = r.read_bits(5)?;
1821        hrd.dpb_output_delay_length_minus1 = r.read_bits(5)?;
1822        hrd.time_offset_length = r.read_bits(5)?;
1823        Ok(())
1824    }
1825
1826    fn parse_vui(r: &mut NaluReader, sps: &mut Sps) -> anyhow::Result<()> {
1827        let vui = &mut sps.vui_parameters;
1828
1829        vui.aspect_ratio_info_present_flag = r.read_bit()?;
1830        if vui.aspect_ratio_info_present_flag {
1831            vui.aspect_ratio_idc = r.read_bits(8)?;
1832            if vui.aspect_ratio_idc == 255 {
1833                vui.sar_width = r.read_bits(16)?;
1834                vui.sar_height = r.read_bits(16)?;
1835            }
1836        }
1837
1838        vui.overscan_info_present_flag = r.read_bit()?;
1839        if vui.overscan_info_present_flag {
1840            vui.overscan_appropriate_flag = r.read_bit()?;
1841        }
1842
1843        vui.video_signal_type_present_flag = r.read_bit()?;
1844        if vui.video_signal_type_present_flag {
1845            vui.video_format = r.read_bits(3)?;
1846            vui.video_full_range_flag = r.read_bit()?;
1847            vui.colour_description_present_flag = r.read_bit()?;
1848            if vui.colour_description_present_flag {
1849                vui.colour_primaries = r.read_bits(8)?;
1850                vui.transfer_characteristics = r.read_bits(8)?;
1851                vui.matrix_coefficients = r.read_bits(8)?;
1852            }
1853        }
1854
1855        vui.chroma_loc_info_present_flag = r.read_bit()?;
1856        if vui.chroma_loc_info_present_flag {
1857            vui.chroma_sample_loc_type_top_field = r.read_ue_max(5)?;
1858            vui.chroma_sample_loc_type_bottom_field = r.read_ue_max(5)?;
1859        }
1860
1861        vui.timing_info_present_flag = r.read_bit()?;
1862        if vui.timing_info_present_flag {
1863            vui.num_units_in_tick = r.read_bits::<u32>(31)? << 1;
1864            vui.num_units_in_tick |= r.read_bit()? as u32;
1865            if vui.num_units_in_tick == 0 {
1866                return Err(anyhow!(
1867                    "num_units_in_tick == 0, which is not allowed by E.2.1"
1868                ));
1869            }
1870
1871            vui.time_scale = r.read_bits::<u32>(31)? << 1;
1872            vui.time_scale |= r.read_bit()? as u32;
1873            if vui.time_scale == 0 {
1874                return Err(anyhow!("time_scale == 0, which is not allowed by E.2.1"));
1875            }
1876
1877            vui.fixed_frame_rate_flag = r.read_bit()?;
1878        }
1879
1880        vui.nal_hrd_parameters_present_flag = r.read_bit()?;
1881        if vui.nal_hrd_parameters_present_flag {
1882            Parser::parse_hrd(r, &mut vui.nal_hrd_parameters)?;
1883        }
1884
1885        vui.vcl_hrd_parameters_present_flag = r.read_bit()?;
1886        if vui.vcl_hrd_parameters_present_flag {
1887            Parser::parse_hrd(r, &mut vui.vcl_hrd_parameters)?;
1888        }
1889
1890        if vui.nal_hrd_parameters_present_flag || vui.vcl_hrd_parameters_present_flag {
1891            vui.low_delay_hrd_flag = r.read_bit()?;
1892        }
1893
1894        vui.pic_struct_present_flag = r.read_bit()?;
1895        vui.bitstream_restriction_flag = r.read_bit()?;
1896
1897        if vui.bitstream_restriction_flag {
1898            vui.motion_vectors_over_pic_boundaries_flag = r.read_bit()?;
1899            vui.max_bytes_per_pic_denom = r.read_ue()?;
1900            vui.max_bits_per_mb_denom = r.read_ue_max(16)?;
1901            vui.log2_max_mv_length_horizontal = r.read_ue_max(16)?;
1902            vui.log2_max_mv_length_vertical = r.read_ue_max(16)?;
1903            vui.max_num_reorder_frames = r.read_ue()?;
1904            vui.max_dec_frame_buffering = r.read_ue()?;
1905        }
1906
1907        Ok(())
1908    }
1909
1910    /// Parse a SPS and add it to the list of active SPSes.
1911    ///
1912    /// Returns a reference to the new SPS.
1913    pub fn parse_sps(&mut self, nalu: &Nalu) -> anyhow::Result<&Rc<Sps>> {
1914        if !matches!(nalu.header.type_, NaluType::Sps) {
1915            return Err(anyhow!(
1916                "Invalid NALU type, expected {:?}, got {:?}",
1917                NaluType::Sps,
1918                nalu.header.type_
1919            ));
1920        }
1921
1922        let data = nalu.as_ref();
1923        // Skip the header
1924        let mut r = NaluReader::new(&data[nalu.header.len()..]);
1925        let mut sps = Sps {
1926            profile_idc: r.read_bits(8)?,
1927            constraint_set0_flag: r.read_bit()?,
1928            constraint_set1_flag: r.read_bit()?,
1929            constraint_set2_flag: r.read_bit()?,
1930            constraint_set3_flag: r.read_bit()?,
1931            constraint_set4_flag: r.read_bit()?,
1932            constraint_set5_flag: r.read_bit()?,
1933            ..Default::default()
1934        };
1935
1936        // skip reserved_zero_2bits
1937        r.skip_bits(2)?;
1938
1939        let level: u8 = r.read_bits(8)?;
1940        sps.level_idc = Level::n(level).with_context(|| format!("Unsupported level {}", level))?;
1941        sps.seq_parameter_set_id = r.read_ue_max(31)?;
1942
1943        if sps.profile_idc == 100
1944            || sps.profile_idc == 110
1945            || sps.profile_idc == 122
1946            || sps.profile_idc == 244
1947            || sps.profile_idc == 44
1948            || sps.profile_idc == 83
1949            || sps.profile_idc == 86
1950            || sps.profile_idc == 118
1951            || sps.profile_idc == 128
1952            || sps.profile_idc == 138
1953            || sps.profile_idc == 139
1954            || sps.profile_idc == 134
1955            || sps.profile_idc == 135
1956        {
1957            sps.chroma_format_idc = r.read_ue_max(3)?;
1958            if sps.chroma_format_idc == 3 {
1959                sps.separate_colour_plane_flag = r.read_bit()?;
1960            }
1961
1962            sps.bit_depth_luma_minus8 = r.read_ue_max(6)?;
1963            sps.bit_depth_chroma_minus8 = r.read_ue_max(6)?;
1964            sps.qpprime_y_zero_transform_bypass_flag = r.read_bit()?;
1965            sps.seq_scaling_matrix_present_flag = r.read_bit()?;
1966
1967            if sps.seq_scaling_matrix_present_flag {
1968                Parser::parse_sps_scaling_lists(&mut r, &mut sps)?;
1969            } else {
1970                Parser::fill_scaling_list_flat(
1971                    &mut sps.scaling_lists_4x4,
1972                    &mut sps.scaling_lists_8x8,
1973                );
1974            }
1975        } else {
1976            sps.chroma_format_idc = 1;
1977            Parser::fill_scaling_list_flat(&mut sps.scaling_lists_4x4, &mut sps.scaling_lists_8x8);
1978        }
1979
1980        sps.log2_max_frame_num_minus4 = r.read_ue_max(12)?;
1981
1982        sps.pic_order_cnt_type = r.read_ue_max(2)?;
1983
1984        if sps.pic_order_cnt_type == 0 {
1985            sps.log2_max_pic_order_cnt_lsb_minus4 = r.read_ue_max(12)?;
1986            sps.expected_delta_per_pic_order_cnt_cycle = 0;
1987        } else if sps.pic_order_cnt_type == 1 {
1988            sps.delta_pic_order_always_zero_flag = r.read_bit()?;
1989            sps.offset_for_non_ref_pic = r.read_se()?;
1990            sps.offset_for_top_to_bottom_field = r.read_se()?;
1991            sps.num_ref_frames_in_pic_order_cnt_cycle = r.read_ue_max(254)?;
1992
1993            let mut offset_acc = 0;
1994            for i in 0..usize::from(sps.num_ref_frames_in_pic_order_cnt_cycle) {
1995                sps.offset_for_ref_frame[i] = r.read_se()?;
1996
1997                // (7-12) in the spec.
1998                offset_acc += sps.offset_for_ref_frame[i];
1999            }
2000
2001            sps.expected_delta_per_pic_order_cnt_cycle = offset_acc;
2002        }
2003
2004        sps.max_num_ref_frames = r.read_ue_max(DPB_MAX_SIZE as u32)?;
2005        sps.gaps_in_frame_num_value_allowed_flag = r.read_bit()?;
2006        sps.pic_width_in_mbs_minus1 = r.read_ue()?;
2007        sps.pic_height_in_map_units_minus1 = r.read_ue()?;
2008        sps.frame_mbs_only_flag = r.read_bit()?;
2009
2010        if !sps.frame_mbs_only_flag {
2011            sps.mb_adaptive_frame_field_flag = r.read_bit()?;
2012        }
2013
2014        sps.direct_8x8_inference_flag = r.read_bit()?;
2015        sps.frame_cropping_flag = r.read_bit()?;
2016
2017        if sps.frame_cropping_flag {
2018            sps.frame_crop_left_offset = r.read_ue()?;
2019            sps.frame_crop_right_offset = r.read_ue()?;
2020            sps.frame_crop_top_offset = r.read_ue()?;
2021            sps.frame_crop_bottom_offset = r.read_ue()?;
2022
2023            // Validate that cropping info is valid.
2024            let (crop_unit_x, crop_unit_y) = sps.crop_unit_x_y();
2025
2026            let _ = sps
2027                .frame_crop_left_offset
2028                .checked_add(sps.frame_crop_right_offset)
2029                .and_then(|r| r.checked_mul(crop_unit_x))
2030                .and_then(|r| sps.width().checked_sub(r))
2031                .ok_or(anyhow!("Invalid frame crop width"))?;
2032
2033            let _ = sps
2034                .frame_crop_top_offset
2035                .checked_add(sps.frame_crop_bottom_offset)
2036                .and_then(|r| r.checked_mul(crop_unit_y))
2037                .and_then(|r| sps.height().checked_sub(r))
2038                .ok_or(anyhow!("invalid frame crop height"))?;
2039        }
2040
2041        sps.vui_parameters_present_flag = r.read_bit()?;
2042        if sps.vui_parameters_present_flag {
2043            Parser::parse_vui(&mut r, &mut sps)?;
2044        }
2045
2046        let key = sps.seq_parameter_set_id;
2047
2048        if self.active_spses.keys().len() >= MAX_SPS_COUNT as usize {
2049            return Err(anyhow!(
2050                "Broken data: Number of active SPSs > MAX_SPS_COUNT"
2051            ));
2052        }
2053
2054        let sps = Rc::new(sps);
2055        self.active_spses.remove(&key);
2056        Ok(self.active_spses.entry(key).or_insert(sps))
2057    }
2058
2059    pub fn parse_pps(&mut self, nalu: &Nalu) -> anyhow::Result<&Pps> {
2060        if !matches!(nalu.header.type_, NaluType::Pps) {
2061            return Err(anyhow!(
2062                "Invalid NALU type, expected {:?}, got {:?}",
2063                NaluType::Pps,
2064                nalu.header.type_
2065            ));
2066        }
2067
2068        let data = nalu.as_ref();
2069        // Skip the header
2070        let mut r = NaluReader::new(&data[nalu.header.len()..]);
2071        let pic_parameter_set_id = r.read_ue_max(MAX_PPS_COUNT as u32 - 1)?;
2072        let seq_parameter_set_id = r.read_ue_max(MAX_SPS_COUNT as u32 - 1)?;
2073        let sps = self.get_sps(seq_parameter_set_id).context(
2074            "Broken stream: stream references a SPS that has not been successfully parsed",
2075        )?;
2076        let mut pps = Pps {
2077            pic_parameter_set_id,
2078            seq_parameter_set_id,
2079            sps: Rc::clone(sps),
2080            scaling_lists_4x4: [[0; 16]; 6],
2081            scaling_lists_8x8: [[0; 64]; 6],
2082            entropy_coding_mode_flag: Default::default(),
2083            bottom_field_pic_order_in_frame_present_flag: Default::default(),
2084            num_slice_groups_minus1: Default::default(),
2085            num_ref_idx_l0_default_active_minus1: Default::default(),
2086            num_ref_idx_l1_default_active_minus1: Default::default(),
2087            weighted_pred_flag: Default::default(),
2088            weighted_bipred_idc: Default::default(),
2089            pic_init_qp_minus26: Default::default(),
2090            pic_init_qs_minus26: Default::default(),
2091            chroma_qp_index_offset: Default::default(),
2092            deblocking_filter_control_present_flag: Default::default(),
2093            constrained_intra_pred_flag: Default::default(),
2094            redundant_pic_cnt_present_flag: Default::default(),
2095            transform_8x8_mode_flag: Default::default(),
2096            second_chroma_qp_index_offset: Default::default(),
2097            pic_scaling_matrix_present_flag: Default::default(),
2098        };
2099
2100        pps.entropy_coding_mode_flag = r.read_bit()?;
2101        pps.bottom_field_pic_order_in_frame_present_flag = r.read_bit()?;
2102        pps.num_slice_groups_minus1 = r.read_ue_max(7)?;
2103
2104        if pps.num_slice_groups_minus1 > 0 {
2105            return Err(anyhow!("Stream contain unsupported/unimplemented NALs"));
2106        }
2107
2108        pps.num_ref_idx_l0_default_active_minus1 = r.read_ue_max(31)?;
2109        pps.num_ref_idx_l1_default_active_minus1 = r.read_ue_max(31)?;
2110
2111        pps.weighted_pred_flag = r.read_bit()?;
2112        pps.weighted_bipred_idc = r.read_bits(2)?;
2113
2114        let qp_bd_offset_y = i32::from(6 * (sps.bit_depth_luma_minus8));
2115        pps.pic_init_qp_minus26 = r.read_se_bounded(-(26 + qp_bd_offset_y), 25)?;
2116        pps.pic_init_qs_minus26 = r.read_se_bounded(-26, 25)?;
2117
2118        pps.chroma_qp_index_offset = r.read_se_bounded(-12, 12)?;
2119
2120        // When second_chroma_qp_index_offset is not present, it shall be
2121        // inferred to be equal to chroma_qp_index_offset.
2122        pps.second_chroma_qp_index_offset = pps.chroma_qp_index_offset;
2123
2124        pps.deblocking_filter_control_present_flag = r.read_bit()?;
2125        pps.constrained_intra_pred_flag = r.read_bit()?;
2126        pps.redundant_pic_cnt_present_flag = r.read_bit()?;
2127
2128        if r.has_more_rsbp_data() {
2129            pps.transform_8x8_mode_flag = r.read_bit()?;
2130            pps.pic_scaling_matrix_present_flag = r.read_bit()?;
2131
2132            if pps.pic_scaling_matrix_present_flag {
2133                Parser::parse_pps_scaling_lists(&mut r, &mut pps, sps)?;
2134            }
2135
2136            pps.second_chroma_qp_index_offset = r.read_se()?;
2137        }
2138
2139        if !pps.pic_scaling_matrix_present_flag {
2140            // If not set, specifies that the scaling lists used for the picture
2141            // shall be inferred to be equal to those specified by the sequence
2142            // parameter set. When pic_scaling_matrix_present_flag is not
2143            // present, it shall be inferred to be not set.
2144            pps.scaling_lists_4x4 = sps.scaling_lists_4x4;
2145            pps.scaling_lists_8x8 = sps.scaling_lists_8x8;
2146        }
2147
2148        let key = pps.pic_parameter_set_id;
2149
2150        if self.active_ppses.keys().len() >= MAX_PPS_COUNT as usize {
2151            return Err(anyhow!(
2152                "Broken Data: number of active PPSs > MAX_PPS_COUNT"
2153            ));
2154        }
2155
2156        let pps = Rc::new(pps);
2157        self.active_ppses.remove(&key);
2158        Ok(self.active_ppses.entry(key).or_insert(pps))
2159    }
2160
2161    fn parse_ref_pic_list_modification(
2162        r: &mut NaluReader,
2163        num_ref_idx_active_minus1: u8,
2164        ref_list_mods: &mut Vec<RefPicListModification>,
2165    ) -> anyhow::Result<()> {
2166        if num_ref_idx_active_minus1 >= 32 {
2167            return Err(anyhow!("Broken Data: num_ref_idx_active_minus1 >= 32"));
2168        }
2169
2170        loop {
2171            let mut pic_num_mod = RefPicListModification {
2172                modification_of_pic_nums_idc: r.read_ue_max(3)?,
2173                ..Default::default()
2174            };
2175
2176            match pic_num_mod.modification_of_pic_nums_idc {
2177                0 | 1 => {
2178                    pic_num_mod.abs_diff_pic_num_minus1 = r.read_ue()?;
2179                }
2180
2181                2 => {
2182                    pic_num_mod.long_term_pic_num = r.read_ue()?;
2183                }
2184
2185                3 => {
2186                    ref_list_mods.push(pic_num_mod);
2187                    break;
2188                }
2189
2190                _ => return Err(anyhow!("Broken Data: modification_of_pic_nums_idc > 3")),
2191            }
2192
2193            ref_list_mods.push(pic_num_mod);
2194        }
2195
2196        Ok(())
2197    }
2198
2199    fn parse_ref_pic_list_modifications(
2200        r: &mut NaluReader,
2201        header: &mut SliceHeader,
2202    ) -> anyhow::Result<()> {
2203        if !header.slice_type.is_i() && !header.slice_type.is_si() {
2204            header.ref_pic_list_modification_flag_l0 = r.read_bit()?;
2205            if header.ref_pic_list_modification_flag_l0 {
2206                Parser::parse_ref_pic_list_modification(
2207                    r,
2208                    header.num_ref_idx_l0_active_minus1,
2209                    &mut header.ref_pic_list_modification_l0,
2210                )?;
2211            }
2212        }
2213
2214        if header.slice_type.is_b() {
2215            header.ref_pic_list_modification_flag_l1 = r.read_bit()?;
2216            if header.ref_pic_list_modification_flag_l1 {
2217                Parser::parse_ref_pic_list_modification(
2218                    r,
2219                    header.num_ref_idx_l1_active_minus1,
2220                    &mut header.ref_pic_list_modification_l1,
2221                )?;
2222            }
2223        }
2224
2225        Ok(())
2226    }
2227
2228    fn parse_pred_weight_table(
2229        r: &mut NaluReader,
2230        sps: &Sps,
2231        header: &mut SliceHeader,
2232    ) -> anyhow::Result<()> {
2233        let pt = &mut header.pred_weight_table;
2234        pt.luma_log2_weight_denom = r.read_ue_max(7)?;
2235
2236        // When luma_weight_l0_flag is equal to 0, luma_weight_l0[i] shall be
2237        // inferred to be equal to 2 ^ luma_log2_weight_denom for
2238        // RefPicList0[i].
2239        let default_luma_weight = 1 << pt.luma_log2_weight_denom;
2240        for i in 0..=header.num_ref_idx_l0_active_minus1 {
2241            pt.luma_weight_l0[usize::from(i)] = default_luma_weight;
2242        }
2243
2244        // When luma_weight_l1_flag is equal to 1, luma_weight_l1[i] shall be
2245        // inferred to be equal to 2 ^ luma_log2_weight_denom for
2246        // RefPicList1[i].
2247        if header.slice_type.is_b() {
2248            for i in 0..=header.num_ref_idx_l1_active_minus1 {
2249                pt.luma_weight_l1[usize::from(i)] = default_luma_weight;
2250            }
2251        }
2252
2253        if sps.chroma_array_type() != 0 {
2254            pt.chroma_log2_weight_denom = r.read_ue_max(7)?;
2255            let default_chroma_weight = 1 << pt.chroma_log2_weight_denom;
2256
2257            // When chroma_weight_l0_flag is equal to 0, chroma_weight_l0[i]
2258            // shall be inferred to be equal to 2 ^ chroma_log2_weight_denom for
2259            // RefPicList0[i].
2260            for i in 0..=header.num_ref_idx_l0_active_minus1 {
2261                pt.chroma_weight_l0[usize::from(i)][0] = default_chroma_weight;
2262                pt.chroma_weight_l0[usize::from(i)][1] = default_chroma_weight;
2263            }
2264
2265            // When chroma_weight_l1_flag is equal to 0, chroma_weight_l1[i]
2266            // shall be inferred to be equal to 2 ^ chroma_log2_weight_denom for
2267            // RefPicList1[i].
2268            for i in 0..=header.num_ref_idx_l1_active_minus1 {
2269                pt.chroma_weight_l1[usize::from(i)][0] = default_chroma_weight;
2270                pt.chroma_weight_l1[usize::from(i)][1] = default_chroma_weight;
2271            }
2272        }
2273
2274        for i in 0..=header.num_ref_idx_l0_active_minus1 {
2275            let luma_weight_l0_flag = r.read_bit()?;
2276
2277            if luma_weight_l0_flag {
2278                pt.luma_weight_l0[usize::from(i)] = r.read_se_bounded(-128, 127)?;
2279                pt.luma_offset_l0[usize::from(i)] = r.read_se_bounded(-128, 127)?;
2280            }
2281
2282            if sps.chroma_array_type() != 0 {
2283                let chroma_weight_l0_flag = r.read_bit()?;
2284                if chroma_weight_l0_flag {
2285                    for j in 0..2 {
2286                        pt.chroma_weight_l0[usize::from(i)][j] = r.read_se_bounded(-128, 127)?;
2287                        pt.chroma_offset_l0[usize::from(i)][j] = r.read_se_bounded(-128, 127)?;
2288                    }
2289                }
2290            }
2291        }
2292
2293        if header.slice_type.is_b() {
2294            for i in 0..=header.num_ref_idx_l1_active_minus1 {
2295                let luma_weight_l1_flag = r.read_bit()?;
2296
2297                if luma_weight_l1_flag {
2298                    pt.luma_weight_l1[usize::from(i)] = r.read_se_bounded(-128, 127)?;
2299                    pt.luma_offset_l1[usize::from(i)] = r.read_se_bounded(-128, 127)?;
2300                }
2301
2302                if sps.chroma_array_type() != 0 {
2303                    let chroma_weight_l1_flag = r.read_bit()?;
2304                    if chroma_weight_l1_flag {
2305                        for j in 0..2 {
2306                            pt.chroma_weight_l1[usize::from(i)][j] =
2307                                r.read_se_bounded(-128, 127)?;
2308                            pt.chroma_offset_l1[usize::from(i)][j] =
2309                                r.read_se_bounded(-128, 127)?;
2310                        }
2311                    }
2312                }
2313            }
2314        }
2315
2316        Ok(())
2317    }
2318
2319    fn parse_dec_ref_pic_marking(
2320        r: &mut NaluReader,
2321        nalu: &Nalu,
2322        header: &mut SliceHeader,
2323    ) -> anyhow::Result<()> {
2324        let rpm = &mut header.dec_ref_pic_marking;
2325
2326        if nalu.header.idr_pic_flag {
2327            rpm.no_output_of_prior_pics_flag = r.read_bit()?;
2328            rpm.long_term_reference_flag = r.read_bit()?;
2329        } else {
2330            rpm.adaptive_ref_pic_marking_mode_flag = r.read_bit()?;
2331
2332            if rpm.adaptive_ref_pic_marking_mode_flag {
2333                loop {
2334                    let mut marking = RefPicMarkingInner::default();
2335
2336                    let mem_mgmt_ctrl_op = r.read_ue_max::<u8>(6)?;
2337                    marking.memory_management_control_operation = mem_mgmt_ctrl_op;
2338
2339                    if mem_mgmt_ctrl_op == 0 {
2340                        break;
2341                    }
2342
2343                    if mem_mgmt_ctrl_op == 1 || mem_mgmt_ctrl_op == 3 {
2344                        marking.difference_of_pic_nums_minus1 = r.read_ue()?;
2345                    }
2346
2347                    if mem_mgmt_ctrl_op == 2 {
2348                        marking.long_term_pic_num = r.read_ue()?;
2349                    }
2350
2351                    if mem_mgmt_ctrl_op == 3 || mem_mgmt_ctrl_op == 6 {
2352                        marking.long_term_frame_idx = r.read_ue()?;
2353                    }
2354
2355                    if mem_mgmt_ctrl_op == 4 {
2356                        marking.max_long_term_frame_idx =
2357                            MaxLongTermFrameIdx::from_value_plus1(r.read_ue()?);
2358                    }
2359
2360                    rpm.inner.push(marking);
2361                }
2362            }
2363        }
2364
2365        Ok(())
2366    }
2367
2368    pub fn parse_slice_header<'a>(&self, nalu: Nalu<'a>) -> anyhow::Result<Slice<'a>> {
2369        if !matches!(
2370            nalu.header.type_,
2371            NaluType::Slice
2372                | NaluType::SliceDpa
2373                | NaluType::SliceDpb
2374                | NaluType::SliceDpc
2375                | NaluType::SliceIdr
2376                | NaluType::SliceExt
2377        ) {
2378            return Err(anyhow!(
2379                "Invalid NALU type: {:?} is not a slice NALU",
2380                nalu.header.type_
2381            ));
2382        }
2383
2384        let data = nalu.as_ref();
2385        // Skip the header
2386        let mut r = NaluReader::new(&data[nalu.header.len()..]);
2387
2388        let mut header = SliceHeader {
2389            first_mb_in_slice: r.read_ue()?,
2390            ..Default::default()
2391        };
2392
2393        let slice_type = r.read_ue_max::<u8>(9)? % 5;
2394        header.slice_type = SliceType::n(slice_type)
2395            .with_context(|| format!("Invalid slice type {}", slice_type))?;
2396
2397        header.pic_parameter_set_id = r.read_ue()?;
2398
2399        let pps = self.get_pps(header.pic_parameter_set_id).context(
2400            "Broken stream: slice references PPS that has not been successfully parsed.",
2401        )?;
2402
2403        let sps = &pps.sps;
2404
2405        if sps.separate_colour_plane_flag {
2406            header.colour_plane_id = r.read_bits(2)?;
2407        }
2408
2409        header.frame_num = r.read_bits(usize::from(sps.log2_max_frame_num_minus4) + 4)?;
2410
2411        if !sps.frame_mbs_only_flag {
2412            header.field_pic_flag = r.read_bit()?;
2413            if header.field_pic_flag {
2414                header.bottom_field_flag = r.read_bit()?;
2415            }
2416        }
2417
2418        if header.field_pic_flag {
2419            header.max_pic_num = 2 * sps.max_frame_num();
2420        } else {
2421            header.max_pic_num = sps.max_frame_num();
2422        }
2423
2424        if nalu.header.idr_pic_flag {
2425            header.idr_pic_id = r.read_ue_max(0xffff)?;
2426        }
2427
2428        if sps.pic_order_cnt_type == 0 {
2429            header.pic_order_cnt_lsb =
2430                r.read_bits(usize::from(sps.log2_max_pic_order_cnt_lsb_minus4) + 4)?;
2431
2432            if pps.bottom_field_pic_order_in_frame_present_flag && !header.field_pic_flag {
2433                header.delta_pic_order_cnt_bottom = r.read_se()?;
2434            }
2435        }
2436
2437        if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero_flag {
2438            header.delta_pic_order_cnt[0] = r.read_se()?;
2439            if pps.bottom_field_pic_order_in_frame_present_flag && !header.field_pic_flag {
2440                header.delta_pic_order_cnt[1] = r.read_se()?;
2441            }
2442        }
2443
2444        if pps.redundant_pic_cnt_present_flag {
2445            header.redundant_pic_cnt = r.read_ue_max(127)?;
2446        }
2447
2448        if header.slice_type.is_b() {
2449            header.direct_spatial_mv_pred_flag = r.read_bit()?;
2450        }
2451
2452        if header.slice_type.is_p() || header.slice_type.is_sp() || header.slice_type.is_b() {
2453            header.num_ref_idx_active_override_flag = r.read_bit()?;
2454            if header.num_ref_idx_active_override_flag {
2455                header.num_ref_idx_l0_active_minus1 = r.read_ue()?;
2456                if header.slice_type.is_b() {
2457                    header.num_ref_idx_l1_active_minus1 = r.read_ue()?;
2458                }
2459            } else {
2460                header.num_ref_idx_l0_active_minus1 = pps.num_ref_idx_l0_default_active_minus1;
2461                if header.slice_type.is_b() {
2462                    header.num_ref_idx_l1_active_minus1 = pps.num_ref_idx_l1_default_active_minus1;
2463                }
2464            }
2465        }
2466
2467        if header.field_pic_flag {
2468            if header.num_ref_idx_l0_active_minus1 > 31 || header.num_ref_idx_l1_active_minus1 > 31
2469            {
2470                return Err(anyhow!("Broken Data"));
2471            }
2472        } else if header.num_ref_idx_l0_active_minus1 > 15
2473            || header.num_ref_idx_l1_active_minus1 > 15
2474        {
2475            return Err(anyhow!("Broken Data"));
2476        }
2477
2478        if let NaluType::SliceExt = nalu.header.type_ {
2479            return Err(anyhow!("Stream contain unsupported/unimplemented NALs"));
2480        }
2481
2482        Parser::parse_ref_pic_list_modifications(&mut r, &mut header)?;
2483
2484        if (pps.weighted_pred_flag && (header.slice_type.is_p() || header.slice_type.is_sp()))
2485            || (pps.weighted_bipred_idc == 1 && header.slice_type.is_b())
2486        {
2487            Parser::parse_pred_weight_table(&mut r, sps, &mut header)?;
2488        }
2489
2490        if nalu.header.ref_idc != 0 {
2491            Parser::parse_dec_ref_pic_marking(&mut r, &nalu, &mut header)?;
2492        }
2493
2494        if pps.entropy_coding_mode_flag && !header.slice_type.is_i() && !header.slice_type.is_si() {
2495            header.cabac_init_idc = r.read_ue_max(2)?;
2496        }
2497
2498        header.slice_qp_delta = r.read_se_bounded(-87, 77)?;
2499
2500        if header.slice_type.is_sp() || header.slice_type.is_si() {
2501            if header.slice_type.is_sp() {
2502                header.sp_for_switch_flag = r.read_bit()?;
2503            }
2504
2505            header.slice_qs_delta = r.read_se_bounded(-51, 51)?;
2506        }
2507
2508        if pps.deblocking_filter_control_present_flag {
2509            header.disable_deblocking_filter_idc = r.read_ue_max(2)?;
2510
2511            if header.disable_deblocking_filter_idc != 1 {
2512                header.slice_alpha_c0_offset_div2 = r.read_se_bounded(-6, 6)?;
2513                header.slice_beta_offset_div2 = r.read_se_bounded(-6, 6)?;
2514            }
2515        }
2516
2517        if pps.num_slice_groups_minus1 > 0 {
2518            return Err(anyhow!("Stream contain unsupported/unimplemented NALs"));
2519        }
2520
2521        let epb = r.num_epb();
2522        header.header_bit_size = (nalu.size - epb) * 8 - r.num_bits_left();
2523
2524        header.n_emulation_prevention_bytes = epb;
2525
2526        Ok(Slice { header, nalu })
2527    }
2528
2529    pub fn get_sps(&self, sps_id: u8) -> Option<&Rc<Sps>> {
2530        self.active_spses.get(&sps_id)
2531    }
2532
2533    pub fn get_pps(&self, pps_id: u8) -> Option<&Rc<Pps>> {
2534        self.active_ppses.get(&pps_id)
2535    }
2536}
2537
2538#[derive(Debug)]
2539pub struct NaluHeader {
2540    pub ref_idc: u8,
2541    pub type_: NaluType,
2542    pub idr_pic_flag: bool,
2543}
2544
2545impl Header for NaluHeader {
2546    fn parse<T: AsRef<[u8]>>(cursor: &Cursor<T>) -> anyhow::Result<Self> {
2547        if !cursor.has_remaining() {
2548            return Err(anyhow!("Broken Data"));
2549        }
2550
2551        let byte = cursor.chunk()[0];
2552
2553        let type_ = NaluType::n(byte & 0x1f).ok_or(anyhow!("Broken Data"))?;
2554
2555        if let NaluType::SliceExt = type_ {
2556            return Err(anyhow!("Stream contain unsupported/unimplemented NALs"));
2557        }
2558
2559        let ref_idc = (byte & 0x60) >> 5;
2560        let idr_pic_flag = matches!(type_, NaluType::SliceIdr);
2561
2562        Ok(NaluHeader {
2563            ref_idc,
2564            type_,
2565            idr_pic_flag,
2566        })
2567    }
2568
2569    fn is_end(&self) -> bool {
2570        matches!(self.type_, NaluType::SeqEnd | NaluType::StreamEnd)
2571    }
2572
2573    fn len(&self) -> usize {
2574        1
2575    }
2576}
2577
2578#[cfg(test)]
2579mod tests {
2580    use std::io::Cursor;
2581
2582    use crate::codec::h264::parser::Level;
2583    use crate::codec::h264::parser::MaxLongTermFrameIdx;
2584    use crate::codec::h264::parser::Nalu;
2585    use crate::codec::h264::parser::NaluType;
2586    use crate::codec::h264::parser::Parser;
2587
2588    const STREAM_TEST_25_FPS: &[u8] = include_bytes!("test_data/test-25fps.h264");
2589    const STREAM_TEST_25_FPS_NUM_NALUS: usize = 759;
2590
2591    const STREAM_TEST_25_FPS_SLICE_0: &[u8] =
2592        include_bytes!("test_data/test-25fps-h264-slice-data-0.bin");
2593    const STREAM_TEST_25_FPS_SLICE_2: &[u8] =
2594        include_bytes!("test_data/test-25fps-h264-slice-data-2.bin");
2595    const STREAM_TEST_25_FPS_SLICE_4: &[u8] =
2596        include_bytes!("test_data/test-25fps-h264-slice-data-4.bin");
2597
2598    /// This test is adapted from chromium, available at media/video/h264_parser_unittest.cc
2599    #[test]
2600    fn parse_nalus_from_stream_file() {
2601        let mut cursor = Cursor::new(STREAM_TEST_25_FPS);
2602        let mut num_nalus = 0;
2603        while Nalu::next(&mut cursor).is_ok() {
2604            num_nalus += 1;
2605        }
2606
2607        assert_eq!(num_nalus, STREAM_TEST_25_FPS_NUM_NALUS)
2608    }
2609
2610    /// The results were manually extracted from the GStreamer parser using GDB
2611    /// (gsth264parser.c) in order to compare both implementations using the
2612    /// following pipeline:
2613    /// gst-launch-1.0 filesrc location=test-25fps.h264 ! h264parse ! 'video/x-h264,stream-format=byte-stream' ! vah264dec ! fakevideosink
2614    #[test]
2615    fn parse_test25fps() {
2616        let mut cursor = Cursor::new(STREAM_TEST_25_FPS);
2617        let mut sps_ids = Vec::new();
2618        let mut pps_ids = Vec::new();
2619        let mut slices = Vec::new();
2620
2621        let mut parser = Parser::default();
2622
2623        while let Ok(nalu) = Nalu::next(&mut cursor) {
2624            match nalu.header.type_ {
2625                NaluType::Slice
2626                | NaluType::SliceDpa
2627                | NaluType::SliceDpb
2628                | NaluType::SliceDpc
2629                | NaluType::SliceIdr
2630                | NaluType::SliceExt => {
2631                    let slice = parser.parse_slice_header(nalu).unwrap();
2632                    slices.push(slice);
2633                }
2634                NaluType::Sps => {
2635                    let sps = parser.parse_sps(&nalu).unwrap();
2636                    sps_ids.push(sps.seq_parameter_set_id);
2637                }
2638                NaluType::Pps => {
2639                    let pps = parser.parse_pps(&nalu).unwrap();
2640                    pps_ids.push(pps.pic_parameter_set_id);
2641                }
2642                _ => {
2643                    continue;
2644                }
2645            }
2646        }
2647
2648        for sps_id in &sps_ids {
2649            // four identical SPSes in this stream
2650            let sps = parser.get_sps(*sps_id).unwrap();
2651
2652            assert_eq!(sps.seq_parameter_set_id, 0);
2653            assert_eq!(sps.profile_idc, 77);
2654            assert!(!sps.constraint_set0_flag);
2655            assert!(sps.constraint_set1_flag);
2656            assert!(!sps.constraint_set2_flag);
2657            assert!(!sps.constraint_set3_flag);
2658            assert!(!sps.constraint_set4_flag);
2659            assert!(!sps.constraint_set5_flag);
2660            assert_eq!(sps.level_idc, Level::L1_3);
2661            assert_eq!(sps.chroma_format_idc, 1);
2662            assert!(!sps.separate_colour_plane_flag);
2663            assert_eq!(sps.bit_depth_luma_minus8, 0);
2664            assert_eq!(sps.bit_depth_chroma_minus8, 0);
2665            assert!(!sps.qpprime_y_zero_transform_bypass_flag);
2666            assert!(!sps.seq_scaling_matrix_present_flag);
2667
2668            for outer in &sps.scaling_lists_4x4 {
2669                for inner in outer {
2670                    assert_eq!(*inner, 16);
2671                }
2672            }
2673
2674            for outer in &sps.scaling_lists_8x8 {
2675                for inner in outer {
2676                    assert_eq!(*inner, 16);
2677                }
2678            }
2679
2680            assert_eq!(sps.log2_max_frame_num_minus4, 1);
2681            assert_eq!(sps.pic_order_cnt_type, 0);
2682            assert_eq!(sps.log2_max_pic_order_cnt_lsb_minus4, 3);
2683            assert!(!sps.delta_pic_order_always_zero_flag);
2684            assert_eq!(sps.offset_for_non_ref_pic, 0);
2685            assert_eq!(sps.offset_for_top_to_bottom_field, 0);
2686            assert_eq!(sps.num_ref_frames_in_pic_order_cnt_cycle, 0);
2687
2688            for offset in sps.offset_for_ref_frame {
2689                assert_eq!(offset, 0);
2690            }
2691
2692            assert_eq!(sps.max_num_ref_frames, 2);
2693            assert!(!sps.gaps_in_frame_num_value_allowed_flag);
2694            assert_eq!(sps.pic_width_in_mbs_minus1, 19);
2695            assert_eq!(sps.pic_height_in_map_units_minus1, 14);
2696            assert!(sps.frame_mbs_only_flag);
2697            assert!(!sps.mb_adaptive_frame_field_flag);
2698            assert!(!sps.direct_8x8_inference_flag);
2699            assert!(!sps.frame_cropping_flag);
2700            assert_eq!(sps.frame_crop_left_offset, 0);
2701            assert_eq!(sps.frame_crop_right_offset, 0);
2702            assert_eq!(sps.frame_crop_top_offset, 0);
2703            assert_eq!(sps.frame_crop_bottom_offset, 0);
2704            assert_eq!(sps.chroma_array_type(), 1);
2705            assert_eq!(sps.max_frame_num(), 32);
2706            assert_eq!(sps.width(), 320);
2707            assert_eq!(sps.height(), 240);
2708        }
2709
2710        for pps_id in &pps_ids {
2711            // four identical SPSes in this stream
2712            let pps = parser.get_pps(*pps_id).unwrap();
2713            assert_eq!(pps.pic_parameter_set_id, 0);
2714            assert_eq!(pps.seq_parameter_set_id, 0);
2715            assert!(pps.bottom_field_pic_order_in_frame_present_flag);
2716            assert_eq!(pps.num_slice_groups_minus1, 0);
2717            assert_eq!(pps.num_ref_idx_l0_default_active_minus1, 0);
2718            assert_eq!(pps.num_ref_idx_l1_default_active_minus1, 0);
2719            assert!(!pps.weighted_pred_flag);
2720            assert_eq!(pps.weighted_bipred_idc, 0);
2721            assert_eq!(pps.pic_init_qp_minus26, 2);
2722            assert_eq!(pps.pic_init_qs_minus26, 0);
2723            assert_eq!(pps.chroma_qp_index_offset, 0);
2724            assert!(!pps.deblocking_filter_control_present_flag);
2725            assert!(!pps.constrained_intra_pred_flag);
2726            assert!(!pps.redundant_pic_cnt_present_flag);
2727            assert!(!pps.transform_8x8_mode_flag);
2728
2729            for outer in &pps.scaling_lists_4x4 {
2730                for inner in outer {
2731                    assert_eq!(*inner, 16);
2732                }
2733            }
2734
2735            for outer in &pps.scaling_lists_8x8 {
2736                for inner in outer {
2737                    assert_eq!(*inner, 16);
2738                }
2739            }
2740
2741            assert_eq!(pps.second_chroma_qp_index_offset, 0);
2742            assert!(!pps.pic_scaling_matrix_present_flag);
2743        }
2744
2745        // test an I slice
2746        let hdr = &slices[0].header;
2747        let nalu = &slices[0].nalu;
2748        assert_eq!(nalu.as_ref(), STREAM_TEST_25_FPS_SLICE_0);
2749
2750        assert_eq!(hdr.first_mb_in_slice, 0);
2751        assert!(hdr.slice_type.is_i());
2752        assert_eq!(hdr.colour_plane_id, 0);
2753        assert_eq!(hdr.frame_num, 0);
2754        assert!(!hdr.field_pic_flag);
2755        assert!(!hdr.bottom_field_flag);
2756        assert_eq!(hdr.idr_pic_id, 0);
2757        assert_eq!(hdr.pic_order_cnt_lsb, 0);
2758        assert_eq!(hdr.delta_pic_order_cnt_bottom, 0);
2759        assert_eq!(hdr.delta_pic_order_cnt[0], 0);
2760        assert_eq!(hdr.delta_pic_order_cnt[1], 0);
2761        assert_eq!(hdr.redundant_pic_cnt, 0);
2762        assert!(!hdr.direct_spatial_mv_pred_flag);
2763        assert_eq!(hdr.num_ref_idx_l0_active_minus1, 0);
2764        assert_eq!(hdr.num_ref_idx_l1_active_minus1, 0);
2765        assert!(!hdr.ref_pic_list_modification_flag_l0);
2766
2767        assert_eq!(hdr.ref_pic_list_modification_l0.len(), 0);
2768
2769        for rplm in &hdr.ref_pic_list_modification_l0 {
2770            assert_eq!(rplm.modification_of_pic_nums_idc, 0);
2771            assert_eq!(rplm.abs_diff_pic_num_minus1, 0);
2772            assert_eq!(rplm.long_term_pic_num, 0);
2773            assert_eq!(rplm.abs_diff_view_idx_minus1, 0);
2774        }
2775
2776        assert!(!hdr.ref_pic_list_modification_flag_l1);
2777        assert_eq!(hdr.ref_pic_list_modification_l1.len(), 0);
2778
2779        for rplm in &hdr.ref_pic_list_modification_l1 {
2780            assert_eq!(rplm.modification_of_pic_nums_idc, 0);
2781            assert_eq!(rplm.abs_diff_pic_num_minus1, 0);
2782            assert_eq!(rplm.long_term_pic_num, 0);
2783            assert_eq!(rplm.abs_diff_view_idx_minus1, 0);
2784        }
2785
2786        // Safe because this type does not have any references
2787        assert_eq!(hdr.pred_weight_table, unsafe { std::mem::zeroed() });
2788
2789        assert_eq!(hdr.dec_ref_pic_marking, Default::default());
2790
2791        assert_eq!(hdr.cabac_init_idc, 0);
2792        assert_eq!(hdr.slice_qp_delta, 12);
2793        assert_eq!(hdr.slice_qs_delta, 0);
2794        assert_eq!(hdr.disable_deblocking_filter_idc, 0);
2795        assert_eq!(hdr.slice_alpha_c0_offset_div2, 0);
2796        assert_eq!(hdr.slice_beta_offset_div2, 0);
2797        assert_eq!(hdr.max_pic_num, 32);
2798        assert_eq!(hdr.header_bit_size, 38);
2799        assert!(!hdr.num_ref_idx_active_override_flag);
2800
2801        // test a P slice
2802        let hdr = &slices[2].header;
2803        let nalu = &slices[2].nalu;
2804        assert_eq!(nalu.as_ref(), STREAM_TEST_25_FPS_SLICE_2);
2805
2806        assert_eq!(hdr.first_mb_in_slice, 0);
2807        assert!(hdr.slice_type.is_p());
2808        assert_eq!(hdr.colour_plane_id, 0);
2809        assert_eq!(hdr.frame_num, 1);
2810        assert!(!hdr.field_pic_flag);
2811        assert!(!hdr.bottom_field_flag);
2812        assert_eq!(hdr.idr_pic_id, 0);
2813        assert_eq!(hdr.pic_order_cnt_lsb, 4);
2814        assert_eq!(hdr.delta_pic_order_cnt_bottom, 0);
2815        assert_eq!(hdr.delta_pic_order_cnt[0], 0);
2816        assert_eq!(hdr.delta_pic_order_cnt[1], 0);
2817        assert_eq!(hdr.redundant_pic_cnt, 0);
2818        assert!(!hdr.direct_spatial_mv_pred_flag);
2819        assert_eq!(hdr.num_ref_idx_l0_active_minus1, 0);
2820        assert_eq!(hdr.num_ref_idx_l1_active_minus1, 0);
2821        assert!(!hdr.ref_pic_list_modification_flag_l0);
2822
2823        assert_eq!(hdr.ref_pic_list_modification_l0.len(), 0);
2824
2825        for rplm in &hdr.ref_pic_list_modification_l0 {
2826            assert_eq!(rplm.modification_of_pic_nums_idc, 0);
2827            assert_eq!(rplm.abs_diff_pic_num_minus1, 0);
2828            assert_eq!(rplm.long_term_pic_num, 0);
2829            assert_eq!(rplm.abs_diff_view_idx_minus1, 0);
2830        }
2831
2832        assert!(!hdr.ref_pic_list_modification_flag_l1);
2833        assert_eq!(hdr.ref_pic_list_modification_l1.len(), 0);
2834
2835        for rplm in &hdr.ref_pic_list_modification_l1 {
2836            assert_eq!(rplm.modification_of_pic_nums_idc, 0);
2837            assert_eq!(rplm.abs_diff_pic_num_minus1, 0);
2838            assert_eq!(rplm.long_term_pic_num, 0);
2839            assert_eq!(rplm.abs_diff_view_idx_minus1, 0);
2840        }
2841
2842        // Safe because this type does not have any references
2843        assert_eq!(hdr.pred_weight_table, unsafe { std::mem::zeroed() });
2844
2845        assert_eq!(hdr.dec_ref_pic_marking, Default::default());
2846
2847        assert_eq!(hdr.cabac_init_idc, 0);
2848        assert_eq!(hdr.slice_qp_delta, 0);
2849        assert_eq!(hdr.slice_qs_delta, 0);
2850        assert_eq!(hdr.disable_deblocking_filter_idc, 0);
2851        assert_eq!(hdr.slice_alpha_c0_offset_div2, 0);
2852        assert_eq!(hdr.slice_beta_offset_div2, 0);
2853        assert_eq!(hdr.max_pic_num, 32);
2854        assert_eq!(hdr.header_bit_size, 28);
2855        assert!(!hdr.num_ref_idx_active_override_flag);
2856
2857        // test a B slice
2858        let hdr = &slices[4].header;
2859        let nalu = &slices[4].nalu;
2860        assert_eq!(nalu.as_ref(), STREAM_TEST_25_FPS_SLICE_4);
2861
2862        assert_eq!(hdr.first_mb_in_slice, 0);
2863        assert!(hdr.slice_type.is_b());
2864        assert_eq!(hdr.colour_plane_id, 0);
2865        assert_eq!(hdr.frame_num, 2);
2866        assert!(!hdr.field_pic_flag);
2867        assert!(!hdr.bottom_field_flag);
2868        assert_eq!(hdr.idr_pic_id, 0);
2869        assert_eq!(hdr.pic_order_cnt_lsb, 2);
2870        assert_eq!(hdr.delta_pic_order_cnt_bottom, 0);
2871        assert_eq!(hdr.delta_pic_order_cnt[0], 0);
2872        assert_eq!(hdr.delta_pic_order_cnt[1], 0);
2873        assert_eq!(hdr.redundant_pic_cnt, 0);
2874        assert!(hdr.direct_spatial_mv_pred_flag);
2875        assert_eq!(hdr.num_ref_idx_l0_active_minus1, 0);
2876        assert_eq!(hdr.num_ref_idx_l1_active_minus1, 0);
2877        assert!(!hdr.ref_pic_list_modification_flag_l0);
2878
2879        assert_eq!(hdr.ref_pic_list_modification_l0.len(), 0);
2880
2881        for rplm in &hdr.ref_pic_list_modification_l0 {
2882            assert_eq!(rplm.modification_of_pic_nums_idc, 0);
2883            assert_eq!(rplm.abs_diff_pic_num_minus1, 0);
2884            assert_eq!(rplm.long_term_pic_num, 0);
2885            assert_eq!(rplm.abs_diff_view_idx_minus1, 0);
2886        }
2887
2888        assert!(!hdr.ref_pic_list_modification_flag_l1);
2889        assert_eq!(hdr.ref_pic_list_modification_l1.len(), 0);
2890
2891        for rplm in &hdr.ref_pic_list_modification_l1 {
2892            assert_eq!(rplm.modification_of_pic_nums_idc, 0);
2893            assert_eq!(rplm.abs_diff_pic_num_minus1, 0);
2894            assert_eq!(rplm.long_term_pic_num, 0);
2895            assert_eq!(rplm.abs_diff_view_idx_minus1, 0);
2896        }
2897
2898        // Safe because this type does not have any references
2899        assert_eq!(hdr.pred_weight_table, unsafe { std::mem::zeroed() });
2900
2901        assert_eq!(hdr.dec_ref_pic_marking, Default::default());
2902
2903        assert_eq!(hdr.cabac_init_idc, 0);
2904        assert_eq!(hdr.slice_qp_delta, 16);
2905        assert_eq!(hdr.slice_qs_delta, 0);
2906        assert_eq!(hdr.disable_deblocking_filter_idc, 0);
2907        assert_eq!(hdr.slice_alpha_c0_offset_div2, 0);
2908        assert_eq!(hdr.slice_beta_offset_div2, 0);
2909        assert_eq!(hdr.max_pic_num, 32);
2910        assert_eq!(hdr.header_bit_size, 41);
2911        assert!(!hdr.num_ref_idx_active_override_flag);
2912    }
2913
2914    #[test]
2915    fn invalid_sps_crop_width() {
2916        // This SPS contains invalid frame_crop_*_offset settings. This led to
2917        // unconditional panic in the parser in the past. This test make sure a
2918        // panic is avoided.
2919        let invalid_sps = vec![
2920            0x00, 0x00, 0x01, 0x07, 0x00, 0x00, 0x0a, 0xfb, 0xb0, 0x32, 0xc0, 0xca, 0x80,
2921        ];
2922
2923        let mut cursor = Cursor::new(invalid_sps.as_ref());
2924        let mut parser = Parser::default();
2925
2926        while let Ok(nalu) = Nalu::next(&mut cursor) {
2927            assert_eq!(nalu.header.type_, NaluType::Sps);
2928            parser.parse_sps(&nalu).unwrap_err();
2929        }
2930    }
2931
2932    #[test]
2933    fn max_long_term_frame_idx() {
2934        assert_eq!(
2935            MaxLongTermFrameIdx::from_value_plus1(0),
2936            MaxLongTermFrameIdx::NoLongTermFrameIndices
2937        );
2938        assert_eq!(
2939            MaxLongTermFrameIdx::NoLongTermFrameIndices.to_value_plus1(),
2940            0
2941        );
2942
2943        assert_eq!(
2944            MaxLongTermFrameIdx::from_value_plus1(1),
2945            MaxLongTermFrameIdx::Idx(0)
2946        );
2947        assert_eq!(MaxLongTermFrameIdx::Idx(0).to_value_plus1(), 1);
2948
2949        assert_eq!(
2950            MaxLongTermFrameIdx::from_value_plus1(25),
2951            MaxLongTermFrameIdx::Idx(24)
2952        );
2953        assert_eq!(MaxLongTermFrameIdx::Idx(24).to_value_plus1(), 25);
2954
2955        // Check PartialOrd<u32> implementation.
2956        assert!(MaxLongTermFrameIdx::NoLongTermFrameIndices < 0);
2957        assert_ne!(MaxLongTermFrameIdx::NoLongTermFrameIndices, 0);
2958        assert_eq!(MaxLongTermFrameIdx::Idx(0), 0);
2959        assert!(MaxLongTermFrameIdx::Idx(0) < 1);
2960        assert_eq!(MaxLongTermFrameIdx::Idx(24), 24);
2961        assert!(MaxLongTermFrameIdx::Idx(24) < 25);
2962    }
2963}