scuffle_h265/sps/
st_ref_pic_set.rs

1use std::fmt::Debug;
2use std::io;
3
4use scuffle_bytes_util::BitReader;
5use scuffle_expgolomb::BitReaderExpGolombExt;
6
7use crate::range_check::range_check;
8
9/// Short-term reference picture set syntax.
10///
11/// `st_ref_pic_set(stRpsIdx)`
12///
13/// - ISO/IEC 23008-2 - 7.3.7
14/// - ISO/IEC 23008-2 - 7.4.8
15#[derive(Debug, Clone, PartialEq)]
16pub struct ShortTermRefPicSets {
17    /// `NumDeltaPocs[stRpsIdx]`
18    pub num_delta_pocs: Vec<u64>,
19    /// `NumPositivePics[stRpsIdx]`
20    pub num_positive_pics: Vec<u64>,
21    /// `NumNegativePics[stRpsIdx]`
22    pub num_negative_pics: Vec<u64>,
23    /// `DeltaPocS1[stRpsIdx][j]`
24    pub delta_poc_s1: Vec<Vec<i64>>,
25    /// `DeltaPocS0[stRpsIdx][j]`
26    pub delta_poc_s0: Vec<Vec<i64>>,
27    /// `UsedByCurrPicS0[stRpsIdx][j]`
28    pub used_by_curr_pic_s0: Vec<Vec<bool>>,
29    /// `UsedByCurrPicS1[stRpsIdx][j]`
30    pub used_by_curr_pic_s1: Vec<Vec<bool>>,
31}
32
33impl ShortTermRefPicSets {
34    pub(crate) fn parse<R: io::Read>(
35        bit_reader: &mut BitReader<R>,
36        num_short_term_ref_pic_sets: usize,
37        nuh_layer_id: u8,
38        sps_max_dec_pic_buffering_minus1_at_sps_max_sub_layers_minus1: u64,
39    ) -> io::Result<Self> {
40        let mut num_delta_pocs = Vec::with_capacity(num_short_term_ref_pic_sets);
41
42        // num_short_term_ref_pic_sets is bound above by 64
43        let mut num_positive_pics = vec![0u64; num_short_term_ref_pic_sets];
44        let mut num_negative_pics = vec![0u64; num_short_term_ref_pic_sets];
45        let mut delta_poc_s1 = Vec::with_capacity(num_short_term_ref_pic_sets);
46        let mut delta_poc_s0 = Vec::with_capacity(num_short_term_ref_pic_sets);
47        let mut used_by_curr_pic_s0 = Vec::with_capacity(num_short_term_ref_pic_sets);
48        let mut used_by_curr_pic_s1 = Vec::with_capacity(num_short_term_ref_pic_sets);
49
50        for st_rps_idx in 0..num_short_term_ref_pic_sets {
51            let mut inter_ref_pic_set_prediction_flag = false;
52            if st_rps_idx != 0 {
53                inter_ref_pic_set_prediction_flag = bit_reader.read_bit()?;
54            }
55
56            if inter_ref_pic_set_prediction_flag {
57                let mut delta_idx_minus1 = 0;
58                if st_rps_idx == num_short_term_ref_pic_sets {
59                    delta_idx_minus1 = bit_reader.read_exp_golomb()? as usize;
60                    range_check!(delta_idx_minus1, 0, st_rps_idx - 1)?;
61                }
62
63                // (7-59)
64                let ref_rps_idx = st_rps_idx - (delta_idx_minus1 + 1);
65
66                let delta_rps_sign = bit_reader.read_bit()?;
67                let abs_delta_rps_minus1 = bit_reader.read_exp_golomb()?;
68                range_check!(abs_delta_rps_minus1, 0, 2u64.pow(15) - 1)?;
69                // (7-60)
70                let delta_rps = (1 - 2 * delta_rps_sign as i64) * (abs_delta_rps_minus1 + 1) as i64;
71
72                // num_delta_pocs is bound above by 32 ((7-71) see below)
73                let len = num_delta_pocs[ref_rps_idx] as usize + 1;
74                let mut used_by_curr_pic_flag = vec![false; len];
75                let mut use_delta_flag = vec![true; len];
76                for j in 0..len {
77                    used_by_curr_pic_flag[j] = bit_reader.read_bit()?;
78                    if !used_by_curr_pic_flag[j] {
79                        use_delta_flag[j] = bit_reader.read_bit()?;
80                    }
81                }
82
83                delta_poc_s0.push(vec![0; len]);
84                delta_poc_s1.push(vec![0; len]);
85                used_by_curr_pic_s0.push(vec![false; len]);
86                used_by_curr_pic_s1.push(vec![false; len]);
87
88                // Calculate derived values as defined as (7-61) and (7-62) by the spec
89                let mut i = 0;
90                if let Some(start) = num_positive_pics[ref_rps_idx].checked_sub(1).map(|s| s as usize) {
91                    for j in (0..=start).rev() {
92                        let d_poc = delta_poc_s1[ref_rps_idx][j] + delta_rps;
93                        if d_poc < 0 && use_delta_flag[num_negative_pics[ref_rps_idx] as usize + j] {
94                            delta_poc_s0[st_rps_idx][i] = d_poc;
95                            used_by_curr_pic_s0[st_rps_idx][i] =
96                                used_by_curr_pic_flag[num_negative_pics[ref_rps_idx] as usize + j];
97                            i += 1;
98                        }
99                    }
100                }
101
102                if delta_rps < 0 && use_delta_flag[num_delta_pocs[ref_rps_idx] as usize] {
103                    delta_poc_s0[st_rps_idx][i] = delta_rps;
104                    used_by_curr_pic_s0[st_rps_idx][i] = used_by_curr_pic_flag[num_delta_pocs[ref_rps_idx] as usize];
105                    i += 1;
106                }
107
108                for j in 0..num_negative_pics[ref_rps_idx] as usize {
109                    let d_poc = delta_poc_s0[ref_rps_idx][j] + delta_rps;
110                    if d_poc < 0 && use_delta_flag[j] {
111                        delta_poc_s0[st_rps_idx][i] = d_poc;
112                        used_by_curr_pic_s0[st_rps_idx][i] = used_by_curr_pic_flag[j];
113                        i += 1;
114                    }
115                }
116
117                num_negative_pics[st_rps_idx] = i as u64;
118                // This is a sanity check just for safety, it should be unreachable
119                // num_negative_pics is said to be bound by
120                // sps_max_dec_pic_buffering_minus1[sps_max_sub_layers_minus1]
121                // which itself is bound by 16
122                range_check!(num_negative_pics[st_rps_idx], 0, 16)?;
123
124                i = 0;
125                if let Some(start) = num_negative_pics[ref_rps_idx].checked_sub(1).map(|s| s as usize) {
126                    for j in (0..=start).rev() {
127                        let d_poc = delta_poc_s0[ref_rps_idx][j] + delta_rps;
128                        if d_poc > 0 && use_delta_flag[j] {
129                            delta_poc_s1[st_rps_idx][i] = d_poc;
130                            used_by_curr_pic_s1[st_rps_idx][i] = used_by_curr_pic_flag[j];
131                            i += 1;
132                        }
133                    }
134                }
135
136                if delta_rps > 0 && use_delta_flag[num_delta_pocs[ref_rps_idx] as usize] {
137                    delta_poc_s1[st_rps_idx][i] = delta_rps;
138                    used_by_curr_pic_s1[st_rps_idx][i] = used_by_curr_pic_flag[num_delta_pocs[ref_rps_idx] as usize];
139                    i += 1;
140                }
141
142                for j in 0..num_positive_pics[ref_rps_idx] as usize {
143                    let d_poc = delta_poc_s1[ref_rps_idx][j] + delta_rps;
144                    if d_poc > 0 && use_delta_flag[num_negative_pics[ref_rps_idx] as usize + j] {
145                        delta_poc_s1[st_rps_idx][i] = d_poc;
146                        used_by_curr_pic_s1[st_rps_idx][i] =
147                            used_by_curr_pic_flag[num_negative_pics[ref_rps_idx] as usize + j];
148                        i += 1;
149                    }
150                }
151
152                num_positive_pics[st_rps_idx] = i as u64;
153                // This is a sanity check just for safety, it should be unreachable
154                // num_positive_pics is said to be bound by
155                // sps_max_dec_pic_buffering_minus1[sps_max_sub_layers_minus1] - num_negative_pics
156                // which itself is bound by 16
157                range_check!(num_negative_pics[st_rps_idx], 0, 16)?;
158            } else {
159                num_negative_pics[st_rps_idx] = bit_reader.read_exp_golomb()?;
160                num_positive_pics[st_rps_idx] = bit_reader.read_exp_golomb()?;
161
162                let upper_bound = if nuh_layer_id == 0 {
163                    // bound above by 16
164                    sps_max_dec_pic_buffering_minus1_at_sps_max_sub_layers_minus1
165                } else {
166                    16
167                };
168                range_check!(num_negative_pics[st_rps_idx], 0, upper_bound)?;
169
170                let upper_bound = if nuh_layer_id == 0 {
171                    // bound above by 16
172                    sps_max_dec_pic_buffering_minus1_at_sps_max_sub_layers_minus1
173                        .saturating_sub(num_negative_pics[st_rps_idx])
174                } else {
175                    16
176                };
177                range_check!(num_positive_pics[st_rps_idx], 0, upper_bound)?;
178
179                delta_poc_s0.push(vec![0; num_negative_pics[st_rps_idx] as usize]);
180                used_by_curr_pic_s0.push(vec![false; num_negative_pics[st_rps_idx] as usize]);
181
182                for i in 0..num_negative_pics[st_rps_idx] as usize {
183                    let delta_poc_s0_minus1 = bit_reader.read_exp_golomb()?;
184                    range_check!(delta_poc_s0_minus1, 0, 2u64.pow(15) - 1)?;
185                    if i == 0 {
186                        // (7-67)
187                        delta_poc_s0[st_rps_idx][i] = -(delta_poc_s0_minus1 as i64 + 1);
188                    } else {
189                        // (7-69)
190                        delta_poc_s0[st_rps_idx][i] = delta_poc_s0[st_rps_idx][i - 1] - (delta_poc_s0_minus1 as i64 + 1);
191                    }
192
193                    let used_by_curr_pic_s0_flag = bit_reader.read_bit()?;
194                    used_by_curr_pic_s0[st_rps_idx][i] = used_by_curr_pic_s0_flag;
195                }
196
197                delta_poc_s1.push(vec![0; num_positive_pics[st_rps_idx] as usize]);
198                used_by_curr_pic_s1.push(vec![false; num_positive_pics[st_rps_idx] as usize]);
199
200                for i in 0..num_positive_pics[st_rps_idx] as usize {
201                    let delta_poc_s1_minus1 = bit_reader.read_exp_golomb()?;
202                    range_check!(delta_poc_s1_minus1, 0, 2u64.pow(15) - 1)?;
203                    if i == 0 {
204                        // (7-68)
205                        delta_poc_s1[st_rps_idx][i] = delta_poc_s1_minus1 as i64 + 1;
206                    } else {
207                        // (7-70)
208                        delta_poc_s1[st_rps_idx][i] = delta_poc_s1[st_rps_idx][i - 1] + delta_poc_s1_minus1 as i64 + 1;
209                    }
210
211                    let used_by_curr_pic_s1_flag = bit_reader.read_bit()?;
212                    used_by_curr_pic_s1[st_rps_idx][i] = used_by_curr_pic_s1_flag;
213                }
214            }
215
216            // (7-71)
217            num_delta_pocs.push(num_negative_pics[st_rps_idx] + num_positive_pics[st_rps_idx]);
218            // both num_negative_pics and num_positive_pics are bound above by 16
219            // => num_delta_pocs[st_rps_idx] <= 32
220        }
221
222        Ok(Self {
223            num_delta_pocs,
224            num_positive_pics,
225            num_negative_pics,
226            delta_poc_s1,
227            delta_poc_s0,
228            used_by_curr_pic_s0,
229            used_by_curr_pic_s1,
230        })
231    }
232}