media-codec-h265 0.1.1

An H.265 decoder implementation for media-codec
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
//! H.265/HEVC Video Parameter Set (VPS) parser

use std::io::Read;

use media_codec_bitstream::{BigEndian, BitReader};
use media_core::{invalid_data_error, Result};
use smallvec::SmallVec;

use crate::constants::{MAX_CPB_COUNT, MAX_SUB_LAYERS, MAX_VPS_COUNT, MAX_VPS_LAYERS};

/// Profile Tier Level information
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ProfileTierLevel {
    /// General profile space (2 bits)
    pub general_profile_space: u8,
    /// General tier flag (0=Main tier, 1=High tier)
    pub general_tier_flag: bool,
    /// General profile IDC
    pub general_profile_idc: u8,
    /// General profile compatibility flags (32 flags)
    pub general_profile_compatibility_flags: u32,
    /// General progressive source flag
    pub general_progressive_source_flag: bool,
    /// General interlaced source flag
    pub general_interlaced_source_flag: bool,
    /// General non-packed constraint flag
    pub general_non_packed_constraint_flag: bool,
    /// General frame only constraint flag
    pub general_frame_only_constraint_flag: bool,
    /// General constraint indicator flags (44 bits stored as upper 44 bits)
    pub general_constraint_indicator_flags: u64,
    /// General level IDC
    pub general_level_idc: u8,
    /// Sub-layer profile present flags
    pub sub_layer_profile_present_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Sub-layer level present flags
    pub sub_layer_level_present_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Sub-layer profile space
    pub sub_layer_profile_space: SmallVec<[u8; MAX_SUB_LAYERS]>,
    /// Sub-layer tier flag
    pub sub_layer_tier_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Sub-layer profile IDC
    pub sub_layer_profile_idc: SmallVec<[u8; MAX_SUB_LAYERS]>,
    /// Sub-layer profile compatibility flags
    pub sub_layer_profile_compatibility_flags: SmallVec<[u32; MAX_SUB_LAYERS]>,
    /// Sub-layer progressive source flag
    pub sub_layer_progressive_source_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Sub-layer interlaced source flag
    pub sub_layer_interlaced_source_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Sub-layer non-packed constraint flag
    pub sub_layer_non_packed_constraint_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Sub-layer frame only constraint flag
    pub sub_layer_frame_only_constraint_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Sub-layer constraint indicator flags
    pub sub_layer_constraint_indicator_flags: SmallVec<[u64; MAX_SUB_LAYERS]>,
    /// Sub-layer level IDC
    pub sub_layer_level_idc: SmallVec<[u8; MAX_SUB_LAYERS]>,
}

