scuffle_h265/sps/
st_ref_pic_set.rs

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