scuffle_h265/sps/
sub_layer_ordering_info.rs

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