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