impl ProfileTierLevel {
    /// Parse ProfileTierLevel from a BitReader
    pub fn parse<R: Read>(reader: &mut BitReader<R, BigEndian>, profile_present_flag: bool, max_num_sub_layers: u8) -> Result<Self> {
        let mut ptl = Self::default();

        if profile_present_flag {
            // Read general_profile_space (2 bits)
            ptl.general_profile_space = reader.read::<2, u8>()?;
            // Read general_tier_flag (1 bit)
            ptl.general_tier_flag = reader.read_bit()?;
            // Read general_profile_idc (5 bits)
            ptl.general_profile_idc = reader.read::<5, u8>()?;
            // Read general_profile_compatibility_flag[32] (32 bits)
            ptl.general_profile_compatibility_flags = reader.read::<32, u32>()?;
            // Read general_progressive_source_flag
            ptl.general_progressive_source_flag = reader.read_bit()?;
            // Read general_interlaced_source_flag
            ptl.general_interlaced_source_flag = reader.read_bit()?;
            // Read general_non_packed_constraint_flag
            ptl.general_non_packed_constraint_flag = reader.read_bit()?;
            // Read general_frame_only_constraint_flag
            ptl.general_frame_only_constraint_flag = reader.read_bit()?;
            // Read general_reserved_zero_44bits (44 bits - constraint indicator flags)
            let high = reader.read::<32, u64>()?;
            let low = reader.read::<12, u64>()?;
            ptl.general_constraint_indicator_flags = (high << 12) | low;
        }

        // general_level_idc
        ptl.general_level_idc = reader.read::<8, u8>()?;

        // Sub-layer flags (count = max_num_sub_layers - 1)
        let sub_layer_count = (max_num_sub_layers - 1) as usize;
        ptl.sub_layer_profile_present_flag.reserve(sub_layer_count);
        ptl.sub_layer_level_present_flag.reserve(sub_layer_count);

        for _ in 0..sub_layer_count {
            ptl.sub_layer_profile_present_flag.push(reader.read_bit()?);
            ptl.sub_layer_level_present_flag.push(reader.read_bit()?);
        }

        // Reserved bits for alignment if max_num_sub_layers > 1
        if max_num_sub_layers > 1 {
            for _ in sub_layer_count..8 {
                let _ = reader.read::<2, u8>()?; // reserved_zero_2bits
            }
        }

        // Sub-layer profile and level data
        ptl.sub_layer_profile_space = smallvec::smallvec![0; sub_layer_count];
        ptl.sub_layer_tier_flag = smallvec::smallvec![false; sub_layer_count];
        ptl.sub_layer_profile_idc = smallvec::smallvec![0; sub_layer_count];
        ptl.sub_layer_profile_compatibility_flags = smallvec::smallvec![0; sub_layer_count];
        ptl.sub_layer_progressive_source_flag = smallvec::smallvec![false; sub_layer_count];
        ptl.sub_layer_interlaced_source_flag = smallvec::smallvec![false; sub_layer_count];
        ptl.sub_layer_non_packed_constraint_flag = smallvec::smallvec![false; sub_layer_count];
        ptl.sub_layer_frame_only_constraint_flag = smallvec::smallvec![false; sub_layer_count];
        ptl.sub_layer_constraint_indicator_flags = smallvec::smallvec![0; sub_layer_count];
        ptl.sub_layer_level_idc = smallvec::smallvec![0; sub_layer_count];

        for i in 0..sub_layer_count {
            if ptl.sub_layer_profile_present_flag[i] {
                ptl.sub_layer_profile_space[i] = reader.read::<2, u8>()?;
                ptl.sub_layer_tier_flag[i] = reader.read_bit()?;
                ptl.sub_layer_profile_idc[i] = reader.read::<5, u8>()?;
                ptl.sub_layer_profile_compatibility_flags[i] = reader.read::<32, u32>()?;
                ptl.sub_layer_progressive_source_flag[i] = reader.read_bit()?;
                ptl.sub_layer_interlaced_source_flag[i] = reader.read_bit()?;
                ptl.sub_layer_non_packed_constraint_flag[i] = reader.read_bit()?;
                ptl.sub_layer_frame_only_constraint_flag[i] = reader.read_bit()?;
                let high = reader.read::<32, u64>()?;
                let low = reader.read::<12, u64>()?;
                ptl.sub_layer_constraint_indicator_flags[i] = (high << 12) | low;
            }
            if ptl.sub_layer_level_present_flag[i] {
                ptl.sub_layer_level_idc[i] = reader.read::<8, u8>()?;
            }
        }

        Ok(ptl)
    }

    /// Check if general profile compatibility flag is set
    #[inline]
    pub fn is_profile_compatible(&self, profile_idc: u8) -> bool {
        if profile_idc < 32 {
            (self.general_profile_compatibility_flags >> (31 - profile_idc)) & 1 != 0
        } else {
            false
        }
    }

    /// Check if this is Main profile
    #[inline]
    pub fn is_main_profile(&self) -> bool {
        self.general_profile_idc == 1 || self.is_profile_compatible(1)
    }

    /// Check if this is Main 10 profile
    #[inline]
    pub fn is_main_10_profile(&self) -> bool {
        self.general_profile_idc == 2 || self.is_profile_compatible(2)
    }

    /// Check if this is Main Still Picture profile
    #[inline]
    pub fn is_main_still_picture_profile(&self) -> bool {
        self.general_profile_idc == 3 || self.is_profile_compatible(3)
    }

