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