Skip to main content

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