    /// Check if this is Range Extensions profile
    #[inline]
    pub fn is_range_extensions_profile(&self) -> bool {
        self.general_profile_idc == 4 || self.is_profile_compatible(4)
    }

    /// Get level as floating point (e.g., 5.1 = 153 / 30 = 5.1)
    #[inline]
    pub fn level(&self) -> f32 {
        self.general_level_idc as f32 / 30.0
    }

    /// Check if high tier
    #[inline]
    pub fn is_high_tier(&self) -> bool {
        self.general_tier_flag
    }
}

/// Sub-layer HRD parameters
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct SubLayerHrdParameters {
    /// Bit rate values
    pub bit_rate_value: SmallVec<[u32; MAX_CPB_COUNT]>,
    /// CPB size values
    pub cpb_size_value: SmallVec<[u32; MAX_CPB_COUNT]>,
    /// CPB size DU values (if sub_pic_hrd_params_present_flag)
    pub cpb_size_du_value: SmallVec<[u32; MAX_CPB_COUNT]>,
    /// Bit rate DU values (if sub_pic_hrd_params_present_flag)
    pub bit_rate_du_value: SmallVec<[u32; MAX_CPB_COUNT]>,
    /// CBR flags
    pub cbr_flag: SmallVec<[bool; MAX_CPB_COUNT]>,
}

impl SubLayerHrdParameters {
    /// Parse SubLayerHrdParameters from a BitReader
    pub fn parse<R: Read>(reader: &mut BitReader<R, BigEndian>, cpb_cnt: usize, sub_pic_hrd_params_present_flag: bool) -> Result<Self> {
        let mut params = Self::default();
        params.bit_rate_value.reserve(cpb_cnt);
        params.cpb_size_value.reserve(cpb_cnt);
        params.cpb_size_du_value.reserve(cpb_cnt);
        params.bit_rate_du_value.reserve(cpb_cnt);
        params.cbr_flag.reserve(cpb_cnt);

        for _ in 0..cpb_cnt {
            params.bit_rate_value.push(reader.read_ue()? + 1);
            params.cpb_size_value.push(reader.read_ue()? + 1);
            if sub_pic_hrd_params_present_flag {
                params.cpb_size_du_value.push(reader.read_ue()? + 1);
                params.bit_rate_du_value.push(reader.read_ue()? + 1);
            }
            params.cbr_flag.push(reader.read_bit()?);
        }

        Ok(params)
    }
}

/// HRD (Hypothetical Reference Decoder) Parameters
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct HrdParameters {
    /// NAL HRD parameters present flag
    pub nal_hrd_parameters_present_flag: bool,
    /// VCL HRD parameters present flag
    pub vcl_hrd_parameters_present_flag: bool,
    /// Sub-picture HRD parameters present flag
    pub sub_pic_hrd_params_present_flag: bool,
    /// Tick divisor
    pub tick_divisor: u8,
    /// DU CPB removal delay increment length
    pub du_cpb_removal_delay_increment_length: u8,
    /// Sub-picture CPB params in pic timing SEI flag
    pub sub_pic_cpb_params_in_pic_timing_sei_flag: bool,
    /// DPB output delay DU length
    pub dpb_output_delay_du_length: u8,
    /// Bit rate scale
    pub bit_rate_scale: u8,
    /// CPB size scale
    pub cpb_size_scale: u8,
    /// CPB size DU scale
    pub cpb_size_du_scale: u8,
    /// Initial CPB removal delay length
    pub initial_cpb_removal_delay_length: u8,
    /// AU CPB removal delay length
    pub au_cpb_removal_delay_length: u8,
    /// DPB output delay length
    pub dpb_output_delay_length: u8,
    /// Fixed picture rate general flags per sub-layer
    pub fixed_pic_rate_general_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Fixed picture rate within CVS flags per sub-layer
    pub fixed_pic_rate_within_cvs_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// Elemental duration in TC per sub-layer
    pub elemental_duration_in_tc: SmallVec<[u32; MAX_SUB_LAYERS]>,
    /// Low delay HRD flags per sub-layer
    pub low_delay_hrd_flag: SmallVec<[bool; MAX_SUB_LAYERS]>,
    /// CPB count per sub-layer
    pub cpb_cnt: SmallVec<[u32; MAX_SUB_LAYERS]>,
    /// NAL sub-layer HRD parameters
    pub nal_sub_layer_hrd_parameters: SmallVec<[SubLayerHrdParameters; MAX_SUB_LAYERS]>,
    /// VCL sub-layer HRD parameters
    pub vcl_sub_layer_hrd_parameters: SmallVec<[SubLayerHrdParameters; MAX_SUB_LAYERS]>,
}

