cros_codecs/codec/h264/
dpb.rs

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
5use std::cell::Ref;
6use std::cell::RefMut;
7use std::fmt;
8use std::rc::Rc;
9
10use log::debug;
11
12use crate::codec::h264::parser::MaxLongTermFrameIdx;
13use crate::codec::h264::parser::RefPicMarkingInner;
14use crate::codec::h264::parser::Sps;
15use crate::codec::h264::picture::Field;
16use crate::codec::h264::picture::FieldRank;
17use crate::codec::h264::picture::IsIdr;
18use crate::codec::h264::picture::PictureData;
19use crate::codec::h264::picture::RcPictureData;
20use crate::codec::h264::picture::Reference;
21
22pub type DpbPicRefList<'a, H> = Vec<&'a DpbEntry<H>>;
23
24/// All the reference picture lists used to decode a picture.
25#[derive(Default)]
26pub 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)]
43pub 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
55impl<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.
60    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
75pub 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)]
98pub enum StorePictureError {
99    DpbIsFull,
100}
101
102impl fmt::Display for StorePictureError {
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104        write!(f, "DPB is full")
105    }
106}
107
108impl std::error::Error for StorePictureError {}
109
110#[derive(Debug)]
111pub enum MmcoError {
112    NoShortTermPic,
113    ExpectedMarked,
114    ExpectedExisting,
115    UnknownMmco(u8),
116}
117
118impl fmt::Display for MmcoError {
119    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
135impl std::error::Error for MmcoError {}
136
137impl<T: Clone> Dpb<T> {
138    /// Returns an iterator over the underlying H264 pictures stored in the
139    /// DPB.
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.
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.
151    pub fn len(&self) -> usize {
152        self.entries.len()
153    }
154
155    pub fn is_empty(&self) -> bool {
156        self.len() == 0
157    }
158
159    /// Get a reference to the whole DPB entries.
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.
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.
171    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.
177    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.
182    pub fn interlaced(&self) -> bool {
183        self.interlaced
184    }
185
186    /// Set the dpb's interlaced mode.
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.
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.
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
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.
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.
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.
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.
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.
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.
311    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.
329    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.
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.
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.
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.
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.
425    pub fn clear(&mut self) {
426        debug!("Clearing the DPB");
427
428        let max_num_pics = self.max_num_pics;
429        let interlaced = self.interlaced;
430
431        *self = Default::default();
432
433        self.max_num_pics = max_num_pics;
434        self.interlaced = interlaced;
435    }
436
437    /// Returns an iterator of short term refs.
438    pub fn short_term_refs_iter(&self) -> impl Iterator<Item = &DpbEntry<T>> {
439        self.entries
440            .iter()
441            .filter(|&handle| matches!(handle.pic.borrow().reference(), Reference::ShortTerm))
442    }
443
444    /// Returns an iterator of long term refs.
445    pub fn long_term_refs_iter(&self) -> impl Iterator<Item = &DpbEntry<T>> {
446        self.entries
447            .iter()
448            .filter(|&handle| matches!(handle.pic.borrow().reference(), Reference::LongTerm))
449    }
450
451    pub fn update_pic_nums(
452        &mut self,
453        frame_num: u32,
454        max_frame_num: u32,
455        current_pic: &PictureData,
456    ) {
457        for mut pic in self.pictures_mut() {
458            if !pic.is_ref() {
459                continue;
460            }
461
462            if *pic.reference() == Reference::LongTerm {
463                pic.long_term_pic_num = if current_pic.field == Field::Frame {
464                    pic.long_term_frame_idx
465                } else if current_pic.field == pic.field {
466                    2 * pic.long_term_frame_idx + 1
467                } else {
468                    2 * pic.long_term_frame_idx
469                };
470            } else {
471                pic.frame_num_wrap = if pic.frame_num > frame_num {
472                    pic.frame_num as i32 - max_frame_num as i32
473                } else {
474                    pic.frame_num as i32
475                };
476
477                pic.pic_num = if current_pic.field == Field::Frame {
478                    pic.frame_num_wrap
479                } else if pic.field == current_pic.field {
480                    2 * pic.frame_num_wrap + 1
481                } else {
482                    2 * pic.frame_num_wrap
483                };
484            }
485        }
486    }
487
488    /// Bumps the DPB if needed. DPB bumping is described on C.4.5.3.
489    pub fn bump_as_needed(&mut self, current_pic: &PictureData) -> Vec<Option<T>> {
490        let mut pics = vec![];
491        while self.needs_bumping(current_pic) && self.len() >= self.max_num_reorder_frames {
492            match self.bump() {
493                Some(pic) => pics.push(pic),
494                None => return pics,
495            }
496            self.remove_unused();
497        }
498
499        pics
500    }
501
502    // 8.2.5.3
503    pub fn sliding_window_marking(&mut self, pic: &mut PictureData, sps: &Sps) {
504        // If the current picture is a coded field that is the second field in
505        // decoding order of a complementary reference field pair, and the first
506        // field has been marked as "used for short-term reference", the current
507        // picture and the complementary reference field pair are also marked as
508        // "used for short-term reference".
509        if let FieldRank::Second(other_field) = pic.field_rank() {
510            if matches!(other_field.borrow().reference(), Reference::ShortTerm) {
511                pic.set_reference(Reference::ShortTerm, false);
512                return;
513            }
514        }
515
516        let mut num_ref_pics = self.num_ref_frames();
517        let max_num_ref_frames = std::cmp::max(1, sps.max_num_ref_frames as usize);
518
519        if num_ref_pics < max_num_ref_frames {
520            return;
521        }
522
523        while num_ref_pics >= max_num_ref_frames {
524            if let Some(to_unmark) = self.find_short_term_lowest_frame_num_wrap() {
525                to_unmark.pic.borrow_mut().set_reference(Reference::None, true);
526                num_ref_pics -= 1;
527            } else {
528                log::warn!("could not find a ShortTerm picture to unmark in the DPB");
529                break;
530            }
531        }
532
533        self.remove_unused();
534    }
535
536    pub fn mmco_op_1(
537        &mut self,
538        pic: &PictureData,
539        marking: &RefPicMarkingInner,
540    ) -> Result<(), MmcoError> {
541        let pic_num_x = pic.pic_num - (marking.difference_of_pic_nums_minus1 as i32 + 1);
542
543        log::debug!("MMCO op 1 for pic_num_x {}", pic_num_x);
544        log::trace!("Dpb state before MMCO=1: {:#?}", self);
545
546        let to_mark =
547            self.find_short_term_with_pic_num(pic_num_x).ok_or(MmcoError::NoShortTermPic)?;
548
549        to_mark.pic.borrow_mut().set_reference(Reference::None, matches!(pic.field, Field::Frame));
550
551        Ok(())
552    }
553
554    pub fn mmco_op_2(
555        &mut self,
556        pic: &PictureData,
557        marking: &RefPicMarkingInner,
558    ) -> Result<(), MmcoError> {
559        log::debug!("MMCO op 2 for long_term_pic_num {}", marking.long_term_pic_num);
560
561        log::trace!("Dpb state before MMCO=2: {:#?}", self);
562
563        let to_mark = self
564            .find_long_term_with_long_term_pic_num(marking.long_term_pic_num)
565            .ok_or(MmcoError::NoShortTermPic)?;
566
567        to_mark.pic.borrow_mut().set_reference(Reference::None, matches!(pic.field, Field::Frame));
568
569        Ok(())
570    }
571
572    pub fn mmco_op_3(
573        &mut self,
574        pic: &PictureData,
575        marking: &RefPicMarkingInner,
576    ) -> Result<(), MmcoError> {
577        let pic_num_x = pic.pic_num - (marking.difference_of_pic_nums_minus1 as i32 + 1);
578
579        log::debug!("MMCO op 3 for pic_num_x {}", pic_num_x);
580        log::trace!("Dpb state before MMCO=3: {:#?}", self);
581
582        let to_mark_as_long_pos =
583            self.find_short_term_with_pic_num_pos(pic_num_x).ok_or(MmcoError::NoShortTermPic)?;
584        let to_mark_as_long = &self.entries[to_mark_as_long_pos].pic;
585
586        if !matches!(to_mark_as_long.borrow().reference(), Reference::ShortTerm) {
587            return Err(MmcoError::ExpectedMarked);
588        }
589
590        if to_mark_as_long.borrow().nonexisting {
591            return Err(MmcoError::ExpectedExisting);
592        }
593
594        let to_mark_as_long_ptr = to_mark_as_long.as_ptr();
595        let to_mark_as_long_other_field_ptr =
596            to_mark_as_long.borrow().other_field().map(|f| f.as_ptr());
597
598        let long_term_frame_idx = marking.long_term_frame_idx;
599
600        for mut picture in self.pictures_mut() {
601            let long_already_assigned = matches!(picture.reference(), Reference::LongTerm)
602                && picture.long_term_frame_idx == long_term_frame_idx;
603
604            if long_already_assigned {
605                let is_frame = matches!(picture.field, Field::Frame);
606
607                let is_complementary_field_pair = picture
608                    .other_field()
609                    .map(|f| {
610                        let pic = f.borrow();
611                        matches!(pic.reference(), Reference::LongTerm)
612                            && pic.long_term_frame_idx == long_term_frame_idx
613                    })
614                    .unwrap_or(false);
615
616                // When LongTermFrameIdx equal to
617                // long_term_frame_idx is already assigned to a
618                // long-term reference frame or a long-term
619                // complementary reference field pair, that frame or
620                // complementary field pair and both of its fields
621                // are marked as "unused for reference"
622                if is_frame || is_complementary_field_pair {
623                    picture.set_reference(Reference::None, true);
624                    break;
625                }
626
627                // When LongTermFrameIdx is already assigned to a
628                // reference field, and that reference field is not
629                // part of a complementary field pair that includes
630                // the picture specified by picNumX, that field is
631                // marked as "unused for reference".
632                let reference_field_is_not_part_of_pic_x = match picture.other_field() {
633                    None => true,
634                    Some(other_field) => {
635                        // Check that the fields do not reference one another.
636                        !std::ptr::eq(other_field.as_ptr(), to_mark_as_long_ptr)
637                            && to_mark_as_long_other_field_ptr
638                                .map(|p| !std::ptr::eq(p, &(*picture)))
639                                .unwrap_or(true)
640                    }
641                };
642
643                if reference_field_is_not_part_of_pic_x {
644                    picture.set_reference(Reference::None, false);
645                    break;
646                }
647            }
648        }
649
650        let is_frame = matches!(pic.field, Field::Frame);
651        let to_mark_as_long = &self.entries[to_mark_as_long_pos].pic;
652        to_mark_as_long.borrow_mut().set_reference(Reference::LongTerm, is_frame);
653        to_mark_as_long.borrow_mut().long_term_frame_idx = long_term_frame_idx;
654
655        if let Some(other_field) = to_mark_as_long.borrow().other_field() {
656            let mut other_field = other_field.borrow_mut();
657            if matches!(other_field.reference(), Reference::LongTerm) {
658                other_field.long_term_frame_idx = long_term_frame_idx;
659
660                log::debug!(
661                    "Assigned long_term_frame_idx {} to other_field {:#?}",
662                    long_term_frame_idx,
663                    &other_field
664                );
665            }
666        }
667
668        Ok(())
669    }
670
671    /// Returns the new `max_long_term_frame_idx`.
672    pub fn mmco_op_4(&mut self, marking: &RefPicMarkingInner) -> MaxLongTermFrameIdx {
673        log::debug!("MMCO op 4, max_long_term_frame_idx: {:?}", marking.max_long_term_frame_idx);
674
675        log::trace!("Dpb state before MMCO=4: {:#?}", self);
676
677        for mut dpb_pic in self
678            .pictures_mut()
679            .filter(|pic| matches!(pic.reference(), Reference::LongTerm))
680            .filter(|pic| marking.max_long_term_frame_idx < pic.long_term_frame_idx)
681        {
682            dpb_pic.set_reference(Reference::None, false);
683        }
684
685        marking.max_long_term_frame_idx
686    }
687
688    /// Returns the new `max_long_term_frame_idx`.
689    pub fn mmco_op_5(&mut self, pic: &mut PictureData) -> MaxLongTermFrameIdx {
690        log::debug!("MMCO op 5, marking all pictures in the DPB as unused for reference");
691        log::trace!("Dpb state before MMCO=5: {:#?}", self);
692
693        self.mark_all_as_unused_for_ref();
694
695        pic.has_mmco_5 = true;
696
697        // A picture including a memory_management_control_operation equal to 5
698        // shall have frame_num constraints as described above and, after the
699        // decoding of the current picture and the processing of the memory
700        // management control operations, the picture shall be inferred to have
701        // had frame_num equal to 0 for all subsequent use in the decoding
702        // process, except as specified in clause 7.4.1.2.4.
703        pic.frame_num = 0;
704
705        // When the current picture includes a
706        // memory_management_control_operation equal to 5, after the decoding of
707        // the current picture, tempPicOrderCnt is set equal to PicOrderCnt(
708        // CurrPic ), TopFieldOrderCnt of the current picture (if any) is set
709        // equal to TopFieldOrderCnt − tempPicOrderCnt, and BottomFieldOrderCnt
710        // of the current picture (if any) is set equal to BottomFieldOrderCnt −
711        // tempPicOrderCnt
712        match pic.field {
713            Field::Top => {
714                pic.top_field_order_cnt = 0;
715                pic.pic_order_cnt = 0;
716            }
717            Field::Bottom => {
718                pic.bottom_field_order_cnt = 0;
719                pic.pic_order_cnt = 0;
720            }
721            Field::Frame => {
722                pic.top_field_order_cnt -= pic.pic_order_cnt;
723                pic.bottom_field_order_cnt -= pic.pic_order_cnt;
724                pic.pic_order_cnt =
725                    std::cmp::min(pic.top_field_order_cnt, pic.bottom_field_order_cnt);
726            }
727        }
728
729        MaxLongTermFrameIdx::NoLongTermFrameIndices
730    }
731
732    pub fn mmco_op_6(&mut self, pic: &mut PictureData, marking: &RefPicMarkingInner) {
733        let long_term_frame_idx = marking.long_term_frame_idx;
734
735        log::debug!("MMCO op 6, long_term_frame_idx: {}", long_term_frame_idx);
736        log::trace!("Dpb state before MMCO=6: {:#?}", self);
737
738        for mut dpb_pic in self.pictures_mut() {
739            // When a variable LongTermFrameIdx equal to long_term_frame_idx is
740            // already assigned to a long-term reference frame or a long-term
741            // complementary reference field pair, that frame or complementary
742            // field pair and both of its fields are marked as "unused for
743            // reference". When LongTermFrameIdx is already assigned to a
744            // reference field, and that reference field is not part of a
745            // complementary field pair that includes the current picture, that
746            // field is marked as "unused for reference".
747            if matches!(dpb_pic.reference(), Reference::LongTerm)
748                && dpb_pic.long_term_frame_idx == long_term_frame_idx
749            {
750                let is_frame = matches!(dpb_pic.field, Field::Frame);
751
752                let is_complementary_ref_field_pair = dpb_pic
753                    .other_field()
754                    .map(|f| {
755                        let pic = f.borrow();
756                        matches!(pic.reference(), Reference::LongTerm)
757                            && pic.long_term_frame_idx == long_term_frame_idx
758                    })
759                    .unwrap_or(false);
760
761                dpb_pic.set_reference(Reference::None, is_frame || is_complementary_ref_field_pair);
762
763                break;
764            }
765        }
766
767        let is_frame = matches!(pic.field, Field::Frame);
768
769        let is_second_ref_field = match pic.field_rank() {
770            FieldRank::Second(first_field)
771                if *first_field.borrow().reference() == Reference::LongTerm =>
772            {
773                first_field.borrow_mut().long_term_frame_idx = long_term_frame_idx;
774                true
775            }
776            _ => false,
777        };
778
779        pic.set_reference(Reference::LongTerm, is_frame || is_second_ref_field);
780        pic.long_term_frame_idx = long_term_frame_idx;
781    }
782
783    #[cfg(debug_assertions)]
784    fn debug_ref_list_p(ref_pic_list: &[&DpbEntry<T>], field_pic: bool) {
785        debug!(
786            "ref_list_p0: (ShortTerm|LongTerm, pic_num) {:?}",
787            ref_pic_list
788                .iter()
789                .map(|h| {
790                    let p = h.pic.borrow();
791                    let reference = match p.reference() {
792                        Reference::None => panic!("Not a reference."),
793                        Reference::ShortTerm => "ShortTerm",
794                        Reference::LongTerm => "LongTerm",
795                    };
796
797                    let field = if !p.is_second_field() { "First field" } else { "Second field" };
798
799                    let field = format!("{}, {:?}", field, p.field);
800
801                    let inner = match (field_pic, p.reference()) {
802                        (false, _) => ("pic_num", p.pic_num, field),
803                        (true, Reference::ShortTerm) => ("frame_num_wrap", p.frame_num_wrap, field),
804                        (true, Reference::LongTerm) => {
805                            ("long_term_frame_idx", p.long_term_frame_idx as i32, field)
806                        }
807
808                        _ => panic!("Not a reference."),
809                    };
810                    (reference, inner)
811                })
812                .collect::<Vec<_>>()
813        );
814    }
815
816    #[cfg(debug_assertions)]
817    fn debug_ref_list_b(ref_pic_list: &[&DpbEntry<T>], ref_pic_list_name: &str) {
818        debug!(
819            "{:?}: (ShortTerm|LongTerm, (POC|LongTermPicNum)) {:?}",
820            ref_pic_list_name,
821            ref_pic_list
822                .iter()
823                .map(|h| {
824                    let p = h.pic.borrow();
825                    let reference = match p.reference() {
826                        Reference::None => panic!("Not a reference."),
827                        Reference::ShortTerm => "ShortTerm",
828                        Reference::LongTerm => "LongTerm",
829                    };
830
831                    let field = if !p.is_second_field() { "First field" } else { "Second field" };
832
833                    let field = format!("{}, {:?}", field, p.field);
834
835                    let inner = match p.reference() {
836                        Reference::ShortTerm => ("POC", p.pic_order_cnt, field),
837                        Reference::LongTerm => {
838                            ("LongTermPicNum", p.long_term_pic_num as i32, field)
839                        }
840                        _ => panic!("Not a reference!"),
841                    };
842                    (reference, inner)
843                })
844                .collect::<Vec<_>>()
845        );
846    }
847
848    fn sort_pic_num_descending(pics: &mut [&DpbEntry<T>]) {
849        pics.sort_by_key(|h| std::cmp::Reverse(h.pic.borrow().pic_num));
850    }
851
852    fn sort_frame_num_wrap_descending(pics: &mut [&DpbEntry<T>]) {
853        pics.sort_by_key(|h| std::cmp::Reverse(h.pic.borrow().frame_num_wrap));
854    }
855
856    fn sort_long_term_pic_num_ascending(pics: &mut [&DpbEntry<T>]) {
857        pics.sort_by_key(|h| h.pic.borrow().long_term_pic_num);
858    }
859
860    fn sort_long_term_frame_idx_ascending(pics: &mut [&DpbEntry<T>]) {
861        pics.sort_by_key(|h| h.pic.borrow().long_term_frame_idx);
862    }
863
864    fn sort_poc_descending(pics: &mut [&DpbEntry<T>]) {
865        pics.sort_by_key(|h| std::cmp::Reverse(h.pic.borrow().pic_order_cnt));
866    }
867
868    fn sort_poc_ascending(pics: &mut [&DpbEntry<T>]) {
869        pics.sort_by_key(|h| h.pic.borrow().pic_order_cnt);
870    }
871
872    // When the reference picture list RefPicList1 has more than one entry
873    // and RefPicList1 is identical to the reference picture list
874    // RefPicList0, the first two entries RefPicList1[0] and RefPicList1[1]
875    // are switched.
876    fn swap_b1_if_needed(b0: &DpbPicRefList<T>, b1: &mut DpbPicRefList<T>) {
877        if b1.len() > 1 && b0.len() == b1.len() {
878            let mut equals = true;
879            for (x1, x2) in b0.iter().zip(b1.iter()) {
880                if !Rc::ptr_eq(&x1.pic, &x2.pic) {
881                    equals = false;
882                    break;
883                }
884            }
885
886            if equals {
887                b1.swap(0, 1);
888            }
889        }
890    }
891
892    /// Copies from refFrameList(XShort|Long)Term into RefPicListX as per 8.2.4.2.5. Used when
893    /// building the reference list for fields in interlaced decoding.
894    fn init_ref_field_pic_list<'a>(
895        mut field: Field,
896        reference_type: Reference,
897        ref_frame_list: &mut DpbPicRefList<'a, T>,
898        ref_pic_list: &mut DpbPicRefList<'a, T>,
899    ) {
900        // When one field of a reference frame was not decoded or is not marked as "used for
901        // (short|long)-term reference", the missing field is ignored and instead the next
902        // available stored reference field of the chosen parity from the ordered list of frames
903        // refFrameListX(Short|Long)Term is inserted into RefPicListX.
904        ref_frame_list.retain(|h| {
905            let p = h.pic.borrow();
906            let skip = p.nonexisting || *p.reference() != reference_type;
907            !skip
908        });
909
910        while let Some(position) = ref_frame_list.iter().position(|h| {
911            let p = h.pic.borrow();
912            let found = p.field == field;
913
914            if found {
915                field = field.opposite();
916            }
917
918            found
919        }) {
920            let pic = ref_frame_list.remove(position);
921            ref_pic_list.push(pic);
922        }
923
924        ref_pic_list.append(ref_frame_list);
925    }
926
927    /// 8.2.4.2.1 Initialization process for the reference picture list for P
928    /// and SP slices in frames
929    fn build_ref_pic_list_p(&self) -> DpbPicRefList<T> {
930        let mut ref_pic_list_p0: Vec<_> =
931            self.short_term_refs_iter().filter(|h| !h.pic.borrow().is_second_field()).collect();
932
933        Self::sort_pic_num_descending(&mut ref_pic_list_p0);
934
935        let num_short_term_refs = ref_pic_list_p0.len();
936
937        ref_pic_list_p0
938            .extend(self.long_term_refs_iter().filter(|h| !h.pic.borrow().is_second_field()));
939        Self::sort_long_term_pic_num_ascending(&mut ref_pic_list_p0[num_short_term_refs..]);
940
941        #[cfg(debug_assertions)]
942        Self::debug_ref_list_p(&ref_pic_list_p0, false);
943
944        ref_pic_list_p0
945    }
946
947    /// 8.2.4.2.2 Initialization process for the reference picture list for P
948    /// and SP slices in fields
949    fn build_ref_field_pic_list_p(&self, cur_pic: &PictureData) -> DpbPicRefList<T> {
950        let mut ref_pic_list_p0 = vec![];
951
952        let mut ref_frame_list_0_short_term: Vec<_> = self.short_term_refs_iter().collect();
953        Self::sort_frame_num_wrap_descending(&mut ref_frame_list_0_short_term);
954
955        let mut ref_frame_list_long_term: Vec<_> = self.long_term_refs_iter().collect();
956        Self::sort_long_term_pic_num_ascending(&mut ref_frame_list_long_term);
957
958        // 8.2.4.2.5
959        Self::init_ref_field_pic_list(
960            cur_pic.field,
961            Reference::ShortTerm,
962            &mut ref_frame_list_0_short_term,
963            &mut ref_pic_list_p0,
964        );
965        Self::init_ref_field_pic_list(
966            cur_pic.field,
967            Reference::LongTerm,
968            &mut ref_frame_list_long_term,
969            &mut ref_pic_list_p0,
970        );
971
972        #[cfg(debug_assertions)]
973        Self::debug_ref_list_p(&ref_pic_list_p0, true);
974
975        ref_pic_list_p0
976    }
977
978    // 8.2.4.2.3 Initialization process for reference picture lists for B slices
979    // in frames
980    fn build_ref_pic_list_b(&self, cur_pic: &PictureData) -> (DpbPicRefList<T>, DpbPicRefList<T>) {
981        let mut short_term_refs: Vec<_> =
982            self.short_term_refs_iter().filter(|h| !h.pic.borrow().is_second_field()).collect();
983
984        // When pic_order_cnt_type is equal to 0, reference pictures that are
985        // marked as "non-existing" as specified in clause 8.2.5.2 are not
986        // included in either RefPicList0 or RefPicList1.
987        if cur_pic.pic_order_cnt_type == 0 {
988            short_term_refs.retain(|h| !h.pic.borrow().nonexisting);
989        }
990
991        let mut ref_pic_list_b0 = vec![];
992        let mut ref_pic_list_b1 = vec![];
993        let mut remaining = vec![];
994        // b0 contains three inner lists of pictures, i.e. [[0] [1] [2]]
995        // [0]: short term pictures with POC < current, sorted by descending POC.
996        // [1]: short term pictures with POC > current, sorted by ascending POC.
997        // [2]: long term pictures sorted by ascending long_term_pic_num
998        for &handle in &short_term_refs {
999            let pic = handle.pic.borrow();
1000
1001            if pic.pic_order_cnt < cur_pic.pic_order_cnt {
1002                ref_pic_list_b0.push(handle);
1003            } else {
1004                remaining.push(handle);
1005            }
1006        }
1007
1008        Self::sort_poc_descending(&mut ref_pic_list_b0);
1009        Self::sort_poc_ascending(&mut remaining);
1010        ref_pic_list_b0.append(&mut remaining);
1011
1012        let mut long_term_refs: Vec<_> = self
1013            .long_term_refs_iter()
1014            .filter(|h| !h.pic.borrow().nonexisting)
1015            .filter(|h| !h.pic.borrow().is_second_field())
1016            .collect();
1017        Self::sort_long_term_pic_num_ascending(&mut long_term_refs);
1018
1019        ref_pic_list_b0.extend(long_term_refs.clone());
1020
1021        // b1 contains three inner lists of pictures, i.e. [[0] [1] [2]]
1022        // [0]: short term pictures with POC > current, sorted by ascending POC.
1023        // [1]: short term pictures with POC < current, sorted by descending POC.
1024        // [2]: long term pictures sorted by ascending long_term_pic_num
1025        for &handle in &short_term_refs {
1026            let pic = handle.pic.borrow();
1027
1028            if pic.pic_order_cnt > cur_pic.pic_order_cnt {
1029                ref_pic_list_b1.push(handle);
1030            } else {
1031                remaining.push(handle);
1032            }
1033        }
1034
1035        Self::sort_poc_ascending(&mut ref_pic_list_b1);
1036        Self::sort_poc_descending(&mut remaining);
1037
1038        ref_pic_list_b1.extend(remaining);
1039        ref_pic_list_b1.extend(long_term_refs);
1040
1041        // When the reference picture list RefPicList1 has more than one entry
1042        // and RefPicList1 is identical to the reference picture list
1043        // RefPicList0, the first two entries RefPicList1[0] and RefPicList1[1]
1044        // are switched.
1045        Self::swap_b1_if_needed(&ref_pic_list_b0, &mut ref_pic_list_b1);
1046
1047        #[cfg(debug_assertions)]
1048        Self::debug_ref_list_b(&ref_pic_list_b0, "ref_pic_list_b0");
1049        #[cfg(debug_assertions)]
1050        Self::debug_ref_list_b(&ref_pic_list_b1, "ref_pic_list_b1");
1051
1052        (ref_pic_list_b0, ref_pic_list_b1)
1053    }
1054
1055    /// 8.2.4.2.4 Initialization process for reference picture lists for B
1056    /// slices in fields
1057    fn build_ref_field_pic_list_b(
1058        &self,
1059        cur_pic: &PictureData,
1060    ) -> (DpbPicRefList<T>, DpbPicRefList<T>) {
1061        let mut ref_pic_list_b0 = vec![];
1062        let mut ref_pic_list_b1 = vec![];
1063        let mut ref_frame_list_0_short_term = vec![];
1064        let mut ref_frame_list_1_short_term = vec![];
1065
1066        let mut remaining = vec![];
1067
1068        let mut short_term_refs: Vec<_> = self.short_term_refs_iter().collect();
1069
1070        // When pic_order_cnt_type is equal to 0, reference pictures that are
1071        // marked as "non-existing" as specified in clause 8.2.5.2 are not
1072        // included in either RefPicList0 or RefPicList1.
1073        if cur_pic.pic_order_cnt_type == 0 {
1074            short_term_refs.retain(|h| !h.pic.borrow().nonexisting);
1075        }
1076
1077        // refFrameList0ShortTerm is comprised of two inner lists, [[0] [1]]
1078        // [0]: short term pictures with POC <= current, sorted by descending POC
1079        // [1]: short term pictures with POC > current, sorted by ascending POC
1080        // NOTE 3 – When the current field follows in decoding order a coded
1081        // field fldPrev with which together it forms a complementary reference
1082        // field pair, fldPrev is included into the list refFrameList0ShortTerm
1083        // using PicOrderCnt( fldPrev ) and the ordering method described in the
1084        // previous sentence is applied.
1085        for &handle in &short_term_refs {
1086            let pic = handle.pic.borrow();
1087
1088            if pic.pic_order_cnt <= cur_pic.pic_order_cnt {
1089                ref_frame_list_0_short_term.push(handle);
1090            } else {
1091                remaining.push(handle);
1092            }
1093        }
1094
1095        Self::sort_poc_descending(&mut ref_frame_list_0_short_term);
1096        Self::sort_poc_ascending(&mut remaining);
1097        ref_frame_list_0_short_term.append(&mut remaining);
1098
1099        // refFrameList1ShortTerm is comprised of two inner lists, [[0] [1]]
1100        // [0]: short term pictures with POC > current, sorted by ascending POC
1101        // [1]: short term pictures with POC <= current, sorted by descending POC
1102        // NOTE 4 – When the current field follows in decoding order a coded
1103        // field fldPrev with which together it forms a complementary reference
1104        // field pair, fldPrev is included into the list refFrameList1ShortTerm
1105        // using PicOrderCnt( fldPrev ) and the ordering method described in the
1106        // previous sentence is applied.
1107
1108        for &handle in &short_term_refs {
1109            let pic = handle.pic.borrow();
1110
1111            if pic.pic_order_cnt > cur_pic.pic_order_cnt {
1112                ref_frame_list_1_short_term.push(handle);
1113            } else {
1114                remaining.push(handle);
1115            }
1116        }
1117
1118        Self::sort_poc_ascending(&mut ref_frame_list_1_short_term);
1119        Self::sort_poc_descending(&mut remaining);
1120        ref_frame_list_1_short_term.append(&mut remaining);
1121
1122        // refFrameListLongTerm: long term pictures sorted by ascending
1123        // LongTermFrameIdx.
1124        // NOTE 5 – When the current picture is the second field of a
1125        // complementary field pair and the first field of the complementary
1126        // field pair is marked as "used for long-term reference", the first
1127        // field is included into the list refFrameListLongTerm. A reference
1128        // entry in which only one field is marked as "used for long-term
1129        // reference" is included into the list refFrameListLongTerm
1130        let mut ref_frame_list_long_term: Vec<_> =
1131            self.long_term_refs_iter().filter(|h| !h.pic.borrow().nonexisting).collect();
1132
1133        Self::sort_long_term_frame_idx_ascending(&mut ref_frame_list_long_term);
1134
1135        #[cfg(debug_assertions)]
1136        Self::debug_ref_list_b(&ref_frame_list_0_short_term, "ref_frame_list_0_short_term");
1137        #[cfg(debug_assertions)]
1138        Self::debug_ref_list_b(&ref_frame_list_1_short_term, "ref_frame_list_1_short_term");
1139        #[cfg(debug_assertions)]
1140        Self::debug_ref_list_b(&ref_frame_list_long_term, "ref_frame_list_long_term");
1141
1142        // 8.2.4.2.5
1143        let field = cur_pic.field;
1144        Self::init_ref_field_pic_list(
1145            field,
1146            Reference::ShortTerm,
1147            &mut ref_frame_list_0_short_term,
1148            &mut ref_pic_list_b0,
1149        );
1150        Self::init_ref_field_pic_list(
1151            field,
1152            Reference::LongTerm,
1153            &mut ref_frame_list_long_term,
1154            &mut ref_pic_list_b0,
1155        );
1156
1157        Self::init_ref_field_pic_list(
1158            field,
1159            Reference::ShortTerm,
1160            &mut ref_frame_list_1_short_term,
1161            &mut ref_pic_list_b1,
1162        );
1163        Self::init_ref_field_pic_list(
1164            field,
1165            Reference::LongTerm,
1166            &mut ref_frame_list_long_term,
1167            &mut ref_pic_list_b1,
1168        );
1169
1170        // When the reference picture list RefPicList1 has more than one entry
1171        // and RefPicList1 is identical to the reference picture list
1172        // RefPicList0, the first two entries RefPicList1[0] and RefPicList1[1]
1173        // are switched.
1174        Self::swap_b1_if_needed(&ref_pic_list_b0, &mut ref_pic_list_b1);
1175
1176        #[cfg(debug_assertions)]
1177        Self::debug_ref_list_b(&ref_pic_list_b0, "ref_pic_list_b0");
1178        #[cfg(debug_assertions)]
1179        Self::debug_ref_list_b(&ref_pic_list_b1, "ref_pic_list_b1");
1180
1181        (ref_pic_list_b0, ref_pic_list_b1)
1182    }
1183
1184    /// Returns the lists of reference pictures for `pic`.
1185    pub fn build_ref_pic_lists(&self, pic: &PictureData) -> ReferencePicLists {
1186        let num_refs = self.pictures().filter(|p| p.is_ref() && !p.nonexisting).count();
1187
1188        // 8.2.4.2.1 ~ 8.2.4.2.4: When this process is invoked, there shall be
1189        // at least one reference frame or complementary reference field pair
1190        // that is currently marked as "used for reference" (i.e., as "used for
1191        // short-term reference" or "used for long-term reference") and is not
1192        // marked as "non-existing".
1193        if num_refs == 0 {
1194            return Default::default();
1195        }
1196
1197        let (ref_pic_list_p0, (ref_pic_list_b0, ref_pic_list_b1)) =
1198            if matches!(pic.field, Field::Frame) {
1199                (self.build_ref_pic_list_p(), self.build_ref_pic_list_b(pic))
1200            } else {
1201                (self.build_ref_field_pic_list_p(pic), self.build_ref_field_pic_list_b(pic))
1202            };
1203
1204        let dpb_start = self.entries.as_ptr();
1205        let refs_to_index = |refs: Vec<_>| {
1206            refs.into_iter()
1207                .map(|r| r as *const DpbEntry<T>)
1208                .map(|r| unsafe { r.offset_from(dpb_start) })
1209                .map(|i| i as usize)
1210                .collect()
1211        };
1212
1213        ReferencePicLists {
1214            ref_pic_list_p0: refs_to_index(ref_pic_list_p0),
1215            ref_pic_list_b0: refs_to_index(ref_pic_list_b0),
1216            ref_pic_list_b1: refs_to_index(ref_pic_list_b1),
1217        }
1218    }
1219}
1220
1221impl<T> Default for Dpb<T> {
1222    fn default() -> Self {
1223        // See https://github.com/rust-lang/rust/issues/26925 on why this can't
1224        // be derived.
1225        Self {
1226            entries: Default::default(),
1227            max_num_pics: Default::default(),
1228            max_num_reorder_frames: Default::default(),
1229            interlaced: Default::default(),
1230        }
1231    }
1232}
1233
1234impl<T> std::fmt::Debug for Dpb<T> {
1235    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1236        let pics = self.entries.iter().map(|h| &h.pic).enumerate().collect::<Vec<_>>();
1237        f.debug_struct("Dpb")
1238            .field("pictures", &pics)
1239            .field("max_num_pics", &self.max_num_pics)
1240            .field("interlaced", &self.interlaced)
1241            .finish()
1242    }
1243}