scuffle_av1/obu/
seq.rs

1use std::io;
2
3use byteorder::{BigEndian, ReadBytesExt};
4use scuffle_bytes_util::BitReader;
5
6use super::ObuHeader;
7use crate::obu::utils::read_uvlc;
8
9/// Sequence Header OBU
10/// AV1-Spec-2 - 5.5
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct SequenceHeaderObu {
13    pub header: ObuHeader,
14    pub seq_profile: u8,
15    pub still_picture: bool,
16    pub reduced_still_picture_header: bool,
17    pub timing_info: Option<TimingInfo>,
18    pub decoder_model_info: Option<DecoderModelInfo>,
19    pub operating_points: Vec<OperatingPoint>,
20    pub max_frame_width: u64,
21    pub max_frame_height: u64,
22    pub frame_ids: Option<FrameIds>,
23    pub use_128x128_superblock: bool,
24    pub enable_filter_intra: bool,
25    pub enable_intra_edge_filter: bool,
26    pub enable_interintra_compound: bool,
27    pub enable_masked_compound: bool,
28    pub enable_warped_motion: bool,
29    pub enable_dual_filter: bool,
30    pub enable_order_hint: bool,
31    pub enable_jnt_comp: bool,
32    pub enable_ref_frame_mvs: bool,
33    pub seq_force_screen_content_tools: u8,
34    pub seq_force_integer_mv: u8,
35    pub order_hint_bits: u8,
36    pub enable_superres: bool,
37    pub enable_cdef: bool,
38    pub enable_restoration: bool,
39    pub color_config: ColorConfig,
40    pub film_grain_params_present: bool,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Copy)]
44pub struct FrameIds {
45    pub delta_frame_id_length: u8,
46    pub additional_frame_id_length: u8,
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Copy)]
50pub struct OperatingPoint {
51    pub idc: u16,
52    pub seq_level_idx: u8,
53    pub seq_tier: bool,
54    pub operating_parameters_info: Option<OperatingParametersInfo>,
55    pub initial_display_delay: Option<u8>,
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Copy)]
59pub struct TimingInfo {
60    pub num_units_in_display_tick: u32,
61    pub time_scale: u32,
62    pub num_ticks_per_picture: Option<u64>,
63}
64
65impl TimingInfo {
66    pub fn parse(bit_reader: &mut BitReader<impl io::Read>) -> io::Result<Self> {
67        let num_units_in_display_tick = bit_reader.read_u32::<BigEndian>()?;
68        let time_scale = bit_reader.read_u32::<BigEndian>()?;
69        let num_ticks_per_picture = if bit_reader.read_bit()? {
70            Some(read_uvlc(bit_reader)? + 1)
71        } else {
72            None
73        };
74        Ok(Self {
75            num_units_in_display_tick,
76            time_scale,
77            num_ticks_per_picture,
78        })
79    }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, Copy)]
83pub struct DecoderModelInfo {
84    pub buffer_delay_length: u8,
85    pub num_units_in_decoding_tick: u32,
86    pub buffer_removal_time_length: u8,
87    pub frame_presentation_time_length: u8,
88}
89
90impl DecoderModelInfo {
91    pub fn parse(bit_reader: &mut BitReader<impl io::Read>) -> io::Result<Self> {
92        let buffer_delay_length = bit_reader.read_bits(5)? as u8 + 1;
93        let num_units_in_decoding_tick = bit_reader.read_u32::<BigEndian>()?;
94        let buffer_removal_time_length = bit_reader.read_bits(5)? as u8 + 1;
95        let frame_presentation_time_length = bit_reader.read_bits(5)? as u8 + 1;
96        Ok(Self {
97            buffer_delay_length,
98            num_units_in_decoding_tick,
99            buffer_removal_time_length,
100            frame_presentation_time_length,
101        })
102    }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Copy)]
106pub struct OperatingParametersInfo {
107    pub decoder_buffer_delay: u64,
108    pub encoder_buffer_delay: u64,
109    pub low_delay_mode_flag: bool,
110}
111
112impl OperatingParametersInfo {
113    pub fn parse(delay_bit_length: u8, bit_reader: &mut BitReader<impl io::Read>) -> io::Result<Self> {
114        let decoder_buffer_delay = bit_reader.read_bits(delay_bit_length)?;
115        let encoder_buffer_delay = bit_reader.read_bits(delay_bit_length)?;
116        let low_delay_mode_flag = bit_reader.read_bit()?;
117        Ok(Self {
118            decoder_buffer_delay,
119            encoder_buffer_delay,
120            low_delay_mode_flag,
121        })
122    }
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Copy)]
126pub struct ColorConfig {
127    pub bit_depth: i32,
128    pub mono_chrome: bool,
129    pub num_planes: u8,
130    pub color_primaries: u8,
131    pub transfer_characteristics: u8,
132    pub matrix_coefficients: u8,
133    pub full_color_range: bool,
134    pub subsampling_x: bool,
135    pub subsampling_y: bool,
136    pub chroma_sample_position: u8,
137    pub separate_uv_delta_q: bool,
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Copy)]
141struct ColorRangeAndSubsampling {
142    color_range: bool,
143    subsampling_x: bool,
144    subsampling_y: bool,
145}
146
147impl ColorConfig {
148    fn parse_color_range_and_subsampling(
149        bit_reader: &mut BitReader<impl io::Read>,
150        seq_profile: u8,
151        color_primaries: u8,
152        transfer_characteristics: u8,
153        matrix_coefficients: u8,
154        bit_depth: i32,
155    ) -> io::Result<ColorRangeAndSubsampling> {
156        let color_range;
157        let subsampling_x;
158        let subsampling_y;
159
160        const CP_BT_709: u8 = 1;
161        const TC_SRGB: u8 = 13;
162        const MC_IDENTITY: u8 = 0;
163
164        if color_primaries == CP_BT_709 && transfer_characteristics == TC_SRGB && matrix_coefficients == MC_IDENTITY {
165            color_range = true;
166            subsampling_x = false;
167            subsampling_y = false;
168        } else {
169            color_range = bit_reader.read_bit()?;
170            if seq_profile == 0 {
171                subsampling_x = true;
172                subsampling_y = true;
173            } else if seq_profile == 1 {
174                subsampling_x = false;
175                subsampling_y = false;
176            } else if bit_depth == 12 {
177                subsampling_x = bit_reader.read_bit()?;
178                if subsampling_x {
179                    subsampling_y = bit_reader.read_bit()?;
180                } else {
181                    subsampling_y = false;
182                }
183            } else {
184                subsampling_x = true;
185                subsampling_y = false;
186            }
187        }
188
189        Ok(ColorRangeAndSubsampling {
190            color_range,
191            subsampling_x,
192            subsampling_y,
193        })
194    }
195
196    pub fn parse(seq_profile: u8, bit_reader: &mut BitReader<impl io::Read>) -> io::Result<Self> {
197        let high_bitdepth = bit_reader.read_bit()?;
198        let bit_depth = match (seq_profile, high_bitdepth) {
199            (2, true) if bit_reader.read_bit()? => 12,
200            (_, true) => 10,
201            (_, false) => 8,
202        };
203
204        let mono_chrome = if seq_profile == 1 { false } else { bit_reader.read_bit()? };
205
206        let color_primaries;
207        let transfer_characteristics;
208        let matrix_coefficients;
209
210        let color_description_present_flag = bit_reader.read_bit()?;
211        if color_description_present_flag {
212            color_primaries = bit_reader.read_bits(8)? as u8;
213            transfer_characteristics = bit_reader.read_bits(8)? as u8;
214            matrix_coefficients = bit_reader.read_bits(8)? as u8;
215        } else {
216            color_primaries = 2; // CP_UNSPECIFIED
217            transfer_characteristics = 2; // TC_UNSPECIFIED
218            matrix_coefficients = 2; // MC_UNSPECIFIED
219        }
220
221        let num_planes = if mono_chrome { 1 } else { 3 };
222
223        if mono_chrome {
224            Ok(ColorConfig {
225                bit_depth,
226                color_primaries,
227                transfer_characteristics,
228                matrix_coefficients,
229                full_color_range: bit_reader.read_bit()?,
230                subsampling_x: true,
231                subsampling_y: true,
232                mono_chrome,
233                separate_uv_delta_q: false,
234                chroma_sample_position: 0, // CSP_UNKNOWN
235                num_planes,
236            })
237        } else {
238            let ColorRangeAndSubsampling {
239                color_range,
240                subsampling_x,
241                subsampling_y,
242            } = Self::parse_color_range_and_subsampling(
243                bit_reader,
244                seq_profile,
245                color_primaries,
246                transfer_characteristics,
247                matrix_coefficients,
248                bit_depth,
249            )?;
250
251            let chroma_sample_position = if subsampling_x && subsampling_y {
252                bit_reader.read_bits(2)? as u8
253            } else {
254                0 // CSP_UNKNOWN
255            };
256
257            let separate_uv_delta_q = bit_reader.read_bit()?;
258            Ok(ColorConfig {
259                bit_depth,
260                mono_chrome,
261                color_primaries,
262                transfer_characteristics,
263                matrix_coefficients,
264                full_color_range: color_range,
265                subsampling_x,
266                subsampling_y,
267                chroma_sample_position,
268                separate_uv_delta_q,
269                num_planes,
270            })
271        }
272    }
273}
274
275impl SequenceHeaderObu {
276    pub const fn header(&self) -> &ObuHeader {
277        &self.header
278    }
279
280    pub fn parse(header: ObuHeader, reader: &mut impl io::Read) -> io::Result<Self> {
281        let mut bit_reader = BitReader::new(reader);
282
283        let seq_profile = bit_reader.read_bits(3)? as u8;
284        let still_picture = bit_reader.read_bit()?;
285        let reduced_still_picture_header = bit_reader.read_bit()?;
286
287        if !still_picture && reduced_still_picture_header {
288            return Err(io::Error::new(
289                io::ErrorKind::InvalidData,
290                "reduced_still_picture_header is true but still_picture is false",
291            ));
292        }
293
294        let mut timing_info = None;
295        let mut decoder_model_info = None;
296        let mut operating_points = Vec::new();
297
298        if reduced_still_picture_header {
299            operating_points.push(OperatingPoint {
300                idc: 0,
301                seq_level_idx: bit_reader.read_bits(5)? as u8,
302                seq_tier: false,
303                operating_parameters_info: None,
304                initial_display_delay: None,
305            });
306        } else {
307            let timing_info_present_flag = bit_reader.read_bit()?;
308            if timing_info_present_flag {
309                timing_info = Some(TimingInfo::parse(&mut bit_reader)?);
310
311                let decoder_model_info_present_flag = bit_reader.read_bit()?;
312                if decoder_model_info_present_flag {
313                    decoder_model_info = Some(DecoderModelInfo::parse(&mut bit_reader)?);
314                }
315            }
316
317            let initial_display_delay_present_flag = bit_reader.read_bit()?;
318            let operating_points_cnt_minus_1 = bit_reader.read_bits(5)? as u8;
319            for _ in 0..operating_points_cnt_minus_1 + 1 {
320                let idc = bit_reader.read_bits(12)? as u16;
321                let seq_level_idx = bit_reader.read_bits(5)? as u8;
322                let seq_tier = if seq_level_idx > 7 { bit_reader.read_bit()? } else { false };
323                let decoder_model_present_for_this_op = if let Some(decoder_model_info) = decoder_model_info {
324                    bit_reader.read_bit()?.then_some(decoder_model_info.buffer_delay_length)
325                } else {
326                    None
327                };
328
329                let operating_parameters_info = if let Some(delay_bit_length) = decoder_model_present_for_this_op {
330                    Some(OperatingParametersInfo::parse(delay_bit_length, &mut bit_reader)?)
331                } else {
332                    None
333                };
334
335                let initial_display_delay = if initial_display_delay_present_flag {
336                    if bit_reader.read_bit()? {
337                        // initial_display_delay_present_for_this_op
338                        Some(bit_reader.read_bits(4)? as u8 + 1) // initial_display_delay_minus_1
339                    } else {
340                        None
341                    }
342                } else {
343                    None
344                };
345
346                operating_points.push(OperatingPoint {
347                    idc,
348                    seq_level_idx,
349                    seq_tier,
350                    operating_parameters_info,
351                    initial_display_delay,
352                });
353            }
354        }
355
356        let frame_width_bits = bit_reader.read_bits(4)? as u8 + 1;
357        let frame_height_bits = bit_reader.read_bits(4)? as u8 + 1;
358
359        let max_frame_width = bit_reader.read_bits(frame_width_bits)? + 1;
360        let max_frame_height = bit_reader.read_bits(frame_height_bits)? + 1;
361
362        let frame_id_numbers_present_flag = if reduced_still_picture_header {
363            false
364        } else {
365            bit_reader.read_bit()?
366        };
367        let frame_ids = if frame_id_numbers_present_flag {
368            let delta_frame_id_length = bit_reader.read_bits(4)? as u8 + 2;
369            let additional_frame_id_length = bit_reader.read_bits(3)? as u8 + 1;
370            Some(FrameIds {
371                delta_frame_id_length,
372                additional_frame_id_length,
373            })
374        } else {
375            None
376        };
377
378        let use_128x128_superblock = bit_reader.read_bit()?;
379        let enable_filter_intra = bit_reader.read_bit()?;
380        let enable_intra_edge_filter = bit_reader.read_bit()?;
381
382        let enable_interintra_compound;
383        let enable_masked_compound;
384        let enable_warped_motion;
385        let enable_dual_filter;
386        let enable_order_hint;
387        let enable_jnt_comp;
388        let enable_ref_frame_mvs;
389        let order_hint_bits;
390        let seq_force_integer_mv;
391
392        let seq_force_screen_content_tools;
393
394        if !reduced_still_picture_header {
395            enable_interintra_compound = bit_reader.read_bit()?;
396            enable_masked_compound = bit_reader.read_bit()?;
397            enable_warped_motion = bit_reader.read_bit()?;
398            enable_dual_filter = bit_reader.read_bit()?;
399            enable_order_hint = bit_reader.read_bit()?;
400            if enable_order_hint {
401                enable_jnt_comp = bit_reader.read_bit()?;
402                enable_ref_frame_mvs = bit_reader.read_bit()?;
403            } else {
404                enable_jnt_comp = false;
405                enable_ref_frame_mvs = false;
406            }
407            if bit_reader.read_bit()? {
408                // seq_choose_screen_content_tools
409                seq_force_screen_content_tools = 2; // SELECT_SCREEN_CONTENT_TOOLS
410            } else {
411                seq_force_screen_content_tools = bit_reader.read_bits(1)? as u8;
412            }
413
414            // If seq_force_screen_content_tools is 0, then seq_force_integer_mv must be 2.
415            // Or if the next bit is 0, then seq_force_integer_mv must be 2.
416            if seq_force_screen_content_tools == 0 || bit_reader.read_bit()? {
417                seq_force_integer_mv = 2; // SELECT_INTEGER_MV
418            } else {
419                seq_force_integer_mv = bit_reader.read_bits(1)? as u8;
420            }
421
422            if enable_order_hint {
423                order_hint_bits = bit_reader.read_bits(3)? as u8 + 1;
424            } else {
425                order_hint_bits = 0;
426            }
427        } else {
428            enable_interintra_compound = false;
429            enable_masked_compound = false;
430            enable_warped_motion = false;
431            enable_dual_filter = false;
432            enable_order_hint = false;
433            enable_jnt_comp = false;
434            enable_ref_frame_mvs = false;
435            seq_force_screen_content_tools = 2; // SELECT_SCREEN_CONTENT_TOOLS
436            seq_force_integer_mv = 2; // SELECT_INTEGER_MV
437            order_hint_bits = 0;
438        }
439
440        let enable_superres = bit_reader.read_bit()?;
441        let enable_cdef = bit_reader.read_bit()?;
442        let enable_restoration = bit_reader.read_bit()?;
443
444        let color_config = ColorConfig::parse(seq_profile, &mut bit_reader)?;
445
446        let film_grain_params_present = bit_reader.read_bit()?;
447
448        Ok(Self {
449            header,
450            seq_profile,
451            still_picture,
452            reduced_still_picture_header,
453            operating_points,
454            decoder_model_info,
455            max_frame_width,
456            max_frame_height,
457            frame_ids,
458            use_128x128_superblock,
459            enable_filter_intra,
460            enable_intra_edge_filter,
461            enable_interintra_compound,
462            enable_masked_compound,
463            enable_warped_motion,
464            enable_dual_filter,
465            enable_order_hint,
466            enable_jnt_comp,
467            enable_ref_frame_mvs,
468            seq_force_screen_content_tools,
469            seq_force_integer_mv,
470            order_hint_bits,
471            enable_superres,
472            enable_cdef,
473            enable_restoration,
474            timing_info,
475            color_config,
476            film_grain_params_present,
477        })
478    }
479}
480
481#[cfg(test)]
482#[cfg_attr(all(coverage_nightly, test), coverage(off))]
483mod tests {
484    use byteorder::WriteBytesExt;
485    use scuffle_bytes_util::BitWriter;
486
487    use super::*;
488    use crate::ObuType;
489
490    #[test]
491    fn test_seq_obu_parse() {
492        let obu = b"\0\0\0j\xef\xbf\xe1\xbc\x02\x19\x90\x10\x10\x10@";
493
494        let header = ObuHeader {
495            obu_type: ObuType::SequenceHeader,
496            size: None,
497            extension_header: None,
498        };
499
500        let seq_header = SequenceHeaderObu::parse(header, &mut io::Cursor::new(obu)).unwrap();
501
502        insta::assert_debug_snapshot!(seq_header, @r"
503        SequenceHeaderObu {
504            header: ObuHeader {
505                obu_type: SequenceHeader,
506                size: None,
507                extension_header: None,
508            },
509            seq_profile: 0,
510            still_picture: false,
511            reduced_still_picture_header: false,
512            timing_info: None,
513            decoder_model_info: None,
514            operating_points: [
515                OperatingPoint {
516                    idc: 0,
517                    seq_level_idx: 13,
518                    seq_tier: false,
519                    operating_parameters_info: None,
520                    initial_display_delay: None,
521                },
522            ],
523            max_frame_width: 3840,
524            max_frame_height: 2160,
525            frame_ids: None,
526            use_128x128_superblock: false,
527            enable_filter_intra: false,
528            enable_intra_edge_filter: false,
529            enable_interintra_compound: false,
530            enable_masked_compound: false,
531            enable_warped_motion: false,
532            enable_dual_filter: false,
533            enable_order_hint: true,
534            enable_jnt_comp: false,
535            enable_ref_frame_mvs: false,
536            seq_force_screen_content_tools: 0,
537            seq_force_integer_mv: 2,
538            order_hint_bits: 7,
539            enable_superres: false,
540            enable_cdef: true,
541            enable_restoration: true,
542            color_config: ColorConfig {
543                bit_depth: 8,
544                mono_chrome: false,
545                num_planes: 3,
546                color_primaries: 1,
547                transfer_characteristics: 1,
548                matrix_coefficients: 1,
549                full_color_range: false,
550                subsampling_x: true,
551                subsampling_y: true,
552                chroma_sample_position: 0,
553                separate_uv_delta_q: false,
554            },
555            film_grain_params_present: false,
556        }
557        ");
558
559        assert_eq!(seq_header.header(), &header);
560    }
561
562    #[test]
563    fn test_seq_obu_parse_reduced_still_picture() {
564        let mut bits = BitWriter::new(Vec::new());
565
566        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
567        bits.write_bit(true).unwrap(); // still_picture
568        bits.write_bit(true).unwrap(); // reduced_still_picture_header
569        bits.write_bits(11, 5).unwrap(); // seq_lvl_idx
570
571        bits.write_bits(15, 4).unwrap();
572        bits.write_bits(15, 4).unwrap();
573        bits.write_bits(1919, 16).unwrap();
574        bits.write_bits(1079, 16).unwrap();
575
576        bits.write_bit(false).unwrap(); // use_128x128_superblock
577        bits.write_bit(false).unwrap(); // enable_filter_intra
578        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
579        bits.write_bit(false).unwrap(); // enable_superres
580        bits.write_bit(false).unwrap(); // enable_cdef
581        bits.write_bit(false).unwrap(); // enable_restoration
582
583        bits.write_bit(false).unwrap(); // high_bitdepth
584        bits.write_bit(true).unwrap(); // mono_chrome
585        bits.write_bit(false).unwrap(); // color_description_present_flag
586        bits.write_bit(true).unwrap(); // color_range
587        bits.write_bit(true).unwrap(); // separate_uv_delta_q
588
589        bits.write_bit(true).unwrap(); // film_grain_params_present
590
591        let obu_header = SequenceHeaderObu::parse(
592            ObuHeader {
593                obu_type: ObuType::SequenceHeader,
594                size: None,
595                extension_header: None,
596            },
597            &mut io::Cursor::new(bits.finish().unwrap()),
598        )
599        .unwrap();
600
601        insta::assert_debug_snapshot!(obu_header, @r"
602        SequenceHeaderObu {
603            header: ObuHeader {
604                obu_type: SequenceHeader,
605                size: None,
606                extension_header: None,
607            },
608            seq_profile: 2,
609            still_picture: true,
610            reduced_still_picture_header: true,
611            timing_info: None,
612            decoder_model_info: None,
613            operating_points: [
614                OperatingPoint {
615                    idc: 0,
616                    seq_level_idx: 11,
617                    seq_tier: false,
618                    operating_parameters_info: None,
619                    initial_display_delay: None,
620                },
621            ],
622            max_frame_width: 1920,
623            max_frame_height: 1080,
624            frame_ids: None,
625            use_128x128_superblock: false,
626            enable_filter_intra: false,
627            enable_intra_edge_filter: false,
628            enable_interintra_compound: false,
629            enable_masked_compound: false,
630            enable_warped_motion: false,
631            enable_dual_filter: false,
632            enable_order_hint: false,
633            enable_jnt_comp: false,
634            enable_ref_frame_mvs: false,
635            seq_force_screen_content_tools: 2,
636            seq_force_integer_mv: 2,
637            order_hint_bits: 0,
638            enable_superres: false,
639            enable_cdef: false,
640            enable_restoration: false,
641            color_config: ColorConfig {
642                bit_depth: 8,
643                mono_chrome: true,
644                num_planes: 1,
645                color_primaries: 2,
646                transfer_characteristics: 2,
647                matrix_coefficients: 2,
648                full_color_range: true,
649                subsampling_x: true,
650                subsampling_y: true,
651                chroma_sample_position: 0,
652                separate_uv_delta_q: false,
653            },
654            film_grain_params_present: true,
655        }
656        ");
657    }
658
659    #[test]
660    fn test_seq_obu_parse_timing_info_decoder_model_preset() {
661        let mut bits = BitWriter::new(Vec::new());
662
663        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
664        bits.write_bit(false).unwrap(); // still_picture
665        bits.write_bit(false).unwrap(); // reduced_still_picture_header
666        bits.write_bit(true).unwrap(); // timing_info_present_flag
667
668        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_display_tick
669        bits.write_u32::<BigEndian>(1).unwrap(); // time_scale
670        bits.write_bit(false).unwrap(); // num_ticks_per_picture
671
672        bits.write_bit(true).unwrap(); // decoder_model_info_present_flag
673        bits.write_bits(4, 5).unwrap(); // buffer_delay_length
674        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_decoding_tick
675        bits.write_bits(4, 5).unwrap(); // buffer_removal_time_length
676        bits.write_bits(4, 5).unwrap(); // frame_presentation_time_length
677
678        bits.write_bit(true).unwrap(); // initial_display_delay_present_flag
679        bits.write_bits(0, 5).unwrap(); // operating_points_cnt_minus_1
680
681        bits.write_bits(0, 12).unwrap(); // idc
682        bits.write_bits(1, 5).unwrap(); // seq_lvl_idx
683        bits.write_bit(true).unwrap(); // seq_tier
684
685        bits.write_bits(0b1010, 5).unwrap(); // decoder_buffer_delay
686        bits.write_bits(0b0101, 5).unwrap(); // encoder_buffer_delay
687        bits.write_bit(false).unwrap(); // low_delay_mode_flag
688
689        bits.write_bit(true).unwrap(); // film_grain_params_present
690        bits.write_bits(15, 4).unwrap(); // initial_display_delay_minus_1
691
692        bits.write_bits(15, 4).unwrap(); // operating_points_cnt_minus_1
693        bits.write_bits(15, 4).unwrap(); // operating_points_cnt_minus_1
694        bits.write_bits(1919, 16).unwrap(); // operating_points_cnt_minus_1
695        bits.write_bits(1079, 16).unwrap(); // operating_points_cnt_minus_1
696
697        bits.write_bit(true).unwrap(); // frame_id_numbers_present_flag
698        bits.write_bits(0b1101, 4).unwrap(); // delta_frame_id_length
699        bits.write_bits(0b101, 3).unwrap(); // additional_frame_id_length
700
701        bits.write_bit(false).unwrap(); // use_128x128_superblock
702        bits.write_bit(false).unwrap(); // enable_filter_intra
703        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
704
705        bits.write_bit(false).unwrap(); // enable_interintra_compound
706        bits.write_bit(false).unwrap(); // enable_masked_compound
707        bits.write_bit(false).unwrap(); // enable_warped_motion
708        bits.write_bit(false).unwrap(); // enable_dual_filter
709        bits.write_bit(true).unwrap(); // enable_order_hint
710        bits.write_bit(false).unwrap(); // enable_jnt_comp
711        bits.write_bit(false).unwrap(); // enable_ref_frame_mvs
712
713        bits.write_bit(false).unwrap();
714        bits.write_bit(true).unwrap();
715        bits.write_bit(false).unwrap();
716        bits.write_bit(false).unwrap();
717
718        bits.write_bits(0b100, 3).unwrap();
719
720        bits.write_bit(false).unwrap(); // enable_superres
721        bits.write_bit(false).unwrap(); // enable_cdef
722        bits.write_bit(false).unwrap(); // enable_restoration
723
724        bits.write_bit(false).unwrap(); // high_bitdepth
725        bits.write_bit(true).unwrap(); // mono_chrome
726        bits.write_bit(false).unwrap(); // color_description_present_flag
727        bits.write_bit(true).unwrap(); // color_range
728        bits.write_bit(true).unwrap(); // separate_uv_delta_q
729
730        bits.write_bit(true).unwrap(); // film_grain_params_present
731
732        let obu_header = SequenceHeaderObu::parse(
733            ObuHeader {
734                obu_type: ObuType::SequenceHeader,
735                size: None,
736                extension_header: None,
737            },
738            &mut io::Cursor::new(bits.finish().unwrap()),
739        )
740        .unwrap();
741
742        insta::assert_debug_snapshot!(obu_header, @r"
743        SequenceHeaderObu {
744            header: ObuHeader {
745                obu_type: SequenceHeader,
746                size: None,
747                extension_header: None,
748            },
749            seq_profile: 2,
750            still_picture: false,
751            reduced_still_picture_header: false,
752            timing_info: Some(
753                TimingInfo {
754                    num_units_in_display_tick: 1,
755                    time_scale: 1,
756                    num_ticks_per_picture: None,
757                },
758            ),
759            decoder_model_info: Some(
760                DecoderModelInfo {
761                    buffer_delay_length: 5,
762                    num_units_in_decoding_tick: 1,
763                    buffer_removal_time_length: 5,
764                    frame_presentation_time_length: 5,
765                },
766            ),
767            operating_points: [
768                OperatingPoint {
769                    idc: 0,
770                    seq_level_idx: 1,
771                    seq_tier: false,
772                    operating_parameters_info: Some(
773                        OperatingParametersInfo {
774                            decoder_buffer_delay: 10,
775                            encoder_buffer_delay: 5,
776                            low_delay_mode_flag: false,
777                        },
778                    ),
779                    initial_display_delay: Some(
780                        16,
781                    ),
782                },
783            ],
784            max_frame_width: 1920,
785            max_frame_height: 1080,
786            frame_ids: Some(
787                FrameIds {
788                    delta_frame_id_length: 15,
789                    additional_frame_id_length: 6,
790                },
791            ),
792            use_128x128_superblock: false,
793            enable_filter_intra: false,
794            enable_intra_edge_filter: false,
795            enable_interintra_compound: false,
796            enable_masked_compound: false,
797            enable_warped_motion: false,
798            enable_dual_filter: false,
799            enable_order_hint: true,
800            enable_jnt_comp: false,
801            enable_ref_frame_mvs: false,
802            seq_force_screen_content_tools: 1,
803            seq_force_integer_mv: 0,
804            order_hint_bits: 5,
805            enable_superres: false,
806            enable_cdef: false,
807            enable_restoration: false,
808            color_config: ColorConfig {
809                bit_depth: 8,
810                mono_chrome: true,
811                num_planes: 1,
812                color_primaries: 2,
813                transfer_characteristics: 2,
814                matrix_coefficients: 2,
815                full_color_range: true,
816                subsampling_x: true,
817                subsampling_y: true,
818                chroma_sample_position: 0,
819                separate_uv_delta_q: false,
820            },
821            film_grain_params_present: true,
822        }
823        ");
824    }
825
826    #[test]
827    fn test_seq_obu_parse_num_ticks_per_picture() {
828        let mut bits = BitWriter::new(Vec::new());
829
830        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
831        bits.write_bit(false).unwrap(); // still_picture
832        bits.write_bit(false).unwrap(); // reduced_still_picture_header
833        bits.write_bit(true).unwrap(); // timing_info_present_flag
834
835        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_display_tick
836        bits.write_u32::<BigEndian>(1).unwrap(); // time_scale
837        bits.write_bit(true).unwrap(); // num_ticks_per_picture
838        bits.write_bits(0b01, 1).unwrap(); // read_uvlc
839
840        bits.write_bit(true).unwrap(); // decoder_model_info_present_flag
841        bits.write_bits(4, 5).unwrap(); // buffer_delay_length
842        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_decoding_tick
843        bits.write_bits(4, 5).unwrap(); // buffer_removal_time_length
844        bits.write_bits(4, 5).unwrap(); // frame_presentation_time_length
845
846        bits.write_bit(true).unwrap(); // initial_display_delay_present_flag
847        bits.write_bits(0, 5).unwrap(); // operating_points_cnt_minus_1
848
849        bits.write_bits(0, 12).unwrap(); // idc
850        bits.write_bits(1, 5).unwrap(); // seq_lvl_idx
851        bits.write_bit(true).unwrap(); // seq_tier
852
853        bits.write_bits(0b1010, 5).unwrap(); // decoder_buffer_delay
854        bits.write_bits(0b0101, 5).unwrap(); // encoder_buffer_delay
855        bits.write_bit(false).unwrap(); // low_delay_mode_flag
856
857        bits.write_bit(true).unwrap(); // film_grain_params_present
858        bits.write_bits(15, 4).unwrap(); // initial_display_delay_minus_1
859
860        bits.write_bits(15, 4).unwrap(); // operating_points_cnt_minus_1
861        bits.write_bits(15, 4).unwrap(); // operating_points_cnt_minus_1
862        bits.write_bits(1919, 16).unwrap(); // operating_points_cnt_minus_1
863        bits.write_bits(1079, 16).unwrap(); // operating_points_cnt_minus_1
864
865        bits.write_bit(true).unwrap(); // frame_id_numbers_present_flag
866        bits.write_bits(0b1101, 4).unwrap(); // delta_frame_id_length
867        bits.write_bits(0b101, 3).unwrap(); // additional_frame_id_length
868
869        bits.write_bit(false).unwrap(); // use_128x128_superblock
870        bits.write_bit(false).unwrap(); // enable_filter_intra
871        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
872
873        bits.write_bit(false).unwrap(); // enable_interintra_compound
874        bits.write_bit(false).unwrap(); // enable_masked_compound
875        bits.write_bit(false).unwrap(); // enable_warped_motion
876        bits.write_bit(false).unwrap(); // enable_dual_filter
877        bits.write_bit(true).unwrap(); // enable_order_hint
878        bits.write_bit(false).unwrap(); // enable_jnt_comp
879        bits.write_bit(false).unwrap(); // enable_ref_frame_mvs
880
881        bits.write_bit(false).unwrap();
882        bits.write_bit(true).unwrap();
883        bits.write_bit(false).unwrap();
884        bits.write_bit(false).unwrap();
885
886        bits.write_bits(0b100, 3).unwrap();
887
888        bits.write_bit(false).unwrap(); // enable_superres
889        bits.write_bit(false).unwrap(); // enable_cdef
890        bits.write_bit(false).unwrap(); // enable_restoration
891
892        bits.write_bit(false).unwrap(); // high_bitdepth
893        bits.write_bit(true).unwrap(); // mono_chrome
894        bits.write_bit(false).unwrap(); // color_description_present_flag
895        bits.write_bit(true).unwrap(); // color_range
896        bits.write_bit(true).unwrap(); // separate_uv_delta_q
897
898        bits.write_bit(true).unwrap(); // film_grain_params_present
899
900        let obu_header = SequenceHeaderObu::parse(
901            ObuHeader {
902                obu_type: ObuType::SequenceHeader,
903                size: None,
904                extension_header: None,
905            },
906            &mut io::Cursor::new(bits.finish().unwrap()),
907        )
908        .unwrap();
909
910        insta::assert_debug_snapshot!(obu_header, @r"
911        SequenceHeaderObu {
912            header: ObuHeader {
913                obu_type: SequenceHeader,
914                size: None,
915                extension_header: None,
916            },
917            seq_profile: 2,
918            still_picture: false,
919            reduced_still_picture_header: false,
920            timing_info: Some(
921                TimingInfo {
922                    num_units_in_display_tick: 1,
923                    time_scale: 1,
924                    num_ticks_per_picture: Some(
925                        1,
926                    ),
927                },
928            ),
929            decoder_model_info: Some(
930                DecoderModelInfo {
931                    buffer_delay_length: 5,
932                    num_units_in_decoding_tick: 1,
933                    buffer_removal_time_length: 5,
934                    frame_presentation_time_length: 5,
935                },
936            ),
937            operating_points: [
938                OperatingPoint {
939                    idc: 0,
940                    seq_level_idx: 1,
941                    seq_tier: false,
942                    operating_parameters_info: Some(
943                        OperatingParametersInfo {
944                            decoder_buffer_delay: 10,
945                            encoder_buffer_delay: 5,
946                            low_delay_mode_flag: false,
947                        },
948                    ),
949                    initial_display_delay: Some(
950                        16,
951                    ),
952                },
953            ],
954            max_frame_width: 1920,
955            max_frame_height: 1080,
956            frame_ids: Some(
957                FrameIds {
958                    delta_frame_id_length: 15,
959                    additional_frame_id_length: 6,
960                },
961            ),
962            use_128x128_superblock: false,
963            enable_filter_intra: false,
964            enable_intra_edge_filter: false,
965            enable_interintra_compound: false,
966            enable_masked_compound: false,
967            enable_warped_motion: false,
968            enable_dual_filter: false,
969            enable_order_hint: true,
970            enable_jnt_comp: false,
971            enable_ref_frame_mvs: false,
972            seq_force_screen_content_tools: 1,
973            seq_force_integer_mv: 0,
974            order_hint_bits: 5,
975            enable_superres: false,
976            enable_cdef: false,
977            enable_restoration: false,
978            color_config: ColorConfig {
979                bit_depth: 8,
980                mono_chrome: true,
981                num_planes: 1,
982                color_primaries: 2,
983                transfer_characteristics: 2,
984                matrix_coefficients: 2,
985                full_color_range: true,
986                subsampling_x: true,
987                subsampling_y: true,
988                chroma_sample_position: 0,
989                separate_uv_delta_q: false,
990            },
991            film_grain_params_present: true,
992        }
993        ");
994    }
995
996    #[test]
997    fn test_seq_obu_parse_initial_display_delay_is_none() {
998        let mut bits = BitWriter::new(Vec::new());
999
1000        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
1001        bits.write_bit(false).unwrap(); // still_picture
1002        bits.write_bit(false).unwrap(); // reduced_still_picture_header
1003        bits.write_bit(true).unwrap(); // timing_info_present_flag
1004
1005        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_display_tick
1006        bits.write_u32::<BigEndian>(1).unwrap(); // time_scale
1007        bits.write_bit(false).unwrap(); // num_ticks_per_picture
1008
1009        bits.write_bit(true).unwrap(); // decoder_model_info_present_flag
1010        bits.write_bits(4, 5).unwrap(); // buffer_delay_length
1011        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_decoding_tick
1012        bits.write_bits(4, 5).unwrap(); // buffer_removal_time_length
1013        bits.write_bits(4, 5).unwrap(); // frame_presentation_time_length
1014
1015        bits.write_bit(true).unwrap(); // initial_display_delay_present_flag
1016        bits.write_bits(0, 5).unwrap(); // operating_points_cnt_minus_1
1017
1018        bits.write_bits(0, 12).unwrap(); // idc
1019        bits.write_bits(1, 5).unwrap(); // seq_lvl_idx
1020        bits.write_bit(true).unwrap(); // seq_tier
1021
1022        bits.write_bits(0b1010, 5).unwrap(); // decoder_buffer_delay
1023        bits.write_bits(0b0101, 5).unwrap(); // encoder_buffer_delay
1024        bits.write_bit(false).unwrap(); // low_delay_mode_flag
1025
1026        bits.write_bit(false).unwrap(); // initial_display_delay_present_for_this_op
1027
1028        bits.write_bits(11, 4).unwrap(); // frame_width_bits
1029        bits.write_bits(11, 4).unwrap(); // frame_height_bits
1030        bits.write_bits(1919, 12).unwrap(); // max_frame_width
1031        bits.write_bits(1079, 12).unwrap(); // max_frame_height
1032
1033        bits.write_bit(true).unwrap(); // frame_id_numbers_present_flag
1034        bits.write_bits(0b1101, 4).unwrap(); // delta_frame_id_length
1035        bits.write_bits(0b101, 3).unwrap(); // additional_frame_id_length
1036
1037        bits.write_bit(false).unwrap(); // use_128x128_superblock
1038        bits.write_bit(false).unwrap(); // enable_filter_intra
1039        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
1040
1041        bits.write_bit(false).unwrap(); // enable_interintra_compound
1042        bits.write_bit(false).unwrap(); // enable_masked_compound
1043        bits.write_bit(false).unwrap(); // enable_warped_motion
1044        bits.write_bit(false).unwrap(); // enable_dual_filter
1045        bits.write_bit(true).unwrap(); // enable_order_hint
1046        bits.write_bit(false).unwrap(); // enable_jnt_comp
1047        bits.write_bit(false).unwrap(); // enable_ref_frame_mvs
1048
1049        bits.write_bit(false).unwrap();
1050        bits.write_bit(true).unwrap();
1051        bits.write_bit(false).unwrap();
1052        bits.write_bit(false).unwrap();
1053
1054        bits.write_bits(0b100, 3).unwrap();
1055
1056        bits.write_bit(false).unwrap(); // enable_superres
1057        bits.write_bit(false).unwrap(); // enable_cdef
1058        bits.write_bit(false).unwrap(); // enable_restoration
1059
1060        bits.write_bit(false).unwrap(); // high_bitdepth
1061        bits.write_bit(true).unwrap(); // mono_chrome
1062        bits.write_bit(false).unwrap(); // color_description_present_flag
1063        bits.write_bit(true).unwrap(); // color_range
1064        bits.write_bit(true).unwrap(); // separate_uv_delta_q
1065
1066        bits.write_bit(true).unwrap(); // film_grain_params_present
1067
1068        let obu_header = SequenceHeaderObu::parse(
1069            ObuHeader {
1070                obu_type: ObuType::SequenceHeader,
1071                size: None,
1072                extension_header: None,
1073            },
1074            &mut io::Cursor::new(bits.finish().unwrap()),
1075        )
1076        .unwrap();
1077
1078        insta::assert_debug_snapshot!(obu_header, @r"
1079        SequenceHeaderObu {
1080            header: ObuHeader {
1081                obu_type: SequenceHeader,
1082                size: None,
1083                extension_header: None,
1084            },
1085            seq_profile: 2,
1086            still_picture: false,
1087            reduced_still_picture_header: false,
1088            timing_info: Some(
1089                TimingInfo {
1090                    num_units_in_display_tick: 1,
1091                    time_scale: 1,
1092                    num_ticks_per_picture: None,
1093                },
1094            ),
1095            decoder_model_info: Some(
1096                DecoderModelInfo {
1097                    buffer_delay_length: 5,
1098                    num_units_in_decoding_tick: 1,
1099                    buffer_removal_time_length: 5,
1100                    frame_presentation_time_length: 5,
1101                },
1102            ),
1103            operating_points: [
1104                OperatingPoint {
1105                    idc: 0,
1106                    seq_level_idx: 1,
1107                    seq_tier: false,
1108                    operating_parameters_info: Some(
1109                        OperatingParametersInfo {
1110                            decoder_buffer_delay: 10,
1111                            encoder_buffer_delay: 5,
1112                            low_delay_mode_flag: false,
1113                        },
1114                    ),
1115                    initial_display_delay: None,
1116                },
1117            ],
1118            max_frame_width: 1920,
1119            max_frame_height: 1080,
1120            frame_ids: Some(
1121                FrameIds {
1122                    delta_frame_id_length: 15,
1123                    additional_frame_id_length: 6,
1124                },
1125            ),
1126            use_128x128_superblock: false,
1127            enable_filter_intra: false,
1128            enable_intra_edge_filter: false,
1129            enable_interintra_compound: false,
1130            enable_masked_compound: false,
1131            enable_warped_motion: false,
1132            enable_dual_filter: false,
1133            enable_order_hint: true,
1134            enable_jnt_comp: false,
1135            enable_ref_frame_mvs: false,
1136            seq_force_screen_content_tools: 1,
1137            seq_force_integer_mv: 0,
1138            order_hint_bits: 5,
1139            enable_superres: false,
1140            enable_cdef: false,
1141            enable_restoration: false,
1142            color_config: ColorConfig {
1143                bit_depth: 8,
1144                mono_chrome: true,
1145                num_planes: 1,
1146                color_primaries: 2,
1147                transfer_characteristics: 2,
1148                matrix_coefficients: 2,
1149                full_color_range: true,
1150                subsampling_x: true,
1151                subsampling_y: true,
1152                chroma_sample_position: 0,
1153                separate_uv_delta_q: false,
1154            },
1155            film_grain_params_present: true,
1156        }
1157        ");
1158    }
1159
1160    #[test]
1161    fn test_seq_obu_parse_enable_order_hint_is_false() {
1162        let mut bits = BitWriter::new(Vec::new());
1163
1164        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
1165        bits.write_bit(false).unwrap(); // still_picture
1166        bits.write_bit(false).unwrap(); // reduced_still_picture_header
1167        bits.write_bit(true).unwrap(); // timing_info_present_flag
1168
1169        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_display_tick
1170        bits.write_u32::<BigEndian>(1).unwrap(); // time_scale
1171        bits.write_bit(false).unwrap(); // num_ticks_per_picture
1172
1173        bits.write_bit(true).unwrap(); // decoder_model_info_present_flag
1174        bits.write_bits(4, 5).unwrap(); // buffer_delay_length
1175        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_decoding_tick
1176        bits.write_bits(4, 5).unwrap(); // buffer_removal_time_length
1177        bits.write_bits(4, 5).unwrap(); // frame_presentation_time_length
1178
1179        bits.write_bit(true).unwrap(); // initial_display_delay_present_flag
1180        bits.write_bits(0, 5).unwrap(); // operating_points_cnt_minus_1
1181
1182        bits.write_bits(0, 12).unwrap(); // idc
1183        bits.write_bits(1, 5).unwrap(); // seq_lvl_idx
1184        bits.write_bit(true).unwrap(); // seq_tier
1185
1186        bits.write_bits(0b1010, 5).unwrap(); // decoder_buffer_delay
1187        bits.write_bits(0b0101, 5).unwrap(); // encoder_buffer_delay
1188        bits.write_bit(false).unwrap(); // low_delay_mode_flag
1189
1190        bits.write_bit(false).unwrap(); // initial_display_delay_present_for_this_op
1191
1192        bits.write_bits(11, 4).unwrap(); // frame_width_bits
1193        bits.write_bits(11, 4).unwrap(); // frame_height_bits
1194        bits.write_bits(1919, 12).unwrap(); // max_frame_width
1195        bits.write_bits(1079, 12).unwrap(); // max_frame_height
1196
1197        bits.write_bit(true).unwrap(); // frame_id_numbers_present_flag
1198        bits.write_bits(0b1101, 4).unwrap(); // delta_frame_id_length
1199        bits.write_bits(0b101, 3).unwrap(); // additional_frame_id_length
1200
1201        bits.write_bit(false).unwrap(); // use_128x128_superblock
1202        bits.write_bit(false).unwrap(); // enable_filter_intra
1203        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
1204
1205        bits.write_bit(false).unwrap(); // enable_interintra_compound
1206        bits.write_bit(false).unwrap(); // enable_masked_compound
1207        bits.write_bit(false).unwrap(); // enable_warped_motion
1208        bits.write_bit(false).unwrap(); // enable_dual_filter
1209        bits.write_bit(false).unwrap(); // enable_order_hint
1210
1211        bits.write_bit(true).unwrap(); // seq_choose_screen_content_tools
1212        bits.write_bit(true).unwrap(); // sets seq_force_integer_mv to be 2
1213
1214        bits.write_bit(false).unwrap(); // enable_superres
1215        bits.write_bit(false).unwrap(); // enable_cdef
1216        bits.write_bit(false).unwrap(); // enable_restoration
1217
1218        bits.write_bit(false).unwrap(); // high_bitdepth
1219        bits.write_bit(true).unwrap(); // mono_chrome
1220        bits.write_bit(false).unwrap(); // color_description_present_flag
1221        bits.write_bit(true).unwrap(); // color_range
1222        bits.write_bit(true).unwrap(); // separate_uv_delta_q
1223
1224        bits.write_bit(true).unwrap(); // film_grain_params_present
1225
1226        let obu_header = SequenceHeaderObu::parse(
1227            ObuHeader {
1228                obu_type: ObuType::SequenceHeader,
1229                size: None,
1230                extension_header: None,
1231            },
1232            &mut io::Cursor::new(bits.finish().unwrap()),
1233        )
1234        .unwrap();
1235
1236        insta::assert_debug_snapshot!(obu_header, @r"
1237        SequenceHeaderObu {
1238            header: ObuHeader {
1239                obu_type: SequenceHeader,
1240                size: None,
1241                extension_header: None,
1242            },
1243            seq_profile: 2,
1244            still_picture: false,
1245            reduced_still_picture_header: false,
1246            timing_info: Some(
1247                TimingInfo {
1248                    num_units_in_display_tick: 1,
1249                    time_scale: 1,
1250                    num_ticks_per_picture: None,
1251                },
1252            ),
1253            decoder_model_info: Some(
1254                DecoderModelInfo {
1255                    buffer_delay_length: 5,
1256                    num_units_in_decoding_tick: 1,
1257                    buffer_removal_time_length: 5,
1258                    frame_presentation_time_length: 5,
1259                },
1260            ),
1261            operating_points: [
1262                OperatingPoint {
1263                    idc: 0,
1264                    seq_level_idx: 1,
1265                    seq_tier: false,
1266                    operating_parameters_info: Some(
1267                        OperatingParametersInfo {
1268                            decoder_buffer_delay: 10,
1269                            encoder_buffer_delay: 5,
1270                            low_delay_mode_flag: false,
1271                        },
1272                    ),
1273                    initial_display_delay: None,
1274                },
1275            ],
1276            max_frame_width: 1920,
1277            max_frame_height: 1080,
1278            frame_ids: Some(
1279                FrameIds {
1280                    delta_frame_id_length: 15,
1281                    additional_frame_id_length: 6,
1282                },
1283            ),
1284            use_128x128_superblock: false,
1285            enable_filter_intra: false,
1286            enable_intra_edge_filter: false,
1287            enable_interintra_compound: false,
1288            enable_masked_compound: false,
1289            enable_warped_motion: false,
1290            enable_dual_filter: false,
1291            enable_order_hint: false,
1292            enable_jnt_comp: false,
1293            enable_ref_frame_mvs: false,
1294            seq_force_screen_content_tools: 2,
1295            seq_force_integer_mv: 2,
1296            order_hint_bits: 0,
1297            enable_superres: false,
1298            enable_cdef: false,
1299            enable_restoration: false,
1300            color_config: ColorConfig {
1301                bit_depth: 8,
1302                mono_chrome: true,
1303                num_planes: 1,
1304                color_primaries: 2,
1305                transfer_characteristics: 2,
1306                matrix_coefficients: 2,
1307                full_color_range: true,
1308                subsampling_x: true,
1309                subsampling_y: true,
1310                chroma_sample_position: 0,
1311                separate_uv_delta_q: false,
1312            },
1313            film_grain_params_present: true,
1314        }
1315        ");
1316    }
1317
1318    #[test]
1319    fn test_seq_obu_parse_decoder_model_info_present_is_false() {
1320        let mut bits = BitWriter::new(Vec::new());
1321
1322        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
1323        bits.write_bit(false).unwrap(); // still_picture
1324        bits.write_bit(false).unwrap(); // reduced_still_picture_header
1325        bits.write_bit(true).unwrap(); // timing_info_present_flag
1326
1327        bits.write_u32::<BigEndian>(1).unwrap(); // num_units_in_display_tick
1328        bits.write_u32::<BigEndian>(1).unwrap(); // time_scale
1329        bits.write_bit(false).unwrap(); // num_ticks_per_picture
1330
1331        bits.write_bit(false).unwrap(); // decoder_model_info_present_flag
1332
1333        bits.write_bit(true).unwrap(); // initial_display_delay_present_flag
1334        bits.write_bits(0, 5).unwrap(); // operating_points_cnt_minus_1
1335
1336        bits.write_bits(0, 12).unwrap(); // idc
1337        bits.write_bits(1, 5).unwrap(); // seq_lvl_idx
1338
1339        bits.write_bit(false).unwrap(); // initial_display_delay_present_for_this_op
1340
1341        bits.write_bits(11, 4).unwrap(); // frame_width_bits
1342        bits.write_bits(11, 4).unwrap(); // frame_height_bits
1343        bits.write_bits(1919, 12).unwrap(); // max_frame_width
1344        bits.write_bits(1079, 12).unwrap(); // max_frame_height
1345
1346        bits.write_bit(true).unwrap(); // frame_id_numbers_present_flag
1347        bits.write_bits(0b1101, 4).unwrap(); // delta_frame_id_length
1348        bits.write_bits(0b101, 3).unwrap(); // additional_frame_id_length
1349
1350        bits.write_bit(false).unwrap(); // use_128x128_superblock
1351        bits.write_bit(false).unwrap(); // enable_filter_intra
1352        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
1353
1354        bits.write_bit(false).unwrap(); // enable_interintra_compound
1355        bits.write_bit(false).unwrap(); // enable_masked_compound
1356        bits.write_bit(false).unwrap(); // enable_warped_motion
1357        bits.write_bit(false).unwrap(); // enable_dual_filter
1358        bits.write_bit(false).unwrap(); // enable_order_hint
1359
1360        bits.write_bit(true).unwrap(); // seq_choose_screen_content_tools
1361        bits.write_bit(true).unwrap(); // sets seq_force_integer_mv to be 2
1362
1363        bits.write_bit(false).unwrap(); // enable_superres
1364        bits.write_bit(false).unwrap(); // enable_cdef
1365        bits.write_bit(false).unwrap(); // enable_restoration
1366
1367        bits.write_bit(false).unwrap(); // high_bitdepth
1368        bits.write_bit(true).unwrap(); // mono_chrome
1369        bits.write_bit(false).unwrap(); // color_description_present_flag
1370        bits.write_bit(true).unwrap(); // color_range
1371        bits.write_bit(true).unwrap(); // separate_uv_delta_q
1372
1373        bits.write_bit(true).unwrap(); // film_grain_params_present
1374
1375        let obu_header = SequenceHeaderObu::parse(
1376            ObuHeader {
1377                obu_type: ObuType::SequenceHeader,
1378                size: None,
1379                extension_header: None,
1380            },
1381            &mut io::Cursor::new(bits.finish().unwrap()),
1382        )
1383        .unwrap();
1384
1385        insta::assert_debug_snapshot!(obu_header, @r"
1386        SequenceHeaderObu {
1387            header: ObuHeader {
1388                obu_type: SequenceHeader,
1389                size: None,
1390                extension_header: None,
1391            },
1392            seq_profile: 2,
1393            still_picture: false,
1394            reduced_still_picture_header: false,
1395            timing_info: Some(
1396                TimingInfo {
1397                    num_units_in_display_tick: 1,
1398                    time_scale: 1,
1399                    num_ticks_per_picture: None,
1400                },
1401            ),
1402            decoder_model_info: None,
1403            operating_points: [
1404                OperatingPoint {
1405                    idc: 0,
1406                    seq_level_idx: 1,
1407                    seq_tier: false,
1408                    operating_parameters_info: None,
1409                    initial_display_delay: None,
1410                },
1411            ],
1412            max_frame_width: 1920,
1413            max_frame_height: 1080,
1414            frame_ids: Some(
1415                FrameIds {
1416                    delta_frame_id_length: 15,
1417                    additional_frame_id_length: 6,
1418                },
1419            ),
1420            use_128x128_superblock: false,
1421            enable_filter_intra: false,
1422            enable_intra_edge_filter: false,
1423            enable_interintra_compound: false,
1424            enable_masked_compound: false,
1425            enable_warped_motion: false,
1426            enable_dual_filter: false,
1427            enable_order_hint: false,
1428            enable_jnt_comp: false,
1429            enable_ref_frame_mvs: false,
1430            seq_force_screen_content_tools: 2,
1431            seq_force_integer_mv: 2,
1432            order_hint_bits: 0,
1433            enable_superres: false,
1434            enable_cdef: false,
1435            enable_restoration: false,
1436            color_config: ColorConfig {
1437                bit_depth: 8,
1438                mono_chrome: true,
1439                num_planes: 1,
1440                color_primaries: 2,
1441                transfer_characteristics: 2,
1442                matrix_coefficients: 2,
1443                full_color_range: true,
1444                subsampling_x: true,
1445                subsampling_y: true,
1446                chroma_sample_position: 0,
1447                separate_uv_delta_q: false,
1448            },
1449            film_grain_params_present: true,
1450        }
1451        ");
1452    }
1453
1454    #[test]
1455    fn test_seq_obu_parse_color_range_and_subsampling() {
1456        let mut bits = BitWriter::new(Vec::new());
1457
1458        bits.write_bit(false).unwrap(); // color_range
1459        bits.write_bit(false).unwrap(); // subsampling_x
1460        bits.write_bit(false).unwrap(); // subsampling_y
1461
1462        let color_range_and_subsampling = ColorConfig::parse_color_range_and_subsampling(
1463            &mut BitReader::new(std::io::Cursor::new(Vec::new())),
1464            0,
1465            1,
1466            13,
1467            0,
1468            8,
1469        )
1470        .unwrap();
1471
1472        assert_eq!(
1473            color_range_and_subsampling,
1474            ColorRangeAndSubsampling {
1475                color_range: true,
1476                subsampling_x: false,
1477                subsampling_y: false,
1478            }
1479        );
1480
1481        let color_range_and_subsampling = ColorConfig::parse_color_range_and_subsampling(
1482            &mut BitReader::new(std::io::Cursor::new(&[0b10000000])),
1483            0,
1484            1,
1485            0,
1486            0,
1487            8,
1488        )
1489        .unwrap();
1490
1491        assert_eq!(
1492            color_range_and_subsampling,
1493            ColorRangeAndSubsampling {
1494                color_range: true,
1495                subsampling_x: true,
1496                subsampling_y: true,
1497            }
1498        );
1499
1500        let color_range_and_subsampling = ColorConfig::parse_color_range_and_subsampling(
1501            &mut BitReader::new(std::io::Cursor::new(&[0b10000000])),
1502            1,
1503            1,
1504            0,
1505            0,
1506            8,
1507        )
1508        .unwrap();
1509
1510        assert_eq!(
1511            color_range_and_subsampling,
1512            ColorRangeAndSubsampling {
1513                color_range: true,
1514                subsampling_x: false,
1515                subsampling_y: false,
1516            }
1517        );
1518
1519        let color_range_and_subsampling = ColorConfig::parse_color_range_and_subsampling(
1520            &mut BitReader::new(std::io::Cursor::new(&[0b11100000])),
1521            2,
1522            1,
1523            0,
1524            0,
1525            12,
1526        )
1527        .unwrap();
1528
1529        assert_eq!(
1530            color_range_and_subsampling,
1531            ColorRangeAndSubsampling {
1532                color_range: true,
1533                subsampling_x: true,
1534                subsampling_y: true,
1535            }
1536        );
1537
1538        let color_range_and_subsampling = ColorConfig::parse_color_range_and_subsampling(
1539            &mut BitReader::new(std::io::Cursor::new(&[0b11000000])),
1540            2,
1541            1,
1542            0,
1543            0,
1544            12,
1545        )
1546        .unwrap();
1547
1548        assert_eq!(
1549            color_range_and_subsampling,
1550            ColorRangeAndSubsampling {
1551                color_range: true,
1552                subsampling_x: true,
1553                subsampling_y: false,
1554            }
1555        );
1556
1557        let color_range_and_subsampling = ColorConfig::parse_color_range_and_subsampling(
1558            &mut BitReader::new(std::io::Cursor::new(&[0b10100000])),
1559            2,
1560            1,
1561            0,
1562            0,
1563            12,
1564        )
1565        .unwrap();
1566
1567        assert_eq!(
1568            color_range_and_subsampling,
1569            ColorRangeAndSubsampling {
1570                color_range: true,
1571                subsampling_x: false,
1572                subsampling_y: false,
1573            }
1574        );
1575
1576        let color_range_and_subsampling = ColorConfig::parse_color_range_and_subsampling(
1577            &mut BitReader::new(std::io::Cursor::new(&[0b11100000])),
1578            2,
1579            1,
1580            0,
1581            0,
1582            8,
1583        )
1584        .unwrap();
1585
1586        assert_eq!(
1587            color_range_and_subsampling,
1588            ColorRangeAndSubsampling {
1589                color_range: true,
1590                subsampling_x: true,
1591                subsampling_y: false,
1592            }
1593        );
1594    }
1595
1596    #[test]
1597    fn test_color_config_parse_bit_depth_12() {
1598        let mut bits = BitWriter::new(Vec::new());
1599
1600        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
1601        bits.write_bit(true).unwrap(); // still_picture
1602        bits.write_bit(true).unwrap(); // reduced_still_picture_header
1603        bits.write_bits(11, 5).unwrap(); // seq_lvl_idx
1604
1605        bits.write_bits(15, 4).unwrap();
1606        bits.write_bits(15, 4).unwrap();
1607        bits.write_bits(1919, 16).unwrap();
1608        bits.write_bits(1079, 16).unwrap();
1609
1610        bits.write_bit(false).unwrap(); // use_128x128_superblock
1611        bits.write_bit(false).unwrap(); // enable_filter_intra
1612        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
1613        bits.write_bit(false).unwrap(); // enable_superres
1614        bits.write_bit(false).unwrap(); // enable_cdef
1615        bits.write_bit(false).unwrap(); // enable_restoration
1616
1617        bits.write_bit(true).unwrap(); // high_bitdepth
1618        bits.write_bit(true).unwrap(); // sets bitdepth to 12 instead of 10
1619        bits.write_bit(true).unwrap(); // mono_chrome
1620        bits.write_bit(false).unwrap(); // color_description_present_flag
1621        bits.write_bit(true).unwrap(); // color_range
1622        bits.write_bit(true).unwrap(); // separate_uv_delta_q
1623
1624        bits.write_bit(true).unwrap(); // film_grain_params_present
1625
1626        let obu_header = SequenceHeaderObu::parse(
1627            ObuHeader {
1628                obu_type: ObuType::SequenceHeader,
1629                size: None,
1630                extension_header: None,
1631            },
1632            &mut io::Cursor::new(bits.finish().unwrap()),
1633        )
1634        .unwrap();
1635
1636        insta::assert_debug_snapshot!(obu_header, @r"
1637        SequenceHeaderObu {
1638            header: ObuHeader {
1639                obu_type: SequenceHeader,
1640                size: None,
1641                extension_header: None,
1642            },
1643            seq_profile: 2,
1644            still_picture: true,
1645            reduced_still_picture_header: true,
1646            timing_info: None,
1647            decoder_model_info: None,
1648            operating_points: [
1649                OperatingPoint {
1650                    idc: 0,
1651                    seq_level_idx: 11,
1652                    seq_tier: false,
1653                    operating_parameters_info: None,
1654                    initial_display_delay: None,
1655                },
1656            ],
1657            max_frame_width: 1920,
1658            max_frame_height: 1080,
1659            frame_ids: None,
1660            use_128x128_superblock: false,
1661            enable_filter_intra: false,
1662            enable_intra_edge_filter: false,
1663            enable_interintra_compound: false,
1664            enable_masked_compound: false,
1665            enable_warped_motion: false,
1666            enable_dual_filter: false,
1667            enable_order_hint: false,
1668            enable_jnt_comp: false,
1669            enable_ref_frame_mvs: false,
1670            seq_force_screen_content_tools: 2,
1671            seq_force_integer_mv: 2,
1672            order_hint_bits: 0,
1673            enable_superres: false,
1674            enable_cdef: false,
1675            enable_restoration: false,
1676            color_config: ColorConfig {
1677                bit_depth: 12,
1678                mono_chrome: true,
1679                num_planes: 1,
1680                color_primaries: 2,
1681                transfer_characteristics: 2,
1682                matrix_coefficients: 2,
1683                full_color_range: true,
1684                subsampling_x: true,
1685                subsampling_y: true,
1686                chroma_sample_position: 0,
1687                separate_uv_delta_q: false,
1688            },
1689            film_grain_params_present: true,
1690        }
1691        ");
1692    }
1693
1694    #[test]
1695    fn test_color_config_parse_bit_depth_10() {
1696        let mut bits = BitWriter::new(Vec::new());
1697
1698        bits.write_bits(0b010, 3).unwrap(); // seq_profile (2)
1699        bits.write_bit(true).unwrap(); // still_picture
1700        bits.write_bit(true).unwrap(); // reduced_still_picture_header
1701        bits.write_bits(11, 5).unwrap(); // seq_lvl_idx
1702
1703        bits.write_bits(15, 4).unwrap();
1704        bits.write_bits(15, 4).unwrap();
1705        bits.write_bits(1919, 16).unwrap();
1706        bits.write_bits(1079, 16).unwrap();
1707
1708        bits.write_bit(false).unwrap(); // use_128x128_superblock
1709        bits.write_bit(false).unwrap(); // enable_filter_intra
1710        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
1711        bits.write_bit(false).unwrap(); // enable_superres
1712        bits.write_bit(false).unwrap(); // enable_cdef
1713        bits.write_bit(false).unwrap(); // enable_restoration
1714
1715        bits.write_bit(true).unwrap(); // high_bitdepth
1716        bits.write_bit(false).unwrap(); // sets bitdepth to 10 instead of 12
1717        bits.write_bit(true).unwrap(); // mono_chrome
1718        bits.write_bit(false).unwrap(); // color_description_present_flag
1719        bits.write_bit(true).unwrap(); // color_range
1720        bits.write_bit(true).unwrap(); // separate_uv_delta_q
1721
1722        bits.write_bit(true).unwrap(); // film_grain_params_present
1723
1724        let obu_header = SequenceHeaderObu::parse(
1725            ObuHeader {
1726                obu_type: ObuType::SequenceHeader,
1727                size: None,
1728                extension_header: None,
1729            },
1730            &mut io::Cursor::new(bits.finish().unwrap()),
1731        )
1732        .unwrap();
1733
1734        insta::assert_debug_snapshot!(obu_header, @r"
1735        SequenceHeaderObu {
1736            header: ObuHeader {
1737                obu_type: SequenceHeader,
1738                size: None,
1739                extension_header: None,
1740            },
1741            seq_profile: 2,
1742            still_picture: true,
1743            reduced_still_picture_header: true,
1744            timing_info: None,
1745            decoder_model_info: None,
1746            operating_points: [
1747                OperatingPoint {
1748                    idc: 0,
1749                    seq_level_idx: 11,
1750                    seq_tier: false,
1751                    operating_parameters_info: None,
1752                    initial_display_delay: None,
1753                },
1754            ],
1755            max_frame_width: 1920,
1756            max_frame_height: 1080,
1757            frame_ids: None,
1758            use_128x128_superblock: false,
1759            enable_filter_intra: false,
1760            enable_intra_edge_filter: false,
1761            enable_interintra_compound: false,
1762            enable_masked_compound: false,
1763            enable_warped_motion: false,
1764            enable_dual_filter: false,
1765            enable_order_hint: false,
1766            enable_jnt_comp: false,
1767            enable_ref_frame_mvs: false,
1768            seq_force_screen_content_tools: 2,
1769            seq_force_integer_mv: 2,
1770            order_hint_bits: 0,
1771            enable_superres: false,
1772            enable_cdef: false,
1773            enable_restoration: false,
1774            color_config: ColorConfig {
1775                bit_depth: 10,
1776                mono_chrome: true,
1777                num_planes: 1,
1778                color_primaries: 2,
1779                transfer_characteristics: 2,
1780                matrix_coefficients: 2,
1781                full_color_range: true,
1782                subsampling_x: true,
1783                subsampling_y: true,
1784                chroma_sample_position: 0,
1785                separate_uv_delta_q: false,
1786            },
1787            film_grain_params_present: true,
1788        }
1789        ");
1790    }
1791
1792    #[test]
1793    fn test_color_config_parse_csp_unknown() {
1794        let mut bits = BitWriter::new(Vec::new());
1795
1796        bits.write_bits(0b001, 3).unwrap(); // seq_profile (1)
1797        bits.write_bit(true).unwrap(); // still_picture
1798        bits.write_bit(true).unwrap(); // reduced_still_picture_header
1799        bits.write_bits(11, 5).unwrap(); // seq_lvl_idx
1800
1801        bits.write_bits(15, 4).unwrap();
1802        bits.write_bits(15, 4).unwrap();
1803        bits.write_bits(1919, 16).unwrap();
1804        bits.write_bits(1079, 16).unwrap();
1805
1806        bits.write_bit(false).unwrap(); // use_128x128_superblock
1807        bits.write_bit(false).unwrap(); // enable_filter_intra
1808        bits.write_bit(false).unwrap(); // enable_intra_edge_filter
1809        bits.write_bit(false).unwrap(); // enable_superres
1810        bits.write_bit(false).unwrap(); // enable_cdef
1811        bits.write_bit(false).unwrap(); // enable_restoration
1812
1813        bits.write_bit(false).unwrap(); // high_bitdepth
1814        bits.write_bit(false).unwrap(); // mono_chrome
1815        bits.write_bit(false).unwrap(); // color_description_present_flag
1816        bits.write_bit(true).unwrap(); // separate_uv_delta_q
1817
1818        bits.write_bit(true).unwrap(); // film_grain_params_present
1819
1820        let obu_header = SequenceHeaderObu::parse(
1821            ObuHeader {
1822                obu_type: ObuType::SequenceHeader,
1823                size: None,
1824                extension_header: None,
1825            },
1826            &mut io::Cursor::new(bits.finish().unwrap()),
1827        )
1828        .unwrap();
1829
1830        insta::assert_debug_snapshot!(obu_header, @r"
1831        SequenceHeaderObu {
1832            header: ObuHeader {
1833                obu_type: SequenceHeader,
1834                size: None,
1835                extension_header: None,
1836            },
1837            seq_profile: 1,
1838            still_picture: true,
1839            reduced_still_picture_header: true,
1840            timing_info: None,
1841            decoder_model_info: None,
1842            operating_points: [
1843                OperatingPoint {
1844                    idc: 0,
1845                    seq_level_idx: 11,
1846                    seq_tier: false,
1847                    operating_parameters_info: None,
1848                    initial_display_delay: None,
1849                },
1850            ],
1851            max_frame_width: 1920,
1852            max_frame_height: 1080,
1853            frame_ids: None,
1854            use_128x128_superblock: false,
1855            enable_filter_intra: false,
1856            enable_intra_edge_filter: false,
1857            enable_interintra_compound: false,
1858            enable_masked_compound: false,
1859            enable_warped_motion: false,
1860            enable_dual_filter: false,
1861            enable_order_hint: false,
1862            enable_jnt_comp: false,
1863            enable_ref_frame_mvs: false,
1864            seq_force_screen_content_tools: 2,
1865            seq_force_integer_mv: 2,
1866            order_hint_bits: 0,
1867            enable_superres: false,
1868            enable_cdef: false,
1869            enable_restoration: false,
1870            color_config: ColorConfig {
1871                bit_depth: 8,
1872                mono_chrome: false,
1873                num_planes: 3,
1874                color_primaries: 2,
1875                transfer_characteristics: 2,
1876                matrix_coefficients: 2,
1877                full_color_range: false,
1878                subsampling_x: false,
1879                subsampling_y: false,
1880                chroma_sample_position: 0,
1881                separate_uv_delta_q: true,
1882            },
1883            film_grain_params_present: true,
1884        }
1885        ");
1886    }
1887}