impl HrdParameters {
    /// Parse HrdParameters from a BitReader
    ///
    /// # Arguments
    /// * `reader` - BitReader to read from
    /// * `common_inf_present_flag` - Whether common info is present
    /// * `max_num_sub_layers` - Maximum number of sub-layers (actual value,
    ///   1-7)
    pub fn parse<R: Read>(reader: &mut BitReader<R, BigEndian>, common_inf_present_flag: bool, max_num_sub_layers: u8) -> Result<Self> {
        let mut hrd = Self::default();

        if common_inf_present_flag {
            hrd.nal_hrd_parameters_present_flag = reader.read_bit()?;
            hrd.vcl_hrd_parameters_present_flag = reader.read_bit()?;

            if hrd.nal_hrd_parameters_present_flag || hrd.vcl_hrd_parameters_present_flag {
                hrd.sub_pic_hrd_params_present_flag = reader.read_bit()?;

                if hrd.sub_pic_hrd_params_present_flag {
                    hrd.tick_divisor = reader.read::<8, u8>()? + 2;
                    hrd.du_cpb_removal_delay_increment_length = reader.read::<5, u8>()? + 1;
                    hrd.sub_pic_cpb_params_in_pic_timing_sei_flag = reader.read_bit()?;
                    hrd.dpb_output_delay_du_length = reader.read::<5, u8>()? + 1;
                }

                hrd.bit_rate_scale = reader.read::<4, u8>()?;
                hrd.cpb_size_scale = reader.read::<4, u8>()?;

                if hrd.sub_pic_hrd_params_present_flag {
                    hrd.cpb_size_du_scale = reader.read::<4, u8>()?;
                }

                hrd.initial_cpb_removal_delay_length = reader.read::<5, u8>()? + 1;
                hrd.au_cpb_removal_delay_length = reader.read::<5, u8>()? + 1;
                hrd.dpb_output_delay_length = reader.read::<5, u8>()? + 1;
            }
        }

        let num_sub_layers = max_num_sub_layers as usize;
        hrd.fixed_pic_rate_general_flag = smallvec::smallvec![false; num_sub_layers];
        hrd.fixed_pic_rate_within_cvs_flag = smallvec::smallvec![false; num_sub_layers];
        hrd.elemental_duration_in_tc = smallvec::smallvec![0; num_sub_layers];
        hrd.low_delay_hrd_flag = smallvec::smallvec![false; num_sub_layers];
        hrd.cpb_cnt = smallvec::smallvec![0; num_sub_layers];
        hrd.nal_sub_layer_hrd_parameters.reserve(num_sub_layers);
        hrd.vcl_sub_layer_hrd_parameters.reserve(num_sub_layers);

        for i in 0..num_sub_layers {
            hrd.fixed_pic_rate_general_flag[i] = reader.read_bit()?;

            if !hrd.fixed_pic_rate_general_flag[i] {
                hrd.fixed_pic_rate_within_cvs_flag[i] = reader.read_bit()?;
            } else {
                hrd.fixed_pic_rate_within_cvs_flag[i] = true;
            }

            if hrd.fixed_pic_rate_within_cvs_flag[i] {
                hrd.elemental_duration_in_tc[i] = reader.read_ue()? + 1;
            } else {
                hrd.low_delay_hrd_flag[i] = reader.read_bit()?;
            }

            if !hrd.low_delay_hrd_flag[i] {
                hrd.cpb_cnt[i] = reader.read_ue()? + 1;
            }

            let cpb_cnt = hrd.cpb_cnt[i] as usize;

            if hrd.nal_hrd_parameters_present_flag {
                hrd.nal_sub_layer_hrd_parameters.push(SubLayerHrdParameters::parse(reader, cpb_cnt, hrd.sub_pic_hrd_params_present_flag)?);
            }

            if hrd.vcl_hrd_parameters_present_flag {
                hrd.vcl_sub_layer_hrd_parameters.push(SubLayerHrdParameters::parse(reader, cpb_cnt, hrd.sub_pic_hrd_params_present_flag)?);
            }
        }

        Ok(hrd)
    }

