Skip to main content

moq_vaapi/codec/h264/
picture.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::RefCell;
6use std::ops::Deref;
7use std::rc::Rc;
8use std::rc::Weak;
9
10use log::debug;
11
12use crate::codec::h264::parser::MaxLongTermFrameIdx;
13use crate::codec::h264::parser::RefPicMarking;
14use crate::codec::h264::parser::Slice;
15use crate::codec::h264::parser::SliceType;
16use crate::codec::h264::parser::Sps;
17use crate::Resolution;
18
19#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
20pub enum Field {
21	#[default]
22	Frame,
23	Top,
24	Bottom,
25}
26
27impl Field {
28	/// Returns the field of opposite parity.
29	pub fn opposite(&self) -> Self {
30		match *self {
31			Field::Frame => Field::Frame,
32			Field::Top => Field::Bottom,
33			Field::Bottom => Field::Top,
34		}
35	}
36}
37
38#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
39pub enum Reference {
40	#[default]
41	None,
42	ShortTerm,
43	LongTerm,
44}
45
46#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
47pub enum IsIdr {
48	#[default]
49	No,
50	Yes {
51		idr_pic_id: u16,
52	},
53}
54
55/// The rank of a field, i.e. whether it is the first or second one to be parsed from the stream.
56/// This is unrelated to the `Field` type, as the first field can be either `Top` or `Bottom`.
57#[derive(Default, Debug)]
58pub enum FieldRank {
59	/// Frame has a single field.
60	#[default]
61	Single,
62	/// Frame is interlaced, and this is the first field (with a reference to the second one).
63	First(Weak<RefCell<PictureData>>),
64	/// Frame is interlaced, and this is the second field (with a reference to the first one).
65	Second(Rc<RefCell<PictureData>>),
66}
67
68#[derive(Default)]
69pub struct PictureData {
70	pub pic_order_cnt_type: u8,
71	pub top_field_order_cnt: i32,
72	pub bottom_field_order_cnt: i32,
73	pub pic_order_cnt: i32,
74	pub pic_order_cnt_msb: i32,
75	pub pic_order_cnt_lsb: i32,
76	pub delta_pic_order_cnt_bottom: i32,
77	pub delta_pic_order_cnt0: i32,
78	pub delta_pic_order_cnt1: i32,
79
80	pub pic_num: i32,
81	pub long_term_pic_num: u32,
82	pub frame_num: u32,
83	pub frame_num_offset: u32,
84	pub frame_num_wrap: i32,
85	pub long_term_frame_idx: u32,
86
87	pub coded_resolution: Resolution,
88	pub display_resolution: Resolution,
89
90	pub type_: SliceType,
91	pub nal_ref_idc: u8,
92	pub is_idr: IsIdr,
93	reference: Reference,
94	pub ref_pic_list_modification_flag_l0: i32,
95	pub abs_diff_pic_num_minus1: i32,
96
97	// Does memory management op 5 needs to be executed after this
98	// picture has finished decoding?
99	pub has_mmco_5: bool,
100
101	// Created by the decoding process for gaps in frame_num.
102	// Not for decode or output.
103	pub nonexisting: bool,
104
105	pub field: Field,
106
107	// Values from slice_hdr to be used during reference marking and
108	// memory management after finishing this picture.
109	pub ref_pic_marking: RefPicMarking,
110
111	field_rank: FieldRank,
112
113	pub timestamp: u64,
114}
115
116/// A `PictureData` within a `Rc<RefCell>` which field rank is guaranteed to be correct.
117///
118/// The field rank of `PictureData` is only final after both fields have been constructed - namely,
119/// the first field can only point to the second one after the latter is available as a Rc. Methods
120/// [`PictureData::into_rc`] and [`PictureData::split_frame`] take care of this, and is this only
121/// producer of this type, ensuring all instances are correct.
122#[derive(Default, Debug, Clone)]
123pub struct RcPictureData {
124	pic: Rc<RefCell<PictureData>>,
125}
126
127impl Deref for RcPictureData {
128	type Target = Rc<RefCell<PictureData>>;
129
130	fn deref(&self) -> &Self::Target {
131		&self.pic
132	}
133}
134
135impl PictureData {
136	pub fn new_non_existing(frame_num: u32, timestamp: u64) -> Self {
137		PictureData {
138			frame_num,
139			nonexisting: true,
140			nal_ref_idc: 1,
141			field: Field::Frame,
142			pic_num: frame_num as i32,
143			reference: Reference::ShortTerm,
144			timestamp,
145			..Default::default()
146		}
147	}
148
149	/// Create a new picture from a `slice`, `sps`, and `timestamp`.
150	///
151	/// `first_field` is set if this picture is the second field of a frame.
152	pub fn new_from_slice(slice: &Slice, sps: &Sps, timestamp: u64, first_field: Option<&RcPictureData>) -> Self {
153		let hdr = &slice.header;
154		let nalu_hdr = &slice.nalu.header;
155
156		let is_idr = if nalu_hdr.idr_pic_flag {
157			IsIdr::Yes {
158				idr_pic_id: hdr.idr_pic_id,
159			}
160		} else {
161			IsIdr::No
162		};
163
164		let field = if hdr.field_pic_flag {
165			if hdr.bottom_field_flag {
166				Field::Bottom
167			} else {
168				Field::Top
169			}
170		} else {
171			Field::Frame
172		};
173
174		let reference = if nalu_hdr.ref_idc != 0 {
175			Reference::ShortTerm
176		} else {
177			Reference::None
178		};
179
180		let pic_num = if !hdr.field_pic_flag {
181			hdr.frame_num
182		} else {
183			2 * hdr.frame_num + 1
184		};
185
186		let (pic_order_cnt_lsb, delta_pic_order_cnt_bottom, delta_pic_order_cnt0, delta_pic_order_cnt1) =
187			match sps.pic_order_cnt_type {
188				0 => (
189					hdr.pic_order_cnt_lsb,
190					hdr.delta_pic_order_cnt_bottom,
191					Default::default(),
192					Default::default(),
193				),
194				1 => (
195					Default::default(),
196					Default::default(),
197					hdr.delta_pic_order_cnt[0],
198					hdr.delta_pic_order_cnt[1],
199				),
200				_ => (
201					Default::default(),
202					Default::default(),
203					Default::default(),
204					Default::default(),
205				),
206			};
207
208		let coded_resolution = Resolution::from((sps.width(), sps.height()));
209
210		let visible_rect = sps.visible_rectangle();
211
212		let display_resolution = Resolution {
213			width: visible_rect.max.x - visible_rect.min.x,
214			height: visible_rect.max.y - visible_rect.min.y,
215		};
216
217		let mut pic = PictureData {
218			pic_order_cnt_type: sps.pic_order_cnt_type,
219			pic_order_cnt_lsb: i32::from(pic_order_cnt_lsb),
220			delta_pic_order_cnt_bottom,
221			delta_pic_order_cnt0,
222			delta_pic_order_cnt1,
223			pic_num: i32::from(pic_num),
224			frame_num: u32::from(hdr.frame_num),
225			nal_ref_idc: nalu_hdr.ref_idc,
226			is_idr,
227			reference,
228			field,
229			ref_pic_marking: hdr.dec_ref_pic_marking.clone(),
230			coded_resolution,
231			display_resolution,
232			timestamp,
233			..Default::default()
234		};
235
236		if let Some(first_field) = first_field {
237			pic.set_first_field_to(first_field);
238		}
239
240		pic
241	}
242
243	/// Whether the current picture is a reference, either ShortTerm or LongTerm.
244	pub fn is_ref(&self) -> bool {
245		!matches!(self.reference, Reference::None)
246	}
247
248	/// Whether this picture is a second field.
249	pub fn is_second_field(&self) -> bool {
250		matches!(self.field_rank, FieldRank::Second(..))
251	}
252
253	/// Returns the field rank of this picture, including a reference to its other field.
254	pub fn field_rank(&self) -> &FieldRank {
255		&self.field_rank
256	}
257
258	/// Returns a reference to the picture's Reference
259	pub fn reference(&self) -> &Reference {
260		&self.reference
261	}
262
263	/// Mark the picture as a reference picture.
264	pub fn set_reference(&mut self, reference: Reference, apply_to_other_field: bool) {
265		log::debug!("Set reference of {:#?} to {:?}", self, reference);
266		self.reference = reference;
267
268		if apply_to_other_field {
269			if let Some(other_field) = self.other_field() {
270				log::debug!(
271					"other_field: Set reference of {:#?} to {:?}",
272					&other_field.borrow(),
273					reference
274				);
275				other_field.borrow_mut().reference = reference;
276			}
277		}
278	}
279
280	/// Get a reference to the picture's other field, if there is any
281	/// and its reference is still valid.
282	pub fn other_field(&self) -> Option<Rc<RefCell<PictureData>>> {
283		match &self.field_rank {
284			FieldRank::Single => None,
285			FieldRank::First(other_field) => other_field.upgrade(),
286			FieldRank::Second(other_field) => Some(other_field.clone()),
287		}
288	}
289
290	/// Set this picture's second field.
291	fn set_second_field_to(&mut self, other_field: &Rc<RefCell<Self>>) {
292		self.field_rank = FieldRank::First(Rc::downgrade(other_field));
293	}
294
295	/// Whether the current picture is the second field of a complementary ref pair.
296	pub fn is_second_field_of_complementary_ref_pair(&self) -> bool {
297		self.is_ref() && matches!(self.field_rank(), FieldRank::Second(first_field) if first_field.borrow().is_ref())
298	}
299
300	/// Set this picture's first field.
301	fn set_first_field_to(&mut self, other_field: &Rc<RefCell<Self>>) {
302		self.field_rank = FieldRank::Second(other_field.clone());
303	}
304
305	pub fn pic_num_f(&self, max_pic_num: i32) -> i32 {
306		if !matches!(self.reference(), Reference::LongTerm) {
307			self.pic_num
308		} else {
309			max_pic_num
310		}
311	}
312
313	pub fn long_term_pic_num_f(&self, max_long_term_frame_idx: MaxLongTermFrameIdx) -> u32 {
314		if matches!(self.reference(), Reference::LongTerm) {
315			self.long_term_pic_num
316		} else {
317			2 * max_long_term_frame_idx.to_value_plus1()
318		}
319	}
320
321	/// Consume this picture and return a Rc'd version.
322	///
323	/// If the picture was a second field, adjust the field of the first field to point to this
324	/// one.
325	pub fn into_rc(self) -> RcPictureData {
326		let self_rc = Rc::new(RefCell::new(self));
327
328		if let FieldRank::Second(first_field) = self_rc.borrow().field_rank() {
329			first_field.borrow_mut().set_second_field_to(&self_rc);
330		}
331
332		RcPictureData { pic: self_rc }
333	}
334
335	/// Split a frame into two complementary fields that reference one another.
336	pub fn split_frame(mut self) -> (RcPictureData, RcPictureData) {
337		assert!(matches!(self.field, Field::Frame));
338		assert!(matches!(self.field_rank, FieldRank::Single));
339
340		debug!(
341			"Splitting picture (frame_num, POC) ({:?}, {:?})",
342			self.frame_num, self.pic_order_cnt
343		);
344
345		let second_pic_order_cnt = if self.top_field_order_cnt < self.bottom_field_order_cnt {
346			self.field = Field::Top;
347			self.pic_order_cnt = self.top_field_order_cnt;
348
349			self.bottom_field_order_cnt
350		} else {
351			self.field = Field::Bottom;
352			self.pic_order_cnt = self.bottom_field_order_cnt;
353
354			self.top_field_order_cnt
355		};
356
357		let second_field = PictureData {
358			top_field_order_cnt: self.top_field_order_cnt,
359			bottom_field_order_cnt: self.bottom_field_order_cnt,
360			frame_num: self.frame_num,
361			reference: self.reference,
362			nonexisting: self.nonexisting,
363			pic_order_cnt: second_pic_order_cnt,
364			field: self.field.opposite(),
365			..Default::default()
366		};
367
368		debug!(
369			"Split into picture (frame_num, POC) ({:?}, {:?}), field: {:?}",
370			self.frame_num, self.pic_order_cnt, self.field
371		);
372		debug!(
373			"Split into picture (frame_num, POC) ({:?}, {:?}), field {:?}",
374			second_field.frame_num, second_field.pic_order_cnt, second_field.field
375		);
376
377		let first_field = Rc::new(RefCell::new(self));
378		let second_field = Rc::new(RefCell::new(second_field));
379
380		first_field.borrow_mut().set_second_field_to(&second_field);
381		second_field.borrow_mut().set_first_field_to(&first_field);
382
383		(RcPictureData { pic: first_field }, RcPictureData { pic: second_field })
384	}
385}
386
387impl std::fmt::Debug for PictureData {
388	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389		f.debug_struct("PictureData")
390			.field("pic_order_cnt_type", &self.pic_order_cnt_type)
391			.field("top_field_order_cnt", &self.top_field_order_cnt)
392			.field("bottom_field_order_cnt", &self.bottom_field_order_cnt)
393			.field("pic_order_cnt", &self.pic_order_cnt)
394			.field("pic_order_cnt_msb", &self.pic_order_cnt_msb)
395			.field("pic_order_cnt_lsb", &self.pic_order_cnt_lsb)
396			.field("delta_pic_order_cnt_bottom", &self.delta_pic_order_cnt_bottom)
397			.field("delta_pic_order_cnt0", &self.delta_pic_order_cnt0)
398			.field("delta_pic_order_cnt1", &self.delta_pic_order_cnt1)
399			.field("pic_num", &self.pic_num)
400			.field("long_term_pic_num", &self.long_term_pic_num)
401			.field("frame_num", &self.frame_num)
402			.field("frame_num_offset", &self.frame_num_offset)
403			.field("frame_num_wrap", &self.frame_num_wrap)
404			.field("long_term_frame_idx", &self.long_term_frame_idx)
405			.field("coded_resolution", &self.coded_resolution)
406			.field("display_resolution", &self.display_resolution)
407			.field("type_", &self.type_)
408			.field("nal_ref_idc", &self.nal_ref_idc)
409			.field("is_idr", &self.is_idr)
410			.field("reference", &self.reference)
411			.field(
412				"ref_pic_list_modification_flag_l0",
413				&self.ref_pic_list_modification_flag_l0,
414			)
415			.field("abs_diff_pic_num_minus1", &self.abs_diff_pic_num_minus1)
416			.field("has_mmco_5", &self.has_mmco_5)
417			.field("nonexisting", &self.nonexisting)
418			.field("field", &self.field)
419			.field("ref_pic_marking", &self.ref_pic_marking)
420			.field("field_rank", &self.field_rank)
421			.finish()
422	}
423}