• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::RefMut;
7 use std::fmt;
8 use std::rc::Rc;
9 
10 use log::debug;
11 
12 use crate::codec::h264::parser::MaxLongTermFrameIdx;
13 use crate::codec::h264::parser::RefPicMarkingInner;
14 use crate::codec::h264::parser::Sps;
15 use crate::codec::h264::picture::Field;
16 use crate::codec::h264::picture::FieldRank;
17 use crate::codec::h264::picture::IsIdr;
18 use crate::codec::h264::picture::PictureData;
19 use crate::codec::h264::picture::RcPictureData;
20 use crate::codec::h264::picture::Reference;
21 
22 pub type DpbPicRefList<'a, H> = Vec<&'a DpbEntry<H>>;
23 
24 /// All the reference picture lists used to decode a picture.
25 #[derive(Default)]
26 pub struct ReferencePicLists {
27     /// Reference picture list for P slices. Retains the same meaning as in the
28     /// specification. Points into the pictures stored in the DPB. Derived once
29     /// per picture.
30     pub ref_pic_list_p0: Vec<usize>,
31     /// Reference picture list 0 for B slices. Retains the same meaning as in
32     /// the specification. Points into the pictures stored in the DPB. Derived
33     /// once per picture.
34     pub ref_pic_list_b0: Vec<usize>,
35     /// Reference picture list 1 for B slices. Retains the same meaning as in
36     /// the specification. Points into the pictures stored in the DPB. Derived
37     /// once per picture.
38     pub ref_pic_list_b1: Vec<usize>,
39 }
40 
41 /// A single entry in the DPB.
42 #[derive(Clone)]
43 pub struct DpbEntry<T> {
44     /// `PictureData` of the frame in this entry.
45     pub pic: RcPictureData,
46     /// Reference to the decoded frame, ensuring that it doesn't get reused while in the DPB.
47     pub reference: Option<T>,
48     /// Decoded frame promise. It will be set when the frame enters the DPB, and taken during the
49     /// bump process.
50     pub decoded_frame: Option<T>,
51     /// Whether the picture is still waiting to be bumped and displayed.
52     needed_for_output: bool,
53 }
54 
55 impl<T> DpbEntry<T> {
56     /// Returns `true` is the entry is eligible to be bumped.
57     ///
58     /// An entry can be bumped if its `needed_for_output` flag is true and it is the first field of
59     /// a frame which fields are all decoded.
is_bumpable(&self) -> bool60     fn is_bumpable(&self) -> bool {
61         if !self.needed_for_output {
62             return false;
63         }
64 
65         let pic = self.pic.borrow();
66         match pic.field {
67             // Progressive frames in the DPB are fully decoded.
68             Field::Frame => true,
69             // Only return the first field of fully decoded interlaced frames.
70             Field::Top | Field::Bottom => matches!(pic.field_rank(), FieldRank::First(..)),
71         }
72     }
73 }
74 
75 pub struct Dpb<T> {
76     /// List of `PictureData` and backend handles to decoded pictures.
77     entries: Vec<DpbEntry<T>>,
78     /// The maximum number of pictures that can be stored.
79     max_num_pics: usize,
80     /// Indicates an upper bound for the number of frames buffers, in the
81     /// decoded picture buffer (DPB), that are required for storing frames,
82     /// complementary field pairs, and non-paired fields before output. It is a
83     /// requirement of bitstream conformance that the maximum number of frames,
84     /// complementary field pairs, or non-paired fields that precede any frame,
85     /// complementary field pair, or non-paired field in the coded video
86     /// sequence in decoding order and follow it in output order shall be less
87     /// than or equal to max_num_reorder_frames.
88     max_num_reorder_frames: usize,
89     /// Whether we're decoding in interlaced mode. Interlaced support is
90     /// inspired by the GStreamer implementation, in which frames are split if
91     /// interlaced=1. This makes reference marking easier. We also decode both
92     /// fields to the same frame, and this frame with both fields is outputted
93     /// only once.
94     interlaced: bool,
95 }
96 
97 #[derive(Debug)]
98 pub enum StorePictureError {
99     DpbIsFull,
100 }
101 
102 impl fmt::Display for StorePictureError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result103     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104         write!(f, "DPB is full")
105     }
106 }
107 
108 impl std::error::Error for StorePictureError {}
109 
110 #[derive(Debug)]
111 pub enum MmcoError {
112     NoShortTermPic,
113     ExpectedMarked,
114     ExpectedExisting,
115     UnknownMmco(u8),
116 }
117 
118 impl fmt::Display for MmcoError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result119     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120         match self {
121             MmcoError::NoShortTermPic => {
122                 write!(f, "could not find ShortTerm picture to mark in the DPB")
123             }
124             MmcoError::ExpectedMarked => {
125                 write!(f, "a ShortTerm picture was expected to be marked for MMCO=3")
126             }
127             MmcoError::ExpectedExisting => {
128                 write!(f, "picture cannot be marked as nonexisting for MMCO=3")
129             }
130             MmcoError::UnknownMmco(x) => write!(f, "unknown MMCO: {}", x),
131         }
132     }
133 }
134 
135 impl std::error::Error for MmcoError {}
136 
137 impl<T: Clone> Dpb<T> {
138     /// Returns an iterator over the underlying H264 pictures stored in the
139     /// DPB.
pictures(&self) -> impl Iterator<Item = Ref<'_, PictureData>>140     fn pictures(&self) -> impl Iterator<Item = Ref<'_, PictureData>> {
141         self.entries.iter().map(|h| h.pic.borrow())
142     }
143 
144     /// Returns a mutable iterator over the underlying H264 pictures stored in
145     /// the DPB.
pictures_mut(&mut self) -> impl Iterator<Item = RefMut<'_, PictureData>>146     fn pictures_mut(&mut self) -> impl Iterator<Item = RefMut<'_, PictureData>> {
147         self.entries.iter().map(|h| h.pic.borrow_mut())
148     }
149 
150     /// Returns the length of the DPB.
len(&self) -> usize151     pub fn len(&self) -> usize {
152         self.entries.len()
153     }
154 
is_empty(&self) -> bool155     pub fn is_empty(&self) -> bool {
156         self.len() == 0
157     }
158 
159     /// Get a reference to the whole DPB entries.
entries(&self) -> &Vec<DpbEntry<T>>160     pub fn entries(&self) -> &Vec<DpbEntry<T>> {
161         &self.entries
162     }
163 
164     /// Set the DPB's limits in terms of maximum number or pictures.
set_limits(&mut self, max_num_pics: usize, max_num_reorder_frames: usize)165     pub fn set_limits(&mut self, max_num_pics: usize, max_num_reorder_frames: usize) {
166         self.max_num_pics = max_num_pics;
167         self.max_num_reorder_frames = max_num_reorder_frames;
168     }
169 
170     /// Get a reference to the dpb's max num pics.
max_num_pics(&self) -> usize171     pub fn max_num_pics(&self) -> usize {
172         self.max_num_pics
173     }
174 
175     // Returns the number of reference frames, counting the first field only if
176     // dealing with interlaced content.
num_ref_frames(&self) -> usize177     pub fn num_ref_frames(&self) -> usize {
178         self.pictures().filter(|p| p.is_ref() && !p.is_second_field()).count()
179     }
180 
181     /// Get a reference to the dpb's interlaced mode.
interlaced(&self) -> bool182     pub fn interlaced(&self) -> bool {
183         self.interlaced
184     }
185 
186     /// Set the dpb's interlaced mode.
set_interlaced(&mut self, interlaced: bool)187     pub fn set_interlaced(&mut self, interlaced: bool) {
188         self.interlaced = interlaced;
189     }
190 
191     /// Find the short term reference picture with the lowest `frame_num_wrap`
192     /// value.
find_short_term_lowest_frame_num_wrap(&self) -> Option<&DpbEntry<T>>193     pub fn find_short_term_lowest_frame_num_wrap(&self) -> Option<&DpbEntry<T>> {
194         let lowest = self
195             .entries
196             .iter()
197             .filter(|h| {
198                 let p = h.pic.borrow();
199                 matches!(p.reference(), Reference::ShortTerm)
200             })
201             .min_by_key(|h| {
202                 let p = h.pic.borrow();
203                 p.frame_num_wrap
204             });
205 
206         lowest
207     }
208 
209     /// Mark all pictures in the DPB as unused for reference.
mark_all_as_unused_for_ref(&mut self)210     pub fn mark_all_as_unused_for_ref(&mut self) {
211         for mut picture in self.pictures_mut() {
212             picture.set_reference(Reference::None, false);
213         }
214     }
215 
216     /// Remove unused pictures from the DPB. A picture is not going to be used
217     /// anymore if it's a) not a reference and b) not needed for output
remove_unused(&mut self)218     fn remove_unused(&mut self) {
219         self.entries.retain(|entry| {
220             let pic = entry.pic.borrow();
221             let discard = !pic.is_ref() && !entry.needed_for_output;
222 
223             if discard {
224                 log::debug!("Removing unused picture {:#?}", pic);
225             }
226 
227             !discard
228         });
229     }
230 
231     /// Find a short term reference picture with the given `pic_num` value.
find_short_term_with_pic_num_pos(&self, pic_num: i32) -> Option<usize>232     fn find_short_term_with_pic_num_pos(&self, pic_num: i32) -> Option<usize> {
233         let position = self
234             .pictures()
235             .position(|p| matches!(p.reference(), Reference::ShortTerm) && p.pic_num == pic_num);
236 
237         log::debug!("find_short_term_with_pic_num: {}, found position {:?}", pic_num, position);
238 
239         position
240     }
241 
242     /// 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>>243     pub fn find_short_term_with_pic_num(&self, pic_num: i32) -> Option<&DpbEntry<T>> {
244         let position = self.find_short_term_with_pic_num_pos(pic_num)?;
245         Some(&self.entries[position])
246     }
247 
248     /// Find a long term reference picture with the given `long_term_pic_num`
249     /// value.
find_long_term_with_long_term_pic_num_pos(&self, long_term_pic_num: u32) -> Option<usize>250     fn find_long_term_with_long_term_pic_num_pos(&self, long_term_pic_num: u32) -> Option<usize> {
251         let position = self.pictures().position(|p| {
252             matches!(p.reference(), Reference::LongTerm) && p.long_term_pic_num == long_term_pic_num
253         });
254 
255         log::debug!(
256             "find_long_term_with_long_term_pic_num: {}, found position {:?}",
257             long_term_pic_num,
258             position
259         );
260 
261         position
262     }
263 
264     /// Find a long term reference picture with the given `long_term_pic_num`
265     /// value.
find_long_term_with_long_term_pic_num( &self, long_term_pic_num: u32, ) -> Option<&DpbEntry<T>>266     pub fn find_long_term_with_long_term_pic_num(
267         &self,
268         long_term_pic_num: u32,
269     ) -> Option<&DpbEntry<T>> {
270         let position = self.find_long_term_with_long_term_pic_num_pos(long_term_pic_num)?;
271         Some(&self.entries[position])
272     }
273 
274     /// Store `picture` and its backend handle in the DPB.
store_picture( &mut self, picture: RcPictureData, handle: Option<T>, ) -> Result<(), StorePictureError>275     pub fn store_picture(
276         &mut self,
277         picture: RcPictureData,
278         handle: Option<T>,
279     ) -> Result<(), StorePictureError> {
280         let max_pics = if self.interlaced { self.max_num_pics * 2 } else { self.max_num_pics };
281 
282         if self.entries.len() >= max_pics {
283             return Err(StorePictureError::DpbIsFull);
284         }
285 
286         let pic = picture.borrow();
287 
288         // C.4.2. Decoding of gaps in frame_num and storage of "non-existing"
289         // pictures
290         let needed_for_output = !pic.nonexisting;
291 
292         debug!(
293             "Stored picture POC {:?}, field {:?}, the DPB length is {:?}",
294             pic.pic_order_cnt,
295             pic.field,
296             self.entries.len()
297         );
298         drop(pic);
299 
300         self.entries.push(DpbEntry {
301             pic: picture,
302             reference: handle.clone(),
303             decoded_frame: handle,
304             needed_for_output,
305         });
306 
307         Ok(())
308     }
309 
310     /// Whether the DPB has an empty slot for a new picture.
has_empty_frame_buffer(&self) -> bool311     pub fn has_empty_frame_buffer(&self) -> bool {
312         let count = if !self.interlaced {
313             self.entries.len()
314         } else {
315             self.pictures()
316                 .filter(|pic| {
317                     matches!(pic.field_rank(), FieldRank::First(..))
318                         || (matches!(pic.field_rank(), FieldRank::Single)
319                             && pic.field == Field::Frame)
320                 })
321                 .count()
322         };
323 
324         count < self.max_num_pics
325     }
326 
327     /// Whether the DPB needs bumping, as described by clauses 1, 4, 5, 6 of
328     /// C.4.5.3 "Bumping" process.
needs_bumping(&self, to_insert: &PictureData) -> bool329     pub fn needs_bumping(&self, to_insert: &PictureData) -> bool {
330         // In C.4.5.3 we handle clauses 2 and 3 separately. All other clauses
331         // check for an empty frame buffer first. Here we handle:
332         //    - There is no empty frame buffer and a empty frame buffer is
333         //    needed for storage of an inferred "non-existing" frame.
334         //
335         //    - There is no empty frame buffer and an empty frame buffer is
336         //    needed for storage of a decoded (non-IDR) reference picture.
337         //
338         //    - There is no empty frame buffer and the current picture is a non-
339         //    reference picture that is not the second field of a complementary
340         //    non-reference field pair and there are pictures in the DPB that
341         //    are marked as "needed for output" that precede the current
342         //    non-reference picture in output order.
343         //
344         // Clauses 2 and 3 are handled by H264Codec::handle_picture and
345         // H264Codec::finish_picture, respectively.
346         if self.has_empty_frame_buffer() {
347             return false;
348         }
349 
350         if to_insert.nonexisting {
351             return true;
352         }
353 
354         let non_idr_ref = to_insert.is_ref() && matches!(to_insert.is_idr, IsIdr::No);
355         if non_idr_ref {
356             return true;
357         }
358 
359         let lowest_poc = match self.find_lowest_poc_for_bumping() {
360             Some(handle) => handle.pic.borrow().pic_order_cnt,
361             None => return false,
362         };
363 
364         !to_insert.is_second_field_of_complementary_ref_pair()
365             && to_insert.pic_order_cnt > lowest_poc
366     }
367 
368     /// Find the lowest POC in the DPB that can be bumped.
find_lowest_poc_for_bumping(&self) -> Option<&DpbEntry<T>>369     fn find_lowest_poc_for_bumping(&self) -> Option<&DpbEntry<T>> {
370         self.entries
371             .iter()
372             .filter(|entry| entry.is_bumpable())
373             .min_by_key(|handle| handle.pic.borrow().pic_order_cnt)
374     }
375 
376     /// Find the lowest POC in the DPB that can be bumped and return a mutable reference.
find_lowest_poc_for_bumping_mut(&mut self) -> Option<&mut DpbEntry<T>>377     fn find_lowest_poc_for_bumping_mut(&mut self) -> Option<&mut DpbEntry<T>> {
378         self.entries
379             .iter_mut()
380             .filter(|entry| entry.is_bumpable())
381             .min_by_key(|handle| handle.pic.borrow().pic_order_cnt)
382     }
383 
384     /// Bump the dpb, returning a picture as per the bumping process described in C.4.5.3.
385     /// Note that this picture will still be referenced by its pair, if any.
bump(&mut self) -> Option<Option<T>>386     fn bump(&mut self) -> Option<Option<T>> {
387         let dpb_entry = self.find_lowest_poc_for_bumping_mut()?;
388         let handle = dpb_entry.decoded_frame.take();
389         let pic = dpb_entry.pic.borrow();
390 
391         debug!("Bumping picture {:#?} from the dpb", pic);
392 
393         dpb_entry.needed_for_output = false;
394         // Lookup the second field entry and flip as well.
395         // `find_lowest_poc_for_bumping_mut` always returns the first field, never the second.
396         if let FieldRank::First(second_field) = pic.field_rank() {
397             let second_field = second_field.upgrade();
398             drop(pic);
399             if let Some(second_field) =
400                 second_field.and_then(|f| self.entries.iter_mut().find(|e| Rc::ptr_eq(&f, &e.pic)))
401             {
402                 second_field.needed_for_output = false;
403             }
404         }
405 
406         Some(handle)
407     }
408 
409     /// Drains the DPB by continuously invoking the bumping process.
drain(&mut self) -> Vec<Option<T>>410     pub fn drain(&mut self) -> Vec<Option<T>> {
411         debug!("Draining the DPB.");
412 
413         let mut pics = vec![];
414 
415         while let Some(pic) = self.bump() {
416             pics.push(pic);
417         }
418 
419         self.clear();
420 
421         pics
422     }
423 
424     /// Clears the DPB, dropping all the pictures.
clear(&mut self)425     pub fn clear(&mut self) {
426         debug!("Clearing the DPB");
427 
428         let max_num_pics = self.max_num_pics;
429         let max_num_reorder_frames = self.max_num_reorder_frames;
430         let interlaced = self.interlaced;
431 
432         *self = Default::default();
433 
434         self.max_num_pics = max_num_pics;
435         self.max_num_reorder_frames = max_num_reorder_frames;
436         self.interlaced = interlaced;
437     }
438 
439     /// Returns an iterator of short term refs.
short_term_refs_iter(&self) -> impl Iterator<Item = &DpbEntry<T>>440     pub fn short_term_refs_iter(&self) -> impl Iterator<Item = &DpbEntry<T>> {
441         self.entries
442             .iter()
443             .filter(|&handle| matches!(handle.pic.borrow().reference(), Reference::ShortTerm))
444     }
445 
446     /// Returns an iterator of long term refs.
long_term_refs_iter(&self) -> impl Iterator<Item = &DpbEntry<T>>447     pub fn long_term_refs_iter(&self) -> impl Iterator<Item = &DpbEntry<T>> {
448         self.entries
449             .iter()
450             .filter(|&handle| matches!(handle.pic.borrow().reference(), Reference::LongTerm))
451     }
452 
update_pic_nums( &mut self, frame_num: u32, max_frame_num: u32, current_pic: &PictureData, )453     pub fn update_pic_nums(
454         &mut self,
455         frame_num: u32,
456         max_frame_num: u32,
457         current_pic: &PictureData,
458     ) {
459         for mut pic in self.pictures_mut() {
460             if !pic.is_ref() {
461                 continue;
462             }
463 
464             if *pic.reference() == Reference::LongTerm {
465                 pic.long_term_pic_num = if current_pic.field == Field::Frame {
466                     pic.long_term_frame_idx
467                 } else if current_pic.field == pic.field {
468                     2 * pic.long_term_frame_idx + 1
469                 } else {
470                     2 * pic.long_term_frame_idx
471                 };
472             } else {
473                 pic.frame_num_wrap = if pic.frame_num > frame_num {
474                     pic.frame_num as i32 - max_frame_num as i32
475                 } else {
476                     pic.frame_num as i32
477                 };
478 
479                 pic.pic_num = if current_pic.field == Field::Frame {
480                     pic.frame_num_wrap
481                 } else if pic.field == current_pic.field {
482                     2 * pic.frame_num_wrap + 1
483                 } else {
484                     2 * pic.frame_num_wrap
485                 };
486             }
487         }
488     }
489 
490     /// Gets the number of frames that could potentially be output.
num_not_outputted(&self) -> usize491     pub fn num_not_outputted(&self) -> usize {
492         self.entries.iter().filter(|e| e.needed_for_output).count()
493     }
494 
495     /// Bumps the DPB if needed. DPB bumping is described on C.4.5.3.
bump_as_needed(&mut self, current_pic: &PictureData) -> Vec<Option<T>>496     pub fn bump_as_needed(&mut self, current_pic: &PictureData) -> Vec<Option<T>> {
497         let mut pics = vec![];
498         // We bump proactively, even though the spec only says we need to bump if the DPB is full.
499         // This cuts down on decode latency and seems to be in line with Codec2's expectations.
500         // Also, there is precedence for this in Chrome's H264 decoder.
501         while self.needs_bumping(current_pic)
502             || self.num_not_outputted() >= self.max_num_reorder_frames
503         {
504             match self.bump() {
505                 Some(pic) => pics.push(pic),
506                 None => return pics,
507             }
508             self.remove_unused();
509         }
510 
511         pics
512     }
513 
514     // 8.2.5.3
sliding_window_marking(&mut self, pic: &mut PictureData, sps: &Sps)515     pub fn sliding_window_marking(&mut self, pic: &mut PictureData, sps: &Sps) {
516         // If the current picture is a coded field that is the second field in
517         // decoding order of a complementary reference field pair, and the first
518         // field has been marked as "used for short-term reference", the current
519         // picture and the complementary reference field pair are also marked as
520         // "used for short-term reference".
521         if let FieldRank::Second(other_field) = pic.field_rank() {
522             if matches!(other_field.borrow().reference(), Reference::ShortTerm) {
523                 pic.set_reference(Reference::ShortTerm, false);
524                 return;
525             }
526         }
527 
528         let mut num_ref_pics = self.num_ref_frames();
529         let max_num_ref_frames = std::cmp::max(1, sps.max_num_ref_frames as usize);
530 
531         if num_ref_pics < max_num_ref_frames {
532             return;
533         }
534 
535         while num_ref_pics >= max_num_ref_frames {
536             if let Some(to_unmark) = self.find_short_term_lowest_frame_num_wrap() {
537                 to_unmark.pic.borrow_mut().set_reference(Reference::None, true);
538                 num_ref_pics -= 1;
539             } else {
540                 log::warn!("could not find a ShortTerm picture to unmark in the DPB");
541                 break;
542             }
543         }
544 
545         self.remove_unused();
546     }
547 
mmco_op_1( &mut self, pic: &PictureData, marking: &RefPicMarkingInner, ) -> Result<(), MmcoError>548     pub fn mmco_op_1(
549         &mut self,
550         pic: &PictureData,
551         marking: &RefPicMarkingInner,
552     ) -> Result<(), MmcoError> {
553         let pic_num_x = pic.pic_num - (marking.difference_of_pic_nums_minus1 as i32 + 1);
554 
555         log::debug!("MMCO op 1 for pic_num_x {}", pic_num_x);
556         log::trace!("Dpb state before MMCO=1: {:#?}", self);
557 
558         let to_mark =
559             self.find_short_term_with_pic_num(pic_num_x).ok_or(MmcoError::NoShortTermPic)?;
560 
561         to_mark.pic.borrow_mut().set_reference(Reference::None, matches!(pic.field, Field::Frame));
562 
563         Ok(())
564     }
565 
mmco_op_2( &mut self, pic: &PictureData, marking: &RefPicMarkingInner, ) -> Result<(), MmcoError>566     pub fn mmco_op_2(
567         &mut self,
568         pic: &PictureData,
569         marking: &RefPicMarkingInner,
570     ) -> Result<(), MmcoError> {
571         log::debug!("MMCO op 2 for long_term_pic_num {}", marking.long_term_pic_num);
572 
573         log::trace!("Dpb state before MMCO=2: {:#?}", self);
574 
575         let to_mark = self
576             .find_long_term_with_long_term_pic_num(marking.long_term_pic_num)
577             .ok_or(MmcoError::NoShortTermPic)?;
578 
579         to_mark.pic.borrow_mut().set_reference(Reference::None, matches!(pic.field, Field::Frame));
580 
581         Ok(())
582     }
583 
mmco_op_3( &mut self, pic: &PictureData, marking: &RefPicMarkingInner, ) -> Result<(), MmcoError>584     pub fn mmco_op_3(
585         &mut self,
586         pic: &PictureData,
587         marking: &RefPicMarkingInner,
588     ) -> Result<(), MmcoError> {
589         let pic_num_x = pic.pic_num - (marking.difference_of_pic_nums_minus1 as i32 + 1);
590 
591         log::debug!("MMCO op 3 for pic_num_x {}", pic_num_x);
592         log::trace!("Dpb state before MMCO=3: {:#?}", self);
593 
594         let to_mark_as_long_pos =
595             self.find_short_term_with_pic_num_pos(pic_num_x).ok_or(MmcoError::NoShortTermPic)?;
596         let to_mark_as_long = &self.entries[to_mark_as_long_pos].pic;
597 
598         if !matches!(to_mark_as_long.borrow().reference(), Reference::ShortTerm) {
599             return Err(MmcoError::ExpectedMarked);
600         }
601 
602         if to_mark_as_long.borrow().nonexisting {
603             return Err(MmcoError::ExpectedExisting);
604         }
605 
606         let to_mark_as_long_ptr = to_mark_as_long.as_ptr();
607         let to_mark_as_long_other_field_ptr =
608             to_mark_as_long.borrow().other_field().map(|f| f.as_ptr());
609 
610         let long_term_frame_idx = marking.long_term_frame_idx;
611 
612         for mut picture in self.pictures_mut() {
613             let long_already_assigned = matches!(picture.reference(), Reference::LongTerm)
614                 && picture.long_term_frame_idx == long_term_frame_idx;
615 
616             if long_already_assigned {
617                 let is_frame = matches!(picture.field, Field::Frame);
618 
619                 let is_complementary_field_pair = picture
620                     .other_field()
621                     .map(|f| {
622                         let pic = f.borrow();
623                         matches!(pic.reference(), Reference::LongTerm)
624                             && pic.long_term_frame_idx == long_term_frame_idx
625                     })
626                     .unwrap_or(false);
627 
628                 // When LongTermFrameIdx equal to
629                 // long_term_frame_idx is already assigned to a
630                 // long-term reference frame or a long-term
631                 // complementary reference field pair, that frame or
632                 // complementary field pair and both of its fields
633                 // are marked as "unused for reference"
634                 if is_frame || is_complementary_field_pair {
635                     picture.set_reference(Reference::None, true);
636                     break;
637                 }
638 
639                 // When LongTermFrameIdx is already assigned to a
640                 // reference field, and that reference field is not
641                 // part of a complementary field pair that includes
642                 // the picture specified by picNumX, that field is
643                 // marked as "unused for reference".
644                 let reference_field_is_not_part_of_pic_x = match picture.other_field() {
645                     None => true,
646                     Some(other_field) => {
647                         // Check that the fields do not reference one another.
648                         !std::ptr::eq(other_field.as_ptr(), to_mark_as_long_ptr)
649                             && to_mark_as_long_other_field_ptr
650                                 .map(|p| !std::ptr::eq(p, &(*picture)))
651                                 .unwrap_or(true)
652                     }
653                 };
654 
655                 if reference_field_is_not_part_of_pic_x {
656                     picture.set_reference(Reference::None, false);
657                     break;
658                 }
659             }
660         }
661 
662         let is_frame = matches!(pic.field, Field::Frame);
663         let to_mark_as_long = &self.entries[to_mark_as_long_pos].pic;
664         to_mark_as_long.borrow_mut().set_reference(Reference::LongTerm, is_frame);
665         to_mark_as_long.borrow_mut().long_term_frame_idx = long_term_frame_idx;
666 
667         if let Some(other_field) = to_mark_as_long.borrow().other_field() {
668             let mut other_field = other_field.borrow_mut();
669             if matches!(other_field.reference(), Reference::LongTerm) {
670                 other_field.long_term_frame_idx = long_term_frame_idx;
671 
672                 log::debug!(
673                     "Assigned long_term_frame_idx {} to other_field {:#?}",
674                     long_term_frame_idx,
675                     &other_field
676                 );
677             }
678         }
679 
680         Ok(())
681     }
682 
683     /// Returns the new `max_long_term_frame_idx`.
mmco_op_4(&mut self, marking: &RefPicMarkingInner) -> MaxLongTermFrameIdx684     pub fn mmco_op_4(&mut self, marking: &RefPicMarkingInner) -> MaxLongTermFrameIdx {
685         log::debug!("MMCO op 4, max_long_term_frame_idx: {:?}", marking.max_long_term_frame_idx);
686 
687         log::trace!("Dpb state before MMCO=4: {:#?}", self);
688 
689         for mut dpb_pic in self
690             .pictures_mut()
691             .filter(|pic| matches!(pic.reference(), Reference::LongTerm))
692             .filter(|pic| marking.max_long_term_frame_idx < pic.long_term_frame_idx)
693         {
694             dpb_pic.set_reference(Reference::None, false);
695         }
696 
697         marking.max_long_term_frame_idx
698     }
699 
700     /// Returns the new `max_long_term_frame_idx`.
mmco_op_5(&mut self, pic: &mut PictureData) -> MaxLongTermFrameIdx701     pub fn mmco_op_5(&mut self, pic: &mut PictureData) -> MaxLongTermFrameIdx {
702         log::debug!("MMCO op 5, marking all pictures in the DPB as unused for reference");
703         log::trace!("Dpb state before MMCO=5: {:#?}", self);
704 
705         self.mark_all_as_unused_for_ref();
706 
707         pic.has_mmco_5 = true;
708 
709         // A picture including a memory_management_control_operation equal to 5
710         // shall have frame_num constraints as described above and, after the
711         // decoding of the current picture and the processing of the memory
712         // management control operations, the picture shall be inferred to have
713         // had frame_num equal to 0 for all subsequent use in the decoding
714         // process, except as specified in clause 7.4.1.2.4.
715         pic.frame_num = 0;
716 
717         // When the current picture includes a
718         // memory_management_control_operation equal to 5, after the decoding of
719         // the current picture, tempPicOrderCnt is set equal to PicOrderCnt(
720         // CurrPic ), TopFieldOrderCnt of the current picture (if any) is set
721         // equal to TopFieldOrderCnt − tempPicOrderCnt, and BottomFieldOrderCnt
722         // of the current picture (if any) is set equal to BottomFieldOrderCnt −
723         // tempPicOrderCnt
724         match pic.field {
725             Field::Top => {
726                 pic.top_field_order_cnt = 0;
727                 pic.pic_order_cnt = 0;
728             }
729             Field::Bottom => {
730                 pic.bottom_field_order_cnt = 0;
731                 pic.pic_order_cnt = 0;
732             }
733             Field::Frame => {
734                 pic.top_field_order_cnt -= pic.pic_order_cnt;
735                 pic.bottom_field_order_cnt -= pic.pic_order_cnt;
736                 pic.pic_order_cnt =
737                     std::cmp::min(pic.top_field_order_cnt, pic.bottom_field_order_cnt);
738             }
739         }
740 
741         MaxLongTermFrameIdx::NoLongTermFrameIndices
742     }
743 
mmco_op_6(&mut self, pic: &mut PictureData, marking: &RefPicMarkingInner)744     pub fn mmco_op_6(&mut self, pic: &mut PictureData, marking: &RefPicMarkingInner) {
745         let long_term_frame_idx = marking.long_term_frame_idx;
746 
747         log::debug!("MMCO op 6, long_term_frame_idx: {}", long_term_frame_idx);
748         log::trace!("Dpb state before MMCO=6: {:#?}", self);
749 
750         for mut dpb_pic in self.pictures_mut() {
751             // When a variable LongTermFrameIdx equal to long_term_frame_idx is
752             // already assigned to a long-term reference frame or a long-term
753             // complementary reference field pair, that frame or complementary
754             // field pair and both of its fields are marked as "unused for
755             // reference". When LongTermFrameIdx is already assigned to a
756             // reference field, and that reference field is not part of a
757             // complementary field pair that includes the current picture, that
758             // field is marked as "unused for reference".
759             if matches!(dpb_pic.reference(), Reference::LongTerm)
760                 && dpb_pic.long_term_frame_idx == long_term_frame_idx
761             {
762                 let is_frame = matches!(dpb_pic.field, Field::Frame);
763 
764                 let is_complementary_ref_field_pair = dpb_pic
765                     .other_field()
766                     .map(|f| {
767                         let pic = f.borrow();
768                         matches!(pic.reference(), Reference::LongTerm)
769                             && pic.long_term_frame_idx == long_term_frame_idx
770                     })
771                     .unwrap_or(false);
772 
773                 dpb_pic.set_reference(Reference::None, is_frame || is_complementary_ref_field_pair);
774 
775                 break;
776             }
777         }
778 
779         let is_frame = matches!(pic.field, Field::Frame);
780 
781         let is_second_ref_field = match pic.field_rank() {
782             FieldRank::Second(first_field)
783                 if *first_field.borrow().reference() == Reference::LongTerm =>
784             {
785                 first_field.borrow_mut().long_term_frame_idx = long_term_frame_idx;
786                 true
787             }
788             _ => false,
789         };
790 
791         pic.set_reference(Reference::LongTerm, is_frame || is_second_ref_field);
792         pic.long_term_frame_idx = long_term_frame_idx;
793     }
794 
795     #[cfg(debug_assertions)]
debug_ref_list_p(ref_pic_list: &[&DpbEntry<T>], field_pic: bool)796     fn debug_ref_list_p(ref_pic_list: &[&DpbEntry<T>], field_pic: bool) {
797         debug!(
798             "ref_list_p0: (ShortTerm|LongTerm, pic_num) {:?}",
799             ref_pic_list
800                 .iter()
801                 .map(|h| {
802                     let p = h.pic.borrow();
803                     let reference = match p.reference() {
804                         Reference::None => panic!("Not a reference."),
805                         Reference::ShortTerm => "ShortTerm",
806                         Reference::LongTerm => "LongTerm",
807                     };
808 
809                     let field = if !p.is_second_field() { "First field" } else { "Second field" };
810 
811                     let field = format!("{}, {:?}", field, p.field);
812 
813                     let inner = match (field_pic, p.reference()) {
814                         (false, _) => ("pic_num", p.pic_num, field),
815                         (true, Reference::ShortTerm) => ("frame_num_wrap", p.frame_num_wrap, field),
816                         (true, Reference::LongTerm) => {
817                             ("long_term_frame_idx", p.long_term_frame_idx as i32, field)
818                         }
819 
820                         _ => panic!("Not a reference."),
821                     };
822                     (reference, inner)
823                 })
824                 .collect::<Vec<_>>()
825         );
826     }
827 
828     #[cfg(debug_assertions)]
debug_ref_list_b(ref_pic_list: &[&DpbEntry<T>], ref_pic_list_name: &str)829     fn debug_ref_list_b(ref_pic_list: &[&DpbEntry<T>], ref_pic_list_name: &str) {
830         debug!(
831             "{:?}: (ShortTerm|LongTerm, (POC|LongTermPicNum)) {:?}",
832             ref_pic_list_name,
833             ref_pic_list
834                 .iter()
835                 .map(|h| {
836                     let p = h.pic.borrow();
837                     let reference = match p.reference() {
838                         Reference::None => panic!("Not a reference."),
839                         Reference::ShortTerm => "ShortTerm",
840                         Reference::LongTerm => "LongTerm",
841                     };
842 
843                     let field = if !p.is_second_field() { "First field" } else { "Second field" };
844 
845                     let field = format!("{}, {:?}", field, p.field);
846 
847                     let inner = match p.reference() {
848                         Reference::ShortTerm => ("POC", p.pic_order_cnt, field),
849                         Reference::LongTerm => {
850                             ("LongTermPicNum", p.long_term_pic_num as i32, field)
851                         }
852                         _ => panic!("Not a reference!"),
853                     };
854                     (reference, inner)
855                 })
856                 .collect::<Vec<_>>()
857         );
858     }
859 
sort_pic_num_descending(pics: &mut [&DpbEntry<T>])860     fn sort_pic_num_descending(pics: &mut [&DpbEntry<T>]) {
861         pics.sort_by_key(|h| std::cmp::Reverse(h.pic.borrow().pic_num));
862     }
863 
sort_frame_num_wrap_descending(pics: &mut [&DpbEntry<T>])864     fn sort_frame_num_wrap_descending(pics: &mut [&DpbEntry<T>]) {
865         pics.sort_by_key(|h| std::cmp::Reverse(h.pic.borrow().frame_num_wrap));
866     }
867 
sort_long_term_pic_num_ascending(pics: &mut [&DpbEntry<T>])868     fn sort_long_term_pic_num_ascending(pics: &mut [&DpbEntry<T>]) {
869         pics.sort_by_key(|h| h.pic.borrow().long_term_pic_num);
870     }
871 
sort_long_term_frame_idx_ascending(pics: &mut [&DpbEntry<T>])872     fn sort_long_term_frame_idx_ascending(pics: &mut [&DpbEntry<T>]) {
873         pics.sort_by_key(|h| h.pic.borrow().long_term_frame_idx);
874     }
875 
sort_poc_descending(pics: &mut [&DpbEntry<T>])876     fn sort_poc_descending(pics: &mut [&DpbEntry<T>]) {
877         pics.sort_by_key(|h| std::cmp::Reverse(h.pic.borrow().pic_order_cnt));
878     }
879 
sort_poc_ascending(pics: &mut [&DpbEntry<T>])880     fn sort_poc_ascending(pics: &mut [&DpbEntry<T>]) {
881         pics.sort_by_key(|h| h.pic.borrow().pic_order_cnt);
882     }
883 
884     // When the reference picture list RefPicList1 has more than one entry
885     // and RefPicList1 is identical to the reference picture list
886     // RefPicList0, the first two entries RefPicList1[0] and RefPicList1[1]
887     // are switched.
swap_b1_if_needed(b0: &DpbPicRefList<T>, b1: &mut DpbPicRefList<T>)888     fn swap_b1_if_needed(b0: &DpbPicRefList<T>, b1: &mut DpbPicRefList<T>) {
889         if b1.len() > 1 && b0.len() == b1.len() {
890             let mut equals = true;
891             for (x1, x2) in b0.iter().zip(b1.iter()) {
892                 if !Rc::ptr_eq(&x1.pic, &x2.pic) {
893                     equals = false;
894                     break;
895                 }
896             }
897 
898             if equals {
899                 b1.swap(0, 1);
900             }
901         }
902     }
903 
904     /// Copies from refFrameList(XShort|Long)Term into RefPicListX as per 8.2.4.2.5. Used when
905     /// building the reference list for fields in interlaced decoding.
init_ref_field_pic_list<'a>( mut field: Field, reference_type: Reference, ref_frame_list: &mut DpbPicRefList<'a, T>, ref_pic_list: &mut DpbPicRefList<'a, T>, )906     fn init_ref_field_pic_list<'a>(
907         mut field: Field,
908         reference_type: Reference,
909         ref_frame_list: &mut DpbPicRefList<'a, T>,
910         ref_pic_list: &mut DpbPicRefList<'a, T>,
911     ) {
912         // When one field of a reference frame was not decoded or is not marked as "used for
913         // (short|long)-term reference", the missing field is ignored and instead the next
914         // available stored reference field of the chosen parity from the ordered list of frames
915         // refFrameListX(Short|Long)Term is inserted into RefPicListX.
916         ref_frame_list.retain(|h| {
917             let p = h.pic.borrow();
918             let skip = p.nonexisting || *p.reference() != reference_type;
919             !skip
920         });
921 
922         while let Some(position) = ref_frame_list.iter().position(|h| {
923             let p = h.pic.borrow();
924             let found = p.field == field;
925 
926             if found {
927                 field = field.opposite();
928             }
929 
930             found
931         }) {
932             let pic = ref_frame_list.remove(position);
933             ref_pic_list.push(pic);
934         }
935 
936         ref_pic_list.append(ref_frame_list);
937     }
938 
939     /// 8.2.4.2.1 Initialization process for the reference picture list for P
940     /// and SP slices in frames
build_ref_pic_list_p(&self) -> DpbPicRefList<T>941     fn build_ref_pic_list_p(&self) -> DpbPicRefList<T> {
942         let mut ref_pic_list_p0: Vec<_> =
943             self.short_term_refs_iter().filter(|h| !h.pic.borrow().is_second_field()).collect();
944 
945         Self::sort_pic_num_descending(&mut ref_pic_list_p0);
946 
947         let num_short_term_refs = ref_pic_list_p0.len();
948 
949         ref_pic_list_p0
950             .extend(self.long_term_refs_iter().filter(|h| !h.pic.borrow().is_second_field()));
951         Self::sort_long_term_pic_num_ascending(&mut ref_pic_list_p0[num_short_term_refs..]);
952 
953         #[cfg(debug_assertions)]
954         Self::debug_ref_list_p(&ref_pic_list_p0, false);
955 
956         ref_pic_list_p0
957     }
958 
959     /// 8.2.4.2.2 Initialization process for the reference picture list for P
960     /// and SP slices in fields
build_ref_field_pic_list_p(&self, cur_pic: &PictureData) -> DpbPicRefList<T>961     fn build_ref_field_pic_list_p(&self, cur_pic: &PictureData) -> DpbPicRefList<T> {
962         let mut ref_pic_list_p0 = vec![];
963 
964         let mut ref_frame_list_0_short_term: Vec<_> = self.short_term_refs_iter().collect();
965         Self::sort_frame_num_wrap_descending(&mut ref_frame_list_0_short_term);
966 
967         let mut ref_frame_list_long_term: Vec<_> = self.long_term_refs_iter().collect();
968         Self::sort_long_term_pic_num_ascending(&mut ref_frame_list_long_term);
969 
970         // 8.2.4.2.5
971         Self::init_ref_field_pic_list(
972             cur_pic.field,
973             Reference::ShortTerm,
974             &mut ref_frame_list_0_short_term,
975             &mut ref_pic_list_p0,
976         );
977         Self::init_ref_field_pic_list(
978             cur_pic.field,
979             Reference::LongTerm,
980             &mut ref_frame_list_long_term,
981             &mut ref_pic_list_p0,
982         );
983 
984         #[cfg(debug_assertions)]
985         Self::debug_ref_list_p(&ref_pic_list_p0, true);
986 
987         ref_pic_list_p0
988     }
989 
990     // 8.2.4.2.3 Initialization process for reference picture lists for B slices
991     // in frames
build_ref_pic_list_b(&self, cur_pic: &PictureData) -> (DpbPicRefList<T>, DpbPicRefList<T>)992     fn build_ref_pic_list_b(&self, cur_pic: &PictureData) -> (DpbPicRefList<T>, DpbPicRefList<T>) {
993         let mut short_term_refs: Vec<_> =
994             self.short_term_refs_iter().filter(|h| !h.pic.borrow().is_second_field()).collect();
995 
996         // When pic_order_cnt_type is equal to 0, reference pictures that are
997         // marked as "non-existing" as specified in clause 8.2.5.2 are not
998         // included in either RefPicList0 or RefPicList1.
999         if cur_pic.pic_order_cnt_type == 0 {
1000             short_term_refs.retain(|h| !h.pic.borrow().nonexisting);
1001         }
1002 
1003         let mut ref_pic_list_b0 = vec![];
1004         let mut ref_pic_list_b1 = vec![];
1005         let mut remaining = vec![];
1006         // b0 contains three inner lists of pictures, i.e. [[0] [1] [2]]
1007         // [0]: short term pictures with POC < current, sorted by descending POC.
1008         // [1]: short term pictures with POC > current, sorted by ascending POC.
1009         // [2]: long term pictures sorted by ascending long_term_pic_num
1010         for &handle in &short_term_refs {
1011             let pic = handle.pic.borrow();
1012 
1013             if pic.pic_order_cnt < cur_pic.pic_order_cnt {
1014                 ref_pic_list_b0.push(handle);
1015             } else {
1016                 remaining.push(handle);
1017             }
1018         }
1019 
1020         Self::sort_poc_descending(&mut ref_pic_list_b0);
1021         Self::sort_poc_ascending(&mut remaining);
1022         ref_pic_list_b0.append(&mut remaining);
1023 
1024         let mut long_term_refs: Vec<_> = self
1025             .long_term_refs_iter()
1026             .filter(|h| !h.pic.borrow().nonexisting)
1027             .filter(|h| !h.pic.borrow().is_second_field())
1028             .collect();
1029         Self::sort_long_term_pic_num_ascending(&mut long_term_refs);
1030 
1031         ref_pic_list_b0.extend(long_term_refs.clone());
1032 
1033         // b1 contains three inner lists of pictures, i.e. [[0] [1] [2]]
1034         // [0]: short term pictures with POC > current, sorted by ascending POC.
1035         // [1]: short term pictures with POC < current, sorted by descending POC.
1036         // [2]: long term pictures sorted by ascending long_term_pic_num
1037         for &handle in &short_term_refs {
1038             let pic = handle.pic.borrow();
1039 
1040             if pic.pic_order_cnt > cur_pic.pic_order_cnt {
1041                 ref_pic_list_b1.push(handle);
1042             } else {
1043                 remaining.push(handle);
1044             }
1045         }
1046 
1047         Self::sort_poc_ascending(&mut ref_pic_list_b1);
1048         Self::sort_poc_descending(&mut remaining);
1049 
1050         ref_pic_list_b1.extend(remaining);
1051         ref_pic_list_b1.extend(long_term_refs);
1052 
1053         // When the reference picture list RefPicList1 has more than one entry
1054         // and RefPicList1 is identical to the reference picture list
1055         // RefPicList0, the first two entries RefPicList1[0] and RefPicList1[1]
1056         // are switched.
1057         Self::swap_b1_if_needed(&ref_pic_list_b0, &mut ref_pic_list_b1);
1058 
1059         #[cfg(debug_assertions)]
1060         Self::debug_ref_list_b(&ref_pic_list_b0, "ref_pic_list_b0");
1061         #[cfg(debug_assertions)]
1062         Self::debug_ref_list_b(&ref_pic_list_b1, "ref_pic_list_b1");
1063 
1064         (ref_pic_list_b0, ref_pic_list_b1)
1065     }
1066 
1067     /// 8.2.4.2.4 Initialization process for reference picture lists for B
1068     /// slices in fields
build_ref_field_pic_list_b( &self, cur_pic: &PictureData, ) -> (DpbPicRefList<T>, DpbPicRefList<T>)1069     fn build_ref_field_pic_list_b(
1070         &self,
1071         cur_pic: &PictureData,
1072     ) -> (DpbPicRefList<T>, DpbPicRefList<T>) {
1073         let mut ref_pic_list_b0 = vec![];
1074         let mut ref_pic_list_b1 = vec![];
1075         let mut ref_frame_list_0_short_term = vec![];
1076         let mut ref_frame_list_1_short_term = vec![];
1077 
1078         let mut remaining = vec![];
1079 
1080         let mut short_term_refs: Vec<_> = self.short_term_refs_iter().collect();
1081 
1082         // When pic_order_cnt_type is equal to 0, reference pictures that are
1083         // marked as "non-existing" as specified in clause 8.2.5.2 are not
1084         // included in either RefPicList0 or RefPicList1.
1085         if cur_pic.pic_order_cnt_type == 0 {
1086             short_term_refs.retain(|h| !h.pic.borrow().nonexisting);
1087         }
1088 
1089         // refFrameList0ShortTerm is comprised of two inner lists, [[0] [1]]
1090         // [0]: short term pictures with POC <= current, sorted by descending POC
1091         // [1]: short term pictures with POC > current, sorted by ascending POC
1092         // NOTE 3 – When the current field follows in decoding order a coded
1093         // field fldPrev with which together it forms a complementary reference
1094         // field pair, fldPrev is included into the list refFrameList0ShortTerm
1095         // using PicOrderCnt( fldPrev ) and the ordering method described in the
1096         // previous sentence is applied.
1097         for &handle in &short_term_refs {
1098             let pic = handle.pic.borrow();
1099 
1100             if pic.pic_order_cnt <= cur_pic.pic_order_cnt {
1101                 ref_frame_list_0_short_term.push(handle);
1102             } else {
1103                 remaining.push(handle);
1104             }
1105         }
1106 
1107         Self::sort_poc_descending(&mut ref_frame_list_0_short_term);
1108         Self::sort_poc_ascending(&mut remaining);
1109         ref_frame_list_0_short_term.append(&mut remaining);
1110 
1111         // refFrameList1ShortTerm is comprised of two inner lists, [[0] [1]]
1112         // [0]: short term pictures with POC > current, sorted by ascending POC
1113         // [1]: short term pictures with POC <= current, sorted by descending POC
1114         // NOTE 4 – When the current field follows in decoding order a coded
1115         // field fldPrev with which together it forms a complementary reference
1116         // field pair, fldPrev is included into the list refFrameList1ShortTerm
1117         // using PicOrderCnt( fldPrev ) and the ordering method described in the
1118         // previous sentence is applied.
1119 
1120         for &handle in &short_term_refs {
1121             let pic = handle.pic.borrow();
1122 
1123             if pic.pic_order_cnt > cur_pic.pic_order_cnt {
1124                 ref_frame_list_1_short_term.push(handle);
1125             } else {
1126                 remaining.push(handle);
1127             }
1128         }
1129 
1130         Self::sort_poc_ascending(&mut ref_frame_list_1_short_term);
1131         Self::sort_poc_descending(&mut remaining);
1132         ref_frame_list_1_short_term.append(&mut remaining);
1133 
1134         // refFrameListLongTerm: long term pictures sorted by ascending
1135         // LongTermFrameIdx.
1136         // NOTE 5 – When the current picture is the second field of a
1137         // complementary field pair and the first field of the complementary
1138         // field pair is marked as "used for long-term reference", the first
1139         // field is included into the list refFrameListLongTerm. A reference
1140         // entry in which only one field is marked as "used for long-term
1141         // reference" is included into the list refFrameListLongTerm
1142         let mut ref_frame_list_long_term: Vec<_> =
1143             self.long_term_refs_iter().filter(|h| !h.pic.borrow().nonexisting).collect();
1144 
1145         Self::sort_long_term_frame_idx_ascending(&mut ref_frame_list_long_term);
1146 
1147         #[cfg(debug_assertions)]
1148         Self::debug_ref_list_b(&ref_frame_list_0_short_term, "ref_frame_list_0_short_term");
1149         #[cfg(debug_assertions)]
1150         Self::debug_ref_list_b(&ref_frame_list_1_short_term, "ref_frame_list_1_short_term");
1151         #[cfg(debug_assertions)]
1152         Self::debug_ref_list_b(&ref_frame_list_long_term, "ref_frame_list_long_term");
1153 
1154         // 8.2.4.2.5
1155         let field = cur_pic.field;
1156         Self::init_ref_field_pic_list(
1157             field,
1158             Reference::ShortTerm,
1159             &mut ref_frame_list_0_short_term,
1160             &mut ref_pic_list_b0,
1161         );
1162         Self::init_ref_field_pic_list(
1163             field,
1164             Reference::LongTerm,
1165             &mut ref_frame_list_long_term,
1166             &mut ref_pic_list_b0,
1167         );
1168 
1169         Self::init_ref_field_pic_list(
1170             field,
1171             Reference::ShortTerm,
1172             &mut ref_frame_list_1_short_term,
1173             &mut ref_pic_list_b1,
1174         );
1175         Self::init_ref_field_pic_list(
1176             field,
1177             Reference::LongTerm,
1178             &mut ref_frame_list_long_term,
1179             &mut ref_pic_list_b1,
1180         );
1181 
1182         // When the reference picture list RefPicList1 has more than one entry
1183         // and RefPicList1 is identical to the reference picture list
1184         // RefPicList0, the first two entries RefPicList1[0] and RefPicList1[1]
1185         // are switched.
1186         Self::swap_b1_if_needed(&ref_pic_list_b0, &mut ref_pic_list_b1);
1187 
1188         #[cfg(debug_assertions)]
1189         Self::debug_ref_list_b(&ref_pic_list_b0, "ref_pic_list_b0");
1190         #[cfg(debug_assertions)]
1191         Self::debug_ref_list_b(&ref_pic_list_b1, "ref_pic_list_b1");
1192 
1193         (ref_pic_list_b0, ref_pic_list_b1)
1194     }
1195 
1196     /// Returns the lists of reference pictures for `pic`.
build_ref_pic_lists(&self, pic: &PictureData) -> ReferencePicLists1197     pub fn build_ref_pic_lists(&self, pic: &PictureData) -> ReferencePicLists {
1198         let num_refs = self.pictures().filter(|p| p.is_ref() && !p.nonexisting).count();
1199 
1200         // 8.2.4.2.1 ~ 8.2.4.2.4: When this process is invoked, there shall be
1201         // at least one reference frame or complementary reference field pair
1202         // that is currently marked as "used for reference" (i.e., as "used for
1203         // short-term reference" or "used for long-term reference") and is not
1204         // marked as "non-existing".
1205         if num_refs == 0 {
1206             return Default::default();
1207         }
1208 
1209         let (ref_pic_list_p0, (ref_pic_list_b0, ref_pic_list_b1)) =
1210             if matches!(pic.field, Field::Frame) {
1211                 (self.build_ref_pic_list_p(), self.build_ref_pic_list_b(pic))
1212             } else {
1213                 (self.build_ref_field_pic_list_p(pic), self.build_ref_field_pic_list_b(pic))
1214             };
1215 
1216         let dpb_start = self.entries.as_ptr();
1217         let refs_to_index = |refs: Vec<_>| {
1218             refs.into_iter()
1219                 .map(|r| r as *const DpbEntry<T>)
1220                 .map(|r| unsafe { r.offset_from(dpb_start) })
1221                 .map(|i| i as usize)
1222                 .collect()
1223         };
1224 
1225         ReferencePicLists {
1226             ref_pic_list_p0: refs_to_index(ref_pic_list_p0),
1227             ref_pic_list_b0: refs_to_index(ref_pic_list_b0),
1228             ref_pic_list_b1: refs_to_index(ref_pic_list_b1),
1229         }
1230     }
1231 }
1232 
1233 impl<T> Default for Dpb<T> {
default() -> Self1234     fn default() -> Self {
1235         // See https://github.com/rust-lang/rust/issues/26925 on why this can't
1236         // be derived.
1237         Self {
1238             entries: Default::default(),
1239             max_num_pics: Default::default(),
1240             max_num_reorder_frames: Default::default(),
1241             interlaced: Default::default(),
1242         }
1243     }
1244 }
1245 
1246 impl<T> std::fmt::Debug for Dpb<T> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result1247     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1248         let pics = self.entries.iter().map(|h| &h.pic).enumerate().collect::<Vec<_>>();
1249         f.debug_struct("Dpb")
1250             .field("pictures", &pics)
1251             .field("max_num_pics", &self.max_num_pics)
1252             .field("interlaced", &self.interlaced)
1253             .finish()
1254     }
1255 }
1256