1 // Copyright 2022 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 anyhow::anyhow; 11 use anyhow::Result; 12 use log::debug; 13 14 use crate::decoders::h264::picture::Field; 15 use crate::decoders::h264::picture::IsIdr; 16 use crate::decoders::h264::picture::PictureData; 17 use crate::decoders::h264::picture::Reference; 18 use crate::decoders::DecodedHandle; 19 20 // Shortcut to refer to a DPB entry. 21 // 22 // The first member of the tuple is the `PictureData` for the frame. 23 // 24 // The second member is the backend handle of the frame. It can be `None` if the inserted picture 25 // is non-existing (i.e. `nonexisting` is true on the `PictureData`). 26 #[derive(Clone)] 27 pub struct DpbEntry<T: DecodedHandle>(pub Rc<RefCell<PictureData>>, pub Option<T>); 28 29 pub struct Dpb<T: DecodedHandle> { 30 /// List of `PictureData` and backend handles to decoded pictures. 31 entries: Vec<DpbEntry<T>>, 32 /// The maximum number of pictures that can be stored. 33 max_num_pics: usize, 34 /// Whether we're decoding in interlaced mode. Interlaced support is 35 /// inspired by the GStreamer implementation, in which frames are split if 36 /// interlaced=1. This makes reference marking easier. We also decode both 37 /// fields to the same surface, and this surface with both fields is 38 /// outputted only once. 39 interlaced: bool, 40 } 41 42 impl<T: DecodedHandle> Dpb<T> { 43 /// Returns an iterator over the underlying H264 pictures stored in the 44 /// DPB. pictures(&self) -> impl Iterator<Item = Ref<'_, PictureData>>45 pub fn pictures(&self) -> impl Iterator<Item = Ref<'_, PictureData>> { 46 self.entries.iter().map(|h| h.0.borrow()) 47 } 48 49 /// Returns a mutable iterator over the underlying H264 pictures stored in 50 /// the DPB. pictures_mut(&mut self) -> impl Iterator<Item = RefMut<'_, PictureData>>51 pub fn pictures_mut(&mut self) -> impl Iterator<Item = RefMut<'_, PictureData>> { 52 self.entries.iter().map(|h| h.0.borrow_mut()) 53 } 54 55 /// Returns the length of the DPB. len(&self) -> usize56 pub fn len(&self) -> usize { 57 self.entries.len() 58 } 59 60 /// Get a reference to the whole DPB entries. entries(&self) -> &Vec<DpbEntry<T>>61 pub fn entries(&self) -> &Vec<DpbEntry<T>> { 62 &self.entries 63 } 64 65 /// Set the dpb's max num pics. set_max_num_pics(&mut self, max_num_pics: usize)66 pub fn set_max_num_pics(&mut self, max_num_pics: usize) { 67 self.max_num_pics = max_num_pics; 68 } 69 70 /// Get a reference to the dpb's max num pics. max_num_pics(&self) -> usize71 pub fn max_num_pics(&self) -> usize { 72 self.max_num_pics 73 } 74 75 // Returns the number of reference frames, counting the first field only if 76 // dealing with interlaced content. num_ref_frames(&self) -> usize77 pub fn num_ref_frames(&self) -> usize { 78 self.pictures() 79 .filter(|p| p.is_ref() && !p.is_second_field()) 80 .count() 81 } 82 83 /// Get a reference to the dpb's interlaced mode. interlaced(&self) -> bool84 pub fn interlaced(&self) -> bool { 85 self.interlaced 86 } 87 88 /// Set the dpb's interlaced mode. set_interlaced(&mut self, interlaced: bool)89 pub fn set_interlaced(&mut self, interlaced: bool) { 90 self.interlaced = interlaced; 91 } 92 93 /// Find the short term reference picture with the lowest `frame_num_wrap` 94 /// value. find_short_term_lowest_frame_num_wrap(&self) -> Option<Rc<RefCell<PictureData>>>95 pub fn find_short_term_lowest_frame_num_wrap(&self) -> Option<Rc<RefCell<PictureData>>> { 96 let lowest = self 97 .entries 98 .iter() 99 .filter(|h| { 100 let p = h.0.borrow(); 101 matches!(p.reference(), Reference::ShortTerm) 102 }) 103 .cloned() 104 .map(|h| h.0) 105 .min_by_key(|h| { 106 let p = h.borrow(); 107 p.frame_num_wrap 108 }); 109 110 lowest 111 } 112 113 /// Mark all pictures in the DPB as unused for reference. mark_all_as_unused_for_ref(&mut self)114 pub fn mark_all_as_unused_for_ref(&mut self) { 115 for mut picture in self.pictures_mut() { 116 picture.set_reference(Reference::None, false); 117 } 118 } 119 120 /// Remove unused pictures from the DPB. A picture is not going to be used 121 /// anymore if it's a) not a reference and b) not needed for output remove_unused(&mut self)122 pub fn remove_unused(&mut self) { 123 self.entries.retain(|handle| { 124 let pic = handle.0.borrow(); 125 let discard = !pic.is_ref() && !pic.needed_for_output; 126 127 if discard { 128 log::debug!("Removing unused picture {:#?}", pic); 129 } 130 131 !discard 132 }); 133 } 134 135 /// Find a short term reference picture with the given `pic_num` value. find_short_term_with_pic_num(&self, pic_num: i32) -> Option<DpbEntry<T>>136 pub fn find_short_term_with_pic_num(&self, pic_num: i32) -> Option<DpbEntry<T>> { 137 let position = self 138 .pictures() 139 .position(|p| matches!(p.reference(), Reference::ShortTerm) && p.pic_num == pic_num); 140 141 log::debug!( 142 "find_short_term_with_pic_num: {}, found position {:?}", 143 pic_num, 144 position 145 ); 146 147 Some(self.entries[position?].clone()) 148 } 149 150 /// Find a long term reference picture with the given `long_term_pic_num` 151 /// value. find_long_term_with_long_term_pic_num( &self, long_term_pic_num: i32, ) -> Option<DpbEntry<T>>152 pub fn find_long_term_with_long_term_pic_num( 153 &self, 154 long_term_pic_num: i32, 155 ) -> Option<DpbEntry<T>> { 156 let position = self.pictures().position(|p| { 157 matches!(p.reference(), Reference::LongTerm) && p.long_term_pic_num == long_term_pic_num 158 }); 159 160 log::debug!( 161 "find_long_term_with_long_term_pic_num: {}, found position {:?}", 162 long_term_pic_num, 163 position 164 ); 165 166 Some(self.entries[position?].clone()) 167 } 168 169 /// Store a picture and its backend handle in the DPB. store_picture( &mut self, picture: Rc<RefCell<PictureData>>, handle: Option<T>, ) -> Result<()>170 pub fn store_picture( 171 &mut self, 172 picture: Rc<RefCell<PictureData>>, 173 handle: Option<T>, 174 ) -> Result<()> { 175 let max_pics = if self.interlaced { 176 self.max_num_pics * 2 177 } else { 178 self.max_num_pics 179 }; 180 181 if self.entries.len() >= max_pics { 182 return Err(anyhow!("Can't add a picture to the DPB: DPB is full.")); 183 } 184 185 let mut pic_mut = picture.borrow_mut(); 186 187 // C.4.2. Decoding of gaps in frame_num and storage of "non-existing" 188 // pictures 189 if !pic_mut.nonexisting { 190 pic_mut.needed_for_output = true; 191 } else { 192 pic_mut.needed_for_output = false; 193 } 194 195 if pic_mut.is_second_field() { 196 let first_field_rc = pic_mut.other_field_unchecked(); 197 drop(pic_mut); 198 let mut first_field = first_field_rc.borrow_mut(); 199 first_field.set_second_field_to(&picture); 200 } else { 201 drop(pic_mut); 202 } 203 204 let pic = picture.borrow(); 205 debug!( 206 "Stored picture POC {:?}, field {:?}, the DPB length is {:?}", 207 pic.pic_order_cnt, 208 pic.field, 209 self.entries.len() 210 ); 211 drop(pic); 212 213 self.entries.push(DpbEntry(picture, handle)); 214 215 Ok(()) 216 } 217 218 /// Whether the DPB has an empty slot for a new picture. has_empty_frame_buffer(&self) -> bool219 pub fn has_empty_frame_buffer(&self) -> bool { 220 if !self.interlaced { 221 self.entries.len() < self.max_num_pics 222 } else { 223 let count = self 224 .pictures() 225 .filter(|pic| { 226 !pic.is_second_field() 227 && (matches!(pic.field, Field::Frame) || pic.other_field().is_some()) 228 }) 229 .count(); 230 231 count < self.max_num_pics 232 } 233 } 234 235 /// Whether the DPB needs bumping, as described by clauses 1, 4, 5, 6 of 236 /// C.4.5.3 "Bumping" process. needs_bumping(&self, to_insert: &PictureData) -> bool237 pub fn needs_bumping(&self, to_insert: &PictureData) -> bool { 238 // In C.4.5.3 we handle clauses 2 and 3 separately. All other clauses 239 // check for an empty frame buffer first. Here we handle: 240 // - There is no empty frame buffer and a empty frame buffer is 241 // needed for storage of an inferred "non-existing" frame. 242 // 243 // - There is no empty frame buffer and an empty frame buffer is 244 // needed for storage of a decoded (non-IDR) reference picture. 245 // 246 // - There is no empty frame buffer and the current picture is a non- 247 // reference picture that is not the second field of a complementary 248 // non-reference field pair and there are pictures in the DPB that 249 // are marked as "needed for output" that precede the current 250 // non-reference picture in output order. 251 // 252 // Clauses 2 and 3 are handled by H264Codec::handle_picture and 253 // H264Codec::finish_picture, respectively. 254 if self.has_empty_frame_buffer() { 255 return false; 256 } 257 258 if to_insert.nonexisting { 259 return true; 260 } 261 262 let is_ref = !matches!(to_insert.reference(), Reference::None); 263 let non_idr_ref = is_ref && matches!(to_insert.is_idr, IsIdr::No); 264 265 if non_idr_ref { 266 return true; 267 } 268 269 let lowest_poc = match self.find_lowest_poc_for_bumping() { 270 Some(handle) => handle.0.borrow().pic_order_cnt, 271 None => return false, 272 }; 273 274 !to_insert.is_second_field_of_complementary_ref_pair() 275 && to_insert.pic_order_cnt > lowest_poc 276 } 277 278 /// Find the lowest POC in the DPB that can be bumped. find_lowest_poc_for_bumping(&self) -> Option<DpbEntry<T>>279 fn find_lowest_poc_for_bumping(&self) -> Option<DpbEntry<T>> { 280 let lowest = self 281 .pictures() 282 .filter(|pic| { 283 if !pic.needed_for_output { 284 return false; 285 } 286 287 let skip = !matches!(pic.field, Field::Frame) 288 && (pic.other_field().is_none() || pic.is_second_field()); 289 290 !skip 291 }) 292 .min_by_key(|pic| pic.pic_order_cnt)?; 293 294 let position = self 295 .entries 296 .iter() 297 .position(|handle| handle.0.borrow().pic_order_cnt == lowest.pic_order_cnt) 298 .unwrap(); 299 300 Some(self.entries[position].clone()) 301 } 302 303 /// Gets the position of `needle` in the DPB, if any. get_position(&self, needle: &Rc<RefCell<PictureData>>) -> Option<usize>304 fn get_position(&self, needle: &Rc<RefCell<PictureData>>) -> Option<usize> { 305 self.entries 306 .iter() 307 .position(|handle| Rc::ptr_eq(&handle.0, needle)) 308 } 309 310 /// Bump the dpb, returning a picture as per the bumping process described in C.4.5.3. 311 /// Note that this picture will still be referenced by its pair, if any. bump(&mut self, flush: bool) -> Option<DpbEntry<T>>312 pub fn bump(&mut self, flush: bool) -> Option<DpbEntry<T>> { 313 let handle = self.find_lowest_poc_for_bumping()?; 314 let mut pic = handle.0.borrow_mut(); 315 316 debug!("Bumping picture {:#?} from the dpb", pic); 317 318 pic.needed_for_output = false; 319 320 if !pic.is_ref() || flush { 321 let index = self.get_position(&handle.0).unwrap(); 322 log::debug!("removed picture {:#?} from dpb", pic); 323 self.entries.remove(index); 324 } 325 326 if pic.other_field().is_some() { 327 let other_field_rc = pic.other_field_unchecked(); 328 let mut other_field = other_field_rc.borrow_mut(); 329 other_field.needed_for_output = false; 330 331 if !other_field.is_ref() { 332 log::debug!("other_field: removed picture {:#?} from dpb", other_field); 333 let index = self.get_position(&other_field_rc).unwrap(); 334 self.entries.remove(index); 335 } 336 } 337 338 drop(pic); 339 Some(handle) 340 } 341 342 /// Drains the DPB by continuously invoking the bumping process. drain(&mut self) -> Vec<DpbEntry<T>>343 pub fn drain(&mut self) -> Vec<DpbEntry<T>> { 344 debug!("Draining the DPB."); 345 346 let mut pics = vec![]; 347 348 while let Some(pic) = self.bump(true) { 349 pics.push(pic); 350 } 351 352 pics 353 } 354 355 /// Clears the DPB, dropping all the pictures. clear(&mut self)356 pub fn clear(&mut self) { 357 debug!("Clearing the DPB"); 358 359 let max_num_pics = self.max_num_pics; 360 let interlaced = self.interlaced; 361 362 *self = Default::default(); 363 364 self.max_num_pics = max_num_pics; 365 self.interlaced = interlaced; 366 } 367 368 /// Gets a Vec<ContainedPicture> of short term refs into `out` get_short_term_refs(&self, out: &mut Vec<DpbEntry<T>>)369 pub fn get_short_term_refs(&self, out: &mut Vec<DpbEntry<T>>) { 370 out.extend( 371 self.entries 372 .iter() 373 .filter(|&handle| matches!(handle.0.borrow().reference(), Reference::ShortTerm)) 374 .cloned(), 375 ) 376 } 377 378 /// Gets a Vec<ContainedPicture> of long term refs into `out` get_long_term_refs(&self, out: &mut Vec<DpbEntry<T>>)379 pub fn get_long_term_refs(&self, out: &mut Vec<DpbEntry<T>>) { 380 out.extend( 381 self.entries 382 .iter() 383 .filter(|&handle| matches!(handle.0.borrow().reference(), Reference::LongTerm)) 384 .cloned(), 385 ) 386 } 387 } 388 389 impl<T: DecodedHandle> Default for Dpb<T> { default() -> Self390 fn default() -> Self { 391 // See https://github.com/rust-lang/rust/issues/26925 on why this can't 392 // be derived. 393 Self { 394 entries: Default::default(), 395 max_num_pics: Default::default(), 396 interlaced: Default::default(), 397 } 398 } 399 } 400 401 impl<T: DecodedHandle> std::fmt::Debug for Dpb<T> { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result402 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 403 let pics = self 404 .entries 405 .iter() 406 .map(|h| &h.0) 407 .enumerate() 408 .collect::<Vec<_>>(); 409 f.debug_struct("Dpb") 410 .field("pictures", &pics) 411 .field("max_num_pics", &self.max_num_pics) 412 .field("interlaced", &self.interlaced) 413 .finish() 414 } 415 } 416