• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use crate::codec::av1::parser::BitDepth;
6 use crate::codec::av1::parser::CdefParams;
7 use crate::codec::av1::parser::ColorConfig;
8 use crate::codec::av1::parser::FrameHeaderObu;
9 use crate::codec::av1::parser::FrameType;
10 use crate::codec::av1::parser::ObuHeader;
11 use crate::codec::av1::parser::ObuType;
12 use crate::codec::av1::parser::OperatingPoint;
13 use crate::codec::av1::parser::Profile;
14 use crate::codec::av1::parser::QuantizationParams;
15 use crate::codec::av1::parser::ReferenceFrameType;
16 use crate::codec::av1::parser::SequenceHeaderObu;
17 use crate::codec::av1::parser::TemporalDelimiterObu;
18 use crate::codec::av1::parser::TileInfo;
19 use crate::codec::av1::parser::TxMode;
20 use crate::codec::av1::parser::MAX_NUM_OPERATING_POINTS;
21 use crate::codec::av1::parser::MAX_TILE_COLS;
22 use crate::codec::av1::parser::MAX_TILE_ROWS;
23 use crate::codec::av1::parser::PRIMARY_REF_NONE;
24 use crate::codec::av1::parser::REFS_PER_FRAME;
25 use crate::codec::av1::parser::SELECT_INTEGER_MV;
26 use crate::codec::av1::parser::SUPERRES_NUM;
27 use crate::codec::av1::synthesizer::Synthesizer;
28 use crate::encoder::stateless::av1::BackendRequest;
29 use crate::encoder::stateless::av1::EncoderConfig;
30 use crate::encoder::stateless::predictor::LowDelay;
31 use crate::encoder::stateless::predictor::LowDelayDelegate;
32 use crate::encoder::EncodeError;
33 use crate::encoder::EncodeResult;
34 use crate::encoder::FrameMetadata;
35 use crate::encoder::RateControl;
36 use crate::encoder::Tunings;
37 
38 // AV1 Spec. Dc_Qlookup max indices
39 pub(crate) const MIN_BASE_QINDEX: u32 = 0;
40 pub(crate) const MAX_BASE_QINDEX: u32 = 255;
41 
42 pub(crate) struct LowDelayAV1Delegate {
43     /// Current sequence header obu
44     sequence: SequenceHeaderObu,
45 
46     /// Encoder config
47     config: EncoderConfig,
48 }
49 
50 pub(crate) type LowDelayAV1<Picture, Reference> =
51     LowDelay<Picture, Reference, LowDelayAV1Delegate, BackendRequest<Picture, Reference>>;
52 
53 impl<Picture, Reference> LowDelayAV1<Picture, Reference> {
new(config: EncoderConfig, limit: u16) -> Self54     pub fn new(config: EncoderConfig, limit: u16) -> Self {
55         Self {
56             queue: Default::default(),
57             references: Default::default(),
58             counter: 0,
59             limit,
60             tunings: config.initial_tunings.clone(),
61             delegate: LowDelayAV1Delegate {
62                 sequence: Self::create_sequence_header(&config),
63                 config,
64             },
65             tunings_queue: Default::default(),
66             _phantom: Default::default(),
67         }
68     }
69 
create_sequence_header(config: &EncoderConfig) -> SequenceHeaderObu70     fn create_sequence_header(config: &EncoderConfig) -> SequenceHeaderObu {
71         let width = config.resolution.width;
72         let height = config.resolution.height;
73 
74         SequenceHeaderObu {
75             obu_header: ObuHeader {
76                 obu_type: ObuType::SequenceHeader,
77                 extension_flag: false,
78                 has_size_field: true,
79                 temporal_id: 0,
80                 spatial_id: 0,
81             },
82 
83             seq_profile: Profile::Profile0,
84             num_planes: 3,
85 
86             enable_order_hint: true,
87             order_hint_bits: 8,
88             order_hint_bits_minus_1: 8 - 1,
89 
90             // Use maximum size (16 bits)
91             frame_width_bits_minus_1: (1 << 4) - 1,
92             frame_height_bits_minus_1: (1 << 4) - 1,
93 
94             // Current resolution is the maximum resolution
95             max_frame_width_minus_1: (width - 1) as u16,
96             max_frame_height_minus_1: (height - 1) as u16,
97 
98             seq_force_integer_mv: SELECT_INTEGER_MV as u32,
99 
100             operating_points: {
101                 let mut ops: [OperatingPoint; MAX_NUM_OPERATING_POINTS] = Default::default();
102                 ops[0].idc = 0;
103                 // Use highest level 23 for now.
104                 // TODO(bgrzesik): approximate level base on resolution and framerate
105                 ops[0].seq_level_idx = 23;
106                 ops
107             },
108 
109             bit_depth: config.bit_depth,
110             color_config: ColorConfig {
111                 // YUV 4:2:0 8-bit or 10-bit
112                 high_bitdepth: config.bit_depth == BitDepth::Depth10,
113                 mono_chrome: false,
114                 subsampling_x: true,
115                 subsampling_y: true,
116                 ..Default::default()
117             },
118 
119             ..Default::default()
120         }
121     }
122 
create_temporal_delimiter() -> TemporalDelimiterObu123     fn create_temporal_delimiter() -> TemporalDelimiterObu {
124         TemporalDelimiterObu {
125             obu_header: ObuHeader {
126                 obu_type: ObuType::TemporalDelimiter,
127                 extension_flag: false,
128                 has_size_field: true,
129                 temporal_id: 0,
130                 spatial_id: 0,
131             },
132         }
133     }
134 
create_frame_header(&self, frame_type: FrameType) -> EncodeResult<FrameHeaderObu>135     fn create_frame_header(&self, frame_type: FrameType) -> EncodeResult<FrameHeaderObu> {
136         let width = self.delegate.config.resolution.width;
137         let height = self.delegate.config.resolution.height;
138 
139         // Superblock size
140         let sb_size = if self.delegate.sequence.use_128x128_superblock { 128 } else { 64 };
141 
142         // Use frame counter for order hinting
143         let order_hint_mask = (1 << self.delegate.sequence.order_hint_bits) - 1;
144         let order_hint = (self.counter & order_hint_mask) as u32;
145 
146         let RateControl::ConstantQuality(base_q_idx) = self.tunings.rate_control else {
147             return Err(EncodeError::Unsupported);
148         };
149 
150         // Clamp tunings's quaility range to correct range
151         let min_q_idx = self.tunings.min_quality.max(MIN_BASE_QINDEX);
152         let max_q_idx = self.tunings.max_quality.min(MAX_BASE_QINDEX);
153 
154         // Clamp Q index
155         let base_q_idx = base_q_idx.clamp(min_q_idx, max_q_idx);
156 
157         // Set the frame size in superblocks for the only tile
158         let mut width_in_sbs_minus_1 = [0u32; MAX_TILE_COLS];
159         width_in_sbs_minus_1[0] = ((width + sb_size - 1) / sb_size) - 1;
160 
161         let mut height_in_sbs_minus_1 = [0u32; MAX_TILE_ROWS];
162         height_in_sbs_minus_1[0] = ((height + sb_size - 1) / sb_size) - 1;
163 
164         Ok(FrameHeaderObu {
165             obu_header: ObuHeader {
166                 obu_type: ObuType::FrameHeader,
167                 extension_flag: false,
168                 has_size_field: true,
169                 temporal_id: 0,
170                 spatial_id: 0,
171             },
172             show_frame: true,
173             showable_frame: !matches!(frame_type, FrameType::KeyFrame),
174             frame_type,
175             frame_is_intra: matches!(frame_type, FrameType::KeyFrame | FrameType::IntraOnlyFrame),
176             primary_ref_frame: PRIMARY_REF_NONE,
177             refresh_frame_flags: if matches!(frame_type, FrameType::KeyFrame) {
178                 0xff
179             } else {
180                 0x01
181             },
182 
183             // Use error resilient mode, and provide the order hints for referencing frame ie. just
184             // previous frame
185             error_resilient_mode: true,
186             order_hint,
187             ref_order_hint: [0, 0, 0, 0, 0, 0, 0, 0],
188 
189             reduced_tx_set: true,
190             tx_mode_select: 1,
191             tx_mode: TxMode::Select,
192 
193             // Provide the Q index from config
194             quantization_params: QuantizationParams { base_q_idx, ..Default::default() },
195 
196             // Use single tile for now
197             tile_info: TileInfo {
198                 uniform_tile_spacing_flag: true,
199                 tile_cols: 1,
200                 tile_rows: 1,
201                 tile_cols_log2: 0,
202                 tile_rows_log2: 0,
203                 width_in_sbs_minus_1,
204                 height_in_sbs_minus_1,
205                 ..Default::default()
206             },
207 
208             // CDEF is not used currently, use default value to keep Synthesizer happy
209             cdef_params: CdefParams { cdef_damping: 3, ..Default::default() },
210 
211             // No superres
212             superres_denom: SUPERRES_NUM as u32,
213             upscaled_width: width,
214             frame_width: width,
215             frame_height: height,
216             render_width: width,
217             render_height: height,
218 
219             ..Default::default()
220         })
221     }
222 }
223 
224 impl<Picture, Reference> LowDelayDelegate<Picture, Reference, BackendRequest<Picture, Reference>>
225     for LowDelayAV1<Picture, Reference>
226 {
request_keyframe( &mut self, input: Picture, input_meta: FrameMetadata, idr: bool, ) -> EncodeResult<BackendRequest<Picture, Reference>>227     fn request_keyframe(
228         &mut self,
229         input: Picture,
230         input_meta: FrameMetadata,
231         idr: bool,
232     ) -> EncodeResult<BackendRequest<Picture, Reference>> {
233         log::trace!("Requested keyframe timestamp={}", input_meta.timestamp);
234 
235         let temporal_delim = Self::create_temporal_delimiter();
236         let sequence = self.delegate.sequence.clone();
237         let frame = self.create_frame_header(FrameType::KeyFrame)?;
238 
239         // This is intra frame, so there is no references
240         let references = [None, None, None, None, None, None, None];
241         let ref_frame_ctrl_l0 = [ReferenceFrameType::Intra; REFS_PER_FRAME];
242         let ref_frame_ctrl_l1 = [ReferenceFrameType::Intra; REFS_PER_FRAME];
243 
244         let mut coded_output = Vec::new();
245 
246         // Output Temporal Delimiter, Sequence Header and Frame Header OBUs to bitstream
247         Synthesizer::<'_, TemporalDelimiterObu, _>::synthesize(&temporal_delim, &mut coded_output)?;
248         if idr {
249             Synthesizer::<'_, SequenceHeaderObu, _>::synthesize(&sequence, &mut coded_output)?;
250         }
251         Synthesizer::<'_, FrameHeaderObu, _>::synthesize(&frame, &sequence, &mut coded_output)?;
252 
253         let request = BackendRequest {
254             sequence,
255             frame,
256             input,
257             input_meta,
258             references,
259             ref_frame_ctrl_l0,
260             ref_frame_ctrl_l1,
261             intra_period: self.limit as u32,
262             ip_period: 1,
263             tunings: self.tunings.clone(),
264             coded_output,
265         };
266 
267         Ok(request)
268     }
269 
request_interframe( &mut self, input: Picture, input_meta: FrameMetadata, ) -> EncodeResult<BackendRequest<Picture, Reference>>270     fn request_interframe(
271         &mut self,
272         input: Picture,
273         input_meta: FrameMetadata,
274     ) -> EncodeResult<BackendRequest<Picture, Reference>> {
275         log::trace!("Requested interframe timestamp={}", input_meta.timestamp);
276 
277         let temporal_delim = Self::create_temporal_delimiter();
278         let sequence = self.delegate.sequence.clone();
279         let mut frame = self.create_frame_header(FrameType::InterFrame)?;
280 
281         // Use previous frame as last frame reference
282         let references = [self.references.front().cloned(), None, None, None, None, None, None];
283 
284         let order_hint_mask = (1 << self.delegate.sequence.order_hint_bits) - 1;
285         let mut ref_frame_ctrl_l0 = [ReferenceFrameType::Intra; REFS_PER_FRAME];
286         let ref_frame_ctrl_l1 = [ReferenceFrameType::Intra; REFS_PER_FRAME];
287 
288         // Enable previous frame as reference
289         ref_frame_ctrl_l0[0] = ReferenceFrameType::Last;
290         frame.ref_frame_idx[0] = 0;
291         frame.last_frame_idx = 0;
292         frame.ref_order_hint[0] = ((self.counter - 1) & order_hint_mask) as u32;
293 
294         let mut coded_output = Vec::new();
295 
296         // Output Temporal Delimiter and Frame Header OBUs to bitstream, marking next frame
297         Synthesizer::<'_, TemporalDelimiterObu, _>::synthesize(&temporal_delim, &mut coded_output)?;
298         Synthesizer::<'_, FrameHeaderObu, _>::synthesize(&frame, &sequence, &mut coded_output)?;
299 
300         let request = BackendRequest {
301             sequence,
302             frame,
303             input,
304             input_meta,
305             references,
306             ref_frame_ctrl_l0,
307             ref_frame_ctrl_l1,
308             intra_period: self.limit as u32,
309             ip_period: 1,
310             tunings: self.tunings.clone(),
311             coded_output,
312         };
313 
314         self.references.clear();
315 
316         Ok(request)
317     }
318 
try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()>319     fn try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()> {
320         Ok(())
321     }
322 
apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()>323     fn apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()> {
324         Ok(())
325     }
326 }
327