cros_codecs/codec/h265/
dpb.rs

1// Copyright 2023 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cell::Ref;
6use std::cell::RefCell;
7use std::cell::RefMut;
8use std::rc::Rc;
9
10use anyhow::anyhow;
11
12use crate::codec::h265::parser::Sps;
13use crate::codec::h265::picture::PictureData;
14use crate::codec::h265::picture::Reference;
15
16// Shortcut to refer to a DPB entry.
17//
18// The first member of the tuple is the `PictureData` for the frame.
19//
20// The second member is the backend handle of the frame.
21#[derive(Clone, Debug)]
22pub struct DpbEntry<T>(pub Rc<RefCell<PictureData>>, pub T);
23
24pub struct Dpb<T> {
25    /// List of `PictureData` and backend handles to decoded pictures.
26    entries: Vec<DpbEntry<T>>,
27    /// The maximum number of pictures that can be stored.
28    max_num_pics: usize,
29}
30
31impl<T: Clone> Dpb<T> {
32    /// Returns an iterator over the underlying H265 pictures stored in the
33    /// DPB.
34    pub fn pictures(&self) -> impl Iterator<Item = Ref<'_, PictureData>> {
35        self.entries.iter().map(|h| h.0.borrow())
36    }
37
38    /// Returns a mutable iterator over the underlying H265 pictures stored in
39    /// the DPB.
40    pub fn pictures_mut(&mut self) -> impl Iterator<Item = RefMut<'_, PictureData>> {
41        self.entries.iter().map(|h| h.0.borrow_mut())
42    }
43
44    /// Returns the length of the DPB.
45    pub fn len(&self) -> usize {
46        self.entries.len()
47    }
48
49    pub fn is_empty(&self) -> bool {
50        self.len() == 0
51    }
52
53    /// Get a reference to the whole DPB entries.
54    pub fn entries(&self) -> &Vec<DpbEntry<T>> {
55        &self.entries
56    }
57
58    /// Set the dpb's max num pics.
59    pub fn set_max_num_pics(&mut self, max_num_pics: usize) {
60        self.max_num_pics = max_num_pics;
61    }
62
63    /// Get a reference to the dpb's max num pics.
64    pub fn max_num_pics(&self) -> usize {
65        self.max_num_pics
66    }
67
68    /// Mark all pictures in the DPB as unused for reference.
69    pub fn mark_all_as_unused_for_ref(&mut self) {
70        for mut picture in self.pictures_mut() {
71            picture.set_reference(Reference::None);
72        }
73    }
74
75    /// Gets the position of `needle` in the DPB, if any.
76    fn get_position(&self, needle: &Rc<RefCell<PictureData>>) -> Option<usize> {
77        self.entries
78            .iter()
79            .position(|handle| Rc::ptr_eq(&handle.0, needle))
80    }
81
82    /// Finds a reference picture in the DPB using `poc`.
83    pub fn find_ref_by_poc(&self, poc: i32) -> Option<DpbEntry<T>> {
84        let position = self
85            .pictures()
86            .position(|p| p.is_ref() && p.pic_order_cnt_val == poc);
87
88        log::debug!("find_ref_by_poc: {}, found position {:?}", poc, position);
89        Some(self.entries[position?].clone())
90    }
91
92    /// Finds a reference picture in the DPB using `poc` and `mask`.
93    pub fn find_ref_by_poc_masked(&self, poc: i32, mask: i32) -> Option<DpbEntry<T>> {
94        let position = self
95            .pictures()
96            .position(|p| p.is_ref() && p.pic_order_cnt_val & mask == poc);
97
98        log::debug!("find_ref_by_poc: {}, found position {:?}", poc, position);
99        Some(self.entries[position?].clone())
100    }
101
102    /// Finds a short term reference picture in the DPB using `poc`.
103    pub fn find_short_term_ref_by_poc(&self, poc: i32) -> Option<DpbEntry<T>> {
104        let position = self.pictures().position(|p| {
105            matches!(p.reference(), Reference::ShortTerm) && p.pic_order_cnt_val == poc
106        });
107
108        log::debug!(
109            "find_short_term_ref_by_poc: {}, found position {:?}",
110            poc,
111            position
112        );
113        Some(self.entries[position?].clone())
114    }
115
116    /// Drains the DPB by continuously invoking the bumping process.
117    pub fn drain(&mut self) -> Vec<DpbEntry<T>> {
118        log::debug!("Draining the DPB.");
119
120        let mut pics = vec![];
121        while let Some(pic) = self.bump(true) {
122            pics.push(pic);
123        }
124
125        pics
126    }
127
128    /// Whether the DPB needs bumping. See C.5.2.2.
129    pub fn needs_bumping(&mut self, sps: &Sps) -> bool {
130        let num_needed_for_output = self.pictures().filter(|pic| pic.needed_for_output).count();
131
132        let highest_tid = sps.max_sub_layers_minus1;
133        let max_num_reorder_pics = sps.max_num_reorder_pics[usize::from(highest_tid)];
134        let max_latency_increase_plus1 = sps.max_latency_increase_plus1[usize::from(highest_tid)];
135        let pic_over_max_latency = self.pictures().find(|pic| {
136            pic.needed_for_output && pic.pic_latency_cnt >= i32::from(max_latency_increase_plus1)
137        });
138        let max_dec_pic_buffering =
139            usize::from(sps.max_dec_pic_buffering_minus1[usize::from(highest_tid)]) + 1;
140
141        num_needed_for_output > max_num_reorder_pics.into()
142            || (max_latency_increase_plus1 != 0 && pic_over_max_latency.is_some())
143            || self.entries().len() >= max_dec_pic_buffering
144    }
145
146    /// Find the lowest POC in the DPB that can be bumped.
147    fn find_lowest_poc_for_bumping(&self) -> Option<DpbEntry<T>> {
148        let lowest = self
149            .pictures()
150            .filter(|pic| pic.needed_for_output)
151            .min_by_key(|pic| pic.pic_order_cnt_val)?;
152
153        let position = self
154            .entries
155            .iter()
156            .position(|handle| handle.0.borrow().pic_order_cnt_val == lowest.pic_order_cnt_val)
157            .unwrap();
158
159        Some(self.entries[position].clone())
160    }
161
162    /// See C.5.2.4 "Bumping process".
163    pub fn bump(&mut self, flush: bool) -> Option<DpbEntry<T>> {
164        let handle = self.find_lowest_poc_for_bumping()?;
165        let mut pic = handle.0.borrow_mut();
166
167        pic.needed_for_output = false;
168        log::debug!("Bumping POC {} from the dpb", pic.pic_order_cnt_val);
169        log::trace!("{:#?}", pic);
170
171        if !pic.is_ref() || flush {
172            let index = self.get_position(&handle.0).unwrap();
173
174            log::debug!(
175                "Removed POC {} from the dpb: reference: {}, flush: {}",
176                pic.pic_order_cnt_val,
177                pic.is_ref(),
178                flush
179            );
180            log::trace!("{:#?}", pic);
181
182            self.entries.remove(index);
183        }
184
185        Some(handle.clone())
186    }
187
188    /// See C.5.2.3. Happens when we are done decoding the picture.
189    pub fn needs_additional_bumping(&mut self, sps: &Sps) -> bool {
190        let num_needed_for_output = self.pictures().filter(|pic| pic.needed_for_output).count();
191        let highest_tid = sps.max_sub_layers_minus1;
192
193        let max_num_reorder_pics = sps.max_num_reorder_pics[usize::from(highest_tid)];
194        let max_latency_increase_plus1 = sps.max_latency_increase_plus1[usize::from(highest_tid)];
195
196        let pic_over_max_latency = self.pictures().find(|pic| {
197            pic.needed_for_output && pic.pic_latency_cnt >= i32::from(max_latency_increase_plus1)
198        });
199
200        num_needed_for_output > max_num_reorder_pics.into()
201            || (max_latency_increase_plus1 != 0 && pic_over_max_latency.is_some())
202    }
203
204    /// Clears the DPB, dropping all the pictures.
205    pub fn clear(&mut self) {
206        log::debug!("Clearing the DPB");
207
208        let max_num_pics = self.max_num_pics;
209
210        *self = Default::default();
211        self.max_num_pics = max_num_pics;
212    }
213
214    /// Removes all pictures which are marked as "not needed for output" and
215    /// "unused for reference". See C.5.2.2
216    pub fn remove_unused(&mut self) {
217        log::debug!("Removing unused pictures from DPB.");
218        self.entries.retain(|e| {
219            let pic = e.0.borrow();
220            let retain = pic.needed_for_output || pic.is_ref();
221            log::debug!("Retaining pic POC: {}: {}", pic.pic_order_cnt_val, retain);
222            retain
223        })
224    }
225
226    /// Store a picture and its backend handle in the DPB.
227    pub fn store_picture(
228        &mut self,
229        picture: Rc<RefCell<PictureData>>,
230        handle: T,
231    ) -> anyhow::Result<()> {
232        if self.entries.len() >= self.max_num_pics {
233            return Err(anyhow!("Can't add a picture to the DPB: DPB is full."));
234        }
235
236        let mut pic = picture.borrow_mut();
237        log::debug!(
238            "Stored picture POC {:?}, the DPB length is {:?}",
239            pic.pic_order_cnt_val,
240            self.entries.len()
241        );
242
243        if pic.pic_output_flag {
244            pic.needed_for_output = true;
245            pic.pic_latency_cnt = 0;
246        } else {
247            pic.needed_for_output = false;
248        }
249
250        // C.3.4.
251        // After all the slices of the current picture have been decoded, this
252        // picture is marked as "used for short-term reference".
253        pic.set_reference(Reference::ShortTerm);
254        drop(pic);
255
256        for mut pic in self.pictures_mut() {
257            pic.pic_latency_cnt += 1;
258        }
259
260        self.entries.push(DpbEntry(picture, handle));
261
262        Ok(())
263    }
264
265    /// Returns all the references in the DPB.
266    pub fn get_all_references(&self) -> Vec<DpbEntry<T>> {
267        self.entries
268            .iter()
269            .filter(|e| e.0.borrow().is_ref())
270            .cloned()
271            .collect()
272    }
273}
274
275impl<T: Clone> Default for Dpb<T> {
276    fn default() -> Self {
277        // See https://github.com/rust-lang/rust/issues/26925 on why this can't
278        // be derived.
279        Self {
280            entries: Default::default(),
281            max_num_pics: Default::default(),
282        }
283    }
284}
285
286impl<T: Clone> std::fmt::Debug for Dpb<T> {
287    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288        let pics = self
289            .entries
290            .iter()
291            .map(|h| &h.0)
292            .enumerate()
293            .collect::<Vec<_>>();
294        f.debug_struct("Dpb")
295            .field("pictures", &pics)
296            .field("max_num_pics", &self.max_num_pics)
297            .finish()
298    }
299}