    /// Get initial CPB removal delay length in bits
    #[inline]
    pub fn initial_cpb_removal_delay_length(&self) -> u8 {
        self.initial_cpb_removal_delay_length
    }

    /// Get AU CPB removal delay length in bits
    #[inline]
    pub fn au_cpb_removal_delay_length(&self) -> u8 {
        self.au_cpb_removal_delay_length
    }

    /// Get DPB output delay length in bits
    #[inline]
    pub fn dpb_output_delay_length(&self) -> u8 {
        self.dpb_output_delay_length
    }
}

/// Video Parameter Set (VPS)
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Vps {
    /// VPS ID (0-15)
    pub video_parameter_set_id: u8,
    /// VPS base layer internal flag
    pub vps_base_layer_internal_flag: bool,
    /// VPS base layer available flag
    pub vps_base_layer_available_flag: bool,
    /// Maximum number of layers (0-62)
    pub vps_max_layers: u8,
    /// Maximum number of sub-layers (0-6)
    pub vps_max_sub_layers: u8,
    /// Temporal ID nesting flag
    pub vps_temporal_id_nesting_flag: bool,
    /// Profile tier level
    pub profile_tier_level: ProfileTierLevel,
    /// VPS sub-layer ordering info present flag
    pub vps_sub_layer_ordering_info_present_flag: bool,
    /// Maximum decoder buffer size per sub-layer
    pub vps_max_dec_pic_buffering: SmallVec<[u32; MAX_SUB_LAYERS]>,
    /// Maximum number of reorder pictures per sub-layer
    pub vps_max_num_reorder_pics: SmallVec<[u32; MAX_SUB_LAYERS]>,
    /// Maximum latency increase plus 1 per sub-layer
    pub vps_max_latency_increase_plus1: SmallVec<[u32; MAX_SUB_LAYERS]>,
    /// Maximum layer ID
    pub vps_max_layer_id: u8,
    /// Number of layer sets
    pub vps_num_layer_sets: u32,
    /// Layer ID included flags - kept as Vec<Vec> since outer size is variable
    pub layer_id_included_flag: Vec<Vec<bool>>,
    /// VPS timing info present flag
    pub vps_timing_info_present_flag: bool,
    /// VPS number of units in tick
    pub vps_num_units_in_tick: u32,
    /// VPS time scale
    pub vps_time_scale: u32,
    /// VPS POC proportional to timing flag
    pub vps_poc_proportional_to_timing_flag: bool,
    /// VPS number of ticks POC diff one
    pub vps_num_ticks_poc_diff_one: u32,
    /// VPS number of HRD parameters
    pub vps_num_hrd_parameters: u32,
    /// HRD layer set indices - kept as Vec since count is variable
    pub hrd_layer_set_idx: Vec<u32>,
    /// CPRMS present flags - kept as Vec since count is variable
    pub cprms_present_flag: Vec<bool>,
    /// HRD parameters - kept as Vec since count is variable
    pub hrd_parameters: Vec<HrdParameters>,
    /// VPS extension flag
    pub vps_extension_flag: bool,
}

impl Vps {
    /// Parse VPS from raw NAL unit RBSP data (with EPB already removed)
    pub fn parse(data: &[u8]) -> Result<Self> {
        let mut reader = BitReader::new(data);
        Self::parse_from_bit_reader(&mut reader)
    }

