• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 use std::cell::Ref;
6 use std::cell::RefCell;
7 use std::cell::RefMut;
8 use std::rc::Rc;
9 
10 use crate::codec::h265::parser::Sps;
11 use crate::codec::h265::picture::PictureData;
12 use 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)]
20 pub struct DpbEntry<T>(pub Rc<RefCell<PictureData>>, pub T);
21 
22 pub 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 
29 impl<T: Clone> Dpb<T> {
30     /// Returns an iterator over the underlying H265 pictures stored in the
31     /// DPB.
pictures(&self) -> impl Iterator<Item = Ref<'_, PictureData>>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.
pictures_mut(&mut self) -> impl Iterator<Item = RefMut<'_, PictureData>>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.
len(&self) -> usize43     pub fn len(&self) -> usize {
44         self.entries.len()
45     }
46 
is_empty(&self) -> bool47     pub fn is_empty(&self) -> bool {
48         self.len() == 0
49     }
50 
51     /// Get a reference to the whole DPB entries.
entries(&self) -> &Vec<DpbEntry<T>>52     pub fn entries(&self) -> &Vec<DpbEntry<T>> {
53         &self.entries
54     }
55 
56     /// Set the dpb's max num pics.
set_max_num_pics(&mut self, max_num_pics: usize)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.
max_num_pics(&self) -> usize62     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.
mark_all_as_unused_for_ref(&mut self)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.
get_position(&self, needle: &Rc<RefCell<PictureData>>) -> Option<usize>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`.
find_ref_by_poc(&self, poc: i32) -> Option<DpbEntry<T>>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`.
find_ref_by_poc_masked(&self, poc: i32, mask: i32) -> Option<DpbEntry<T>>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`.
find_short_term_ref_by_poc(&self, poc: i32) -> Option<DpbEntry<T>>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.
drain(&mut self) -> Vec<DpbEntry<T>>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.
needs_bumping(&mut self, sps: &Sps) -> bool118     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.
find_lowest_poc_for_bumping(&self) -> Option<DpbEntry<T>>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".
bump(&mut self, flush: bool) -> Option<DpbEntry<T>>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.
needs_additional_bumping(&mut self, sps: &Sps) -> bool178     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.
clear(&mut self)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
remove_unused(&mut self)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.
store_picture( &mut self, picture: Rc<RefCell<PictureData>>, handle: T, ) -> Result<(), String>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.
get_all_references(&self) -> Vec<DpbEntry<T>>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 
260 impl<T: Clone> Default for Dpb<T> {
default() -> Self261     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 
268 impl<T: Clone> std::fmt::Debug for Dpb<T> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result269     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 }
277