scuffle_h265/sps/sub_layer_ordering_info.rs
1use std::io;
2
3use scuffle_bytes_util::{BitReader, range_check};
4use scuffle_expgolomb::BitReaderExpGolombExt;
5
6/// Info for each sub-layer in the SPS.
7///
8/// Directly part of [SPS RBSP](crate::SpsRbsp).
9#[derive(Debug, Clone, PartialEq)]
10pub struct SubLayerOrderingInfo {
11 /// `sps_max_dec_pic_buffering_minus1[i]` plus 1 specifies the maximum required size of the decoded
12 /// picture buffer for the CVS in units of picture storage buffers when `HighestTid` is equal to `i`.
13 pub sps_max_dec_pic_buffering_minus1: Vec<u64>,
14 /// `sps_max_num_reorder_pics[i]` indicates the maximum allowed number of pictures with `PicOutputFlag`
15 /// equal to 1 that can precede any picture with `PicOutputFlag` equal to 1 in the CVS in decoding order and
16 /// follow that picture with `PicOutputFlag` equal to 1 in output order when `HighestTid` is equal to i.
17 pub sps_max_num_reorder_pics: Vec<u64>,
18 /// `sps_max_latency_increase_plus1[i]` not equal to 0 is used to compute the value of
19 /// [`SpsMaxLatencyPictures[i]`](SubLayerOrderingInfo::sps_max_latency_pictures_at),
20 /// which specifies the maximum number of pictures with `PicOutputFlag` equal
21 /// to 1 that can precede any picture with `PicOutputFlag` equal to 1 in the CVS in output order and follow that
22 /// picture with `PicOutputFlag` equal to 1 in decoding order when `HighestTid` is equal to i.
23 pub sps_max_latency_increase_plus1: Vec<u32>,
24}
25
26impl SubLayerOrderingInfo {
27 pub(crate) fn parse<R: io::Read>(
28 bit_reader: &mut BitReader<R>,
29 sps_sub_layer_ordering_info_present_flag: bool,
30 sps_max_sub_layers_minus1: u8,
31 ) -> io::Result<Self> {
32 let mut sps_max_dec_pic_buffering_minus1 = vec![0; sps_max_sub_layers_minus1 as usize + 1];
33 let mut sps_max_num_reorder_pics = vec![0; sps_max_sub_layers_minus1 as usize + 1];
34 let mut sps_max_latency_increase_plus1 = vec![0; sps_max_sub_layers_minus1 as usize + 1];
35
36 if sps_sub_layer_ordering_info_present_flag {
37 for i in 0..=sps_max_sub_layers_minus1 as usize {
38 sps_max_dec_pic_buffering_minus1[i] = bit_reader.read_exp_golomb()?;
39 // (A-2) defines MaxDpbSize which is always at most 16
40 range_check!(sps_max_dec_pic_buffering_minus1[i], 0, 16)?;
41 if i > 0 && sps_max_dec_pic_buffering_minus1[i] < sps_max_dec_pic_buffering_minus1[i - 1] {
42 return Err(io::Error::new(
43 io::ErrorKind::InvalidData,
44 "sps_max_dec_pic_buffering_minus1[i] must be greater than or equal to sps_max_dec_pic_buffering_minus1[i-1]",
45 ));
46 }
47
48 sps_max_num_reorder_pics[i] = bit_reader.read_exp_golomb()?;
49 range_check!(sps_max_num_reorder_pics[i], 0, sps_max_dec_pic_buffering_minus1[i])?;
50 if i > 0 && sps_max_num_reorder_pics[i] < sps_max_num_reorder_pics[i - 1] {
51 return Err(io::Error::new(
52 io::ErrorKind::InvalidData,
53 "sps_max_num_reorder_pics[i] must be greater than or equal to sps_max_num_reorder_pics[i-1]",
54 ));
55 }
56
57 let sps_max_latency_increase_plus1_i = bit_reader.read_exp_golomb()?;
58 range_check!(sps_max_latency_increase_plus1_i, 0, 2u64.pow(32) - 2)?;
59 sps_max_latency_increase_plus1[i] = sps_max_latency_increase_plus1_i as u32;
60 }
61 } else {
62 // From the spec, page 108 and 109:
63 // When sps_max_dec_pic_buffering_minus1[i] is not present (...) due to
64 // sps_sub_layer_ordering_info_present_flag being equal to 0, it is inferred to be equal to
65 // sps_max_dec_pic_buffering_minus1[sps_max_sub_layers_minus1].
66
67 let sps_max_dec_pic_buffering_minus1_i = bit_reader.read_exp_golomb()?;
68 // (A-2) defines MaxDpbSize which is always at most 16
69 range_check!(sps_max_dec_pic_buffering_minus1_i, 0, 16)?;
70 sps_max_dec_pic_buffering_minus1.fill(sps_max_dec_pic_buffering_minus1_i);
71
72 let sps_max_num_reorder_pics_i = bit_reader.read_exp_golomb()?;
73 range_check!(sps_max_num_reorder_pics_i, 0, sps_max_dec_pic_buffering_minus1_i)?;
74 sps_max_num_reorder_pics.fill(sps_max_num_reorder_pics_i);
75
76 let sps_max_latency_increase_plus1_i = bit_reader.read_exp_golomb()?;
77 range_check!(sps_max_latency_increase_plus1_i, 0, 2u64.pow(32) - 2)?;
78 sps_max_latency_increase_plus1.fill(sps_max_latency_increase_plus1_i as u32);
79 }
80
81 Ok(SubLayerOrderingInfo {
82 sps_max_dec_pic_buffering_minus1,
83 sps_max_num_reorder_pics,
84 sps_max_latency_increase_plus1,
85 })
86 }
87
88 /// Specifies the maximum number of pictures with `PicOutputFlag` equal
89 /// to 1 that can precede any picture with `PicOutputFlag` equal to 1 in the CVS in output order and follow that
90 /// picture with `PicOutputFlag` equal to 1 in decoding order when `HighestTid` is equal to i.
91 ///
92 /// Calculates the full `SpsMaxLatencyPictures` array.
93 ///
94 /// Use [`SubLayerOrderingInfo::sps_max_latency_pictures_at`] to only calculate one specific value `SpsMaxLatencyPictures[i]`.
95 ///
96 /// `SpsMaxLatencyPictures[i] = sps_max_num_reorder_pics[i] + sps_max_latency_increase_plus1[i] − 1` (7-9)
97 ///
98 /// ISO/IEC 23008-2 - 7.4.3.2
99 pub fn sps_max_latency_pictures(&self) -> Vec<Option<u64>> {
100 self.sps_max_num_reorder_pics
101 .iter()
102 .zip(self.sps_max_latency_increase_plus1.iter())
103 .map(|(reorder, latency)| Some(reorder + latency.checked_sub(1)? as u64))
104 .collect()
105 }
106
107 /// Calculates `SpsMaxLatencyPictures[i]`.
108 ///
109 /// See [`sps_max_latency_pictures`](SubLayerOrderingInfo::sps_max_latency_pictures) for details.
110 ///
111 /// `SpsMaxLatencyPictures[i] = sps_max_num_reorder_pics[i] + sps_max_latency_increase_plus1[i] − 1` (7-9)
112 ///
113 /// ISO/IEC 23008-2 - 7.4.3.2
114 pub fn sps_max_latency_pictures_at(&self, i: usize) -> Option<u64> {
115 Some(self.sps_max_num_reorder_pics.get(i)? + self.sps_max_latency_increase_plus1.get(i)?.checked_sub(1)? as u64)
116 }
117}