    /// Parse VPS from a BitReader
    pub fn parse_from_bit_reader<R: Read>(reader: &mut BitReader<R, BigEndian>) -> Result<Self> {
        // Read vps_video_parameter_set_id
        let vps_video_parameter_set_id = reader.read::<4, u8>()?;
        if vps_video_parameter_set_id as usize >= MAX_VPS_COUNT {
            return Err(invalid_data_error!("vps_video_parameter_set_id", vps_video_parameter_set_id));
        }

        // Read vps_base_layer_internal_flag
        let vps_base_layer_internal_flag = reader.read_bit()?;

        // Read vps_base_layer_available_flag
        let vps_base_layer_available_flag = reader.read_bit()?;

        // Read vps_max_layers
        let vps_max_layers = reader.read::<6, u8>()? + 1;
        if vps_max_layers as usize > MAX_VPS_LAYERS {
            return Err(invalid_data_error!("vps_max_layers", vps_max_layers));
        }

        // Read vps_max_sub_layers
        let vps_max_sub_layers = reader.read::<3, u8>()? + 1;
        if vps_max_sub_layers as usize > MAX_SUB_LAYERS {
            return Err(invalid_data_error!("vps_max_sub_layers", vps_max_sub_layers));
        }

        // Read vps_temporal_id_nesting_flag
        let vps_temporal_id_nesting_flag = reader.read_bit()?;

        // Read reserved (must be 0xFFFF)
        let reserved = reader.read::<16, u16>()?;
        if reserved != 0xFFFF {
            return Err(invalid_data_error!("reserved", reserved));
        }

        // Parse profile_tier_level
        let profile_tier_level = ProfileTierLevel::parse(reader, true, vps_max_sub_layers)?;

        // Read vps_sub_layer_ordering_info_present_flag
        let vps_sub_layer_ordering_info_present_flag = reader.read_bit()?;

        // Parse sub-layer ordering info
        let num_sub_layers = vps_max_sub_layers as usize;
        let start_idx = if vps_sub_layer_ordering_info_present_flag {
            0
        } else {
            num_sub_layers - 1
        };

        let mut vps_max_dec_pic_buffering = smallvec::smallvec![0u32; num_sub_layers];
        let mut vps_max_num_reorder_pics = smallvec::smallvec![0u32; num_sub_layers];
        let mut vps_max_latency_increase_plus1 = smallvec::smallvec![0u32; num_sub_layers];

        for i in start_idx..num_sub_layers {
            vps_max_dec_pic_buffering[i] = reader.read_ue()? + 1;
            vps_max_num_reorder_pics[i] = reader.read_ue()?;
            vps_max_latency_increase_plus1[i] = reader.read_ue()?;
        }

        // Fill in lower sub-layers if not present
        if !vps_sub_layer_ordering_info_present_flag {
            for i in 0..start_idx {
                vps_max_dec_pic_buffering[i] = vps_max_dec_pic_buffering[start_idx];
                vps_max_num_reorder_pics[i] = vps_max_num_reorder_pics[start_idx];
                vps_max_latency_increase_plus1[i] = vps_max_latency_increase_plus1[start_idx];
            }
        }

        // Read vps_max_layer_id
        let vps_max_layer_id = reader.read::<6, u8>()?;

        // Read vps_num_layer_sets
        let vps_num_layer_sets = reader.read_ue()? + 1;

        // Parse layer_id_included_flag for each layer set
        let mut layer_id_included_flag = Vec::with_capacity(vps_num_layer_sets as usize);
        // Layer set 0 is implicit
        layer_id_included_flag.push(vec![true]); // layer 0 in set 0

        for _ in 1..vps_num_layer_sets {
            let mut layer_flags = Vec::with_capacity((vps_max_layer_id + 1) as usize);
            for _ in 0..=vps_max_layer_id {
                layer_flags.push(reader.read_bit()?);
            }
            layer_id_included_flag.push(layer_flags);
        }

        // Read vps_timing_info_present_flag
        let vps_timing_info_present_flag = reader.read_bit()?;

        let mut vps_num_units_in_tick = 0;
        let mut vps_time_scale = 0;
        let mut vps_poc_proportional_to_timing_flag = false;
        let mut vps_num_ticks_poc_diff_one = 0;
        let mut vps_num_hrd_parameters = 0;
        let mut hrd_layer_set_idx = Vec::new();
        let mut cprms_present_flag = Vec::new();
        let mut hrd_parameters = Vec::new();

        // Parse timing info and HRD parameters (if present)
        if vps_timing_info_present_flag {
            // Read vps_num_units_in_tick
            vps_num_units_in_tick = reader.read::<32, u32>()?;
            // Read vps_time_scale
            vps_time_scale = reader.read::<32, u32>()?;
            // Read vps_poc_proportional_to_timing_flag
            vps_poc_proportional_to_timing_flag = reader.read_bit()?;

            if vps_poc_proportional_to_timing_flag {
                // Read vps_num_ticks_poc_diff_one
                vps_num_ticks_poc_diff_one = reader.read_ue()? + 1;
            }

            // Read vps_num_hrd_parameters
            vps_num_hrd_parameters = reader.read_ue()?;

            // Parse HRD parameters for each HRD
            for i in 0..vps_num_hrd_parameters as usize {
                hrd_layer_set_idx.push(reader.read_ue()?);

                let cprms_flag = if i > 0 {
                    reader.read_bit()?
                } else {
                    true
                };
                cprms_present_flag.push(cprms_flag);

                hrd_parameters.push(HrdParameters::parse(reader, cprms_flag, vps_max_sub_layers)?);
            }
        }

        // Read vps_extension_flag
        let vps_extension_flag = reader.read_bit()?;

        Ok(Self {
            video_parameter_set_id: vps_video_parameter_set_id,
            vps_base_layer_internal_flag,
            vps_base_layer_available_flag,
            vps_max_layers,
            vps_max_sub_layers,
            vps_temporal_id_nesting_flag,
            profile_tier_level,
            vps_sub_layer_ordering_info_present_flag,
            vps_max_dec_pic_buffering,
            vps_max_num_reorder_pics,
            vps_max_latency_increase_plus1,
            vps_max_layer_id,
            vps_num_layer_sets,
            layer_id_included_flag,
            vps_timing_info_present_flag,
            vps_num_units_in_tick,
            vps_time_scale,
            vps_poc_proportional_to_timing_flag,
            vps_num_ticks_poc_diff_one,
            vps_num_hrd_parameters,
            hrd_layer_set_idx,
            cprms_present_flag,
            hrd_parameters,
            vps_extension_flag,
        })
    }

    /// Get maximum number of layers
    #[inline]
    pub fn max_layers(&self) -> u8 {
        self.vps_max_layers
    }

    /// Get maximum number of sub-layers
    #[inline]
    pub fn max_sub_layers(&self) -> u8 {
        self.vps_max_sub_layers
    }

    /// Get maximum decoded picture buffering for a sub-layer
    #[inline]
    pub fn max_dec_pic_buffering(&self, sub_layer: usize) -> Option<u32> {
        self.vps_max_dec_pic_buffering.get(sub_layer).copied()
    }

    /// Get maximum number of reorder pictures for a sub-layer
    #[inline]
    pub fn max_num_reorder_pics(&self, sub_layer: usize) -> Option<u32> {
        self.vps_max_num_reorder_pics.get(sub_layer).copied()
    }

    /// Get frame rate as (numerator, denominator) if timing info is present
    pub fn frame_rate(&self) -> Option<(u32, u32)> {
        if self.vps_timing_info_present_flag && self.vps_num_units_in_tick > 0 {
            Some((self.vps_time_scale, self.vps_num_units_in_tick))
        } else {
            None
        }
    }

    /// Get frame rate as floating point
    pub fn frame_rate_fps(&self) -> Option<f64> {
        self.frame_rate().map(|(num, den)| num as f64 / den as f64)
    }

    /// Get the number of layer sets
    #[inline]
    pub fn num_layer_sets(&self) -> u32 {
        self.vps_num_layer_sets
    }
}