1// Copyright (c) 2020-2023, The rav1e contributors. All rights reserved
2//
3// This source code is subject to the terms of the BSD 2 Clause License and
4// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
5// was not distributed with this source code in the LICENSE file, you can
6// obtain it at www.aomedia.org/license/software. If the Alliance for Open
7// Media Patent License 1.0 was not distributed with this source code in the
8// PATENTS file, you can obtain it at www.aomedia.org/license/patent.
9
10use num_derive::*;
11
12use crate::partition::BlockSize;
13use crate::serialize::{Deserialize, Serialize};
14
15use std::fmt;
16
17// NOTE: Add Structures at the end.
18/// Contains the speed settings.
19#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
20#[non_exhaustive]
21pub struct SpeedSettings {
22 /// Enables inter-frames to have multiple reference frames.
23 ///
24 /// Enabled is slower.
25 pub multiref: bool,
26
27 /// Enables fast deblocking filter.
28 pub fast_deblock: bool,
29
30 /// The number of lookahead frames to be used for temporal RDO.
31 ///
32 /// Higher is slower.
33 pub rdo_lookahead_frames: usize,
34
35 /// Which scene detection mode to use. Standard is slower, but best.
36 pub scene_detection_mode: SceneDetectionSpeed,
37
38 /// Enables CDEF.
39 pub cdef: bool,
40
41 /// Enables LRF.
42 pub lrf: bool,
43
44 /// Enable searching loop restoration units when no transforms have been coded
45 /// restoration unit.
46 pub lru_on_skip: bool,
47
48 /// The amount of search done for self guided restoration.
49 pub sgr_complexity: SGRComplexityLevel,
50
51 /// Search level for segmentation.
52 ///
53 /// Full search is at least twice as slow.
54 pub segmentation: SegmentationLevel,
55
56 // NOTE: put enums and basic type fields above
57 /// Speed settings related to partition decision
58 pub partition: PartitionSpeedSettings,
59
60 /// Speed settings related to transform size and type decision
61 pub transform: TransformSpeedSettings,
62
63 /// Speed settings related to intra prediction mode selection
64 pub prediction: PredictionSpeedSettings,
65
66 /// Speed settings related to motion estimation and motion vector selection
67 pub motion: MotionSpeedSettings,
68}
69
70impl Default for SpeedSettings {
71 /// The default settings are equivalent to speed 0
72 fn default() -> Self {
73 SpeedSettings {
74 multiref: true,
75 fast_deblock: false,
76 rdo_lookahead_frames: 40,
77 scene_detection_mode: SceneDetectionSpeed::Standard,
78 cdef: true,
79 lrf: true,
80 lru_on_skip: true,
81 sgr_complexity: SGRComplexityLevel::Full,
82 segmentation: SegmentationLevel::Complex,
83 partition: PartitionSpeedSettings {
84 encode_bottomup: true,
85 non_square_partition_max_threshold: BlockSize::BLOCK_64X64,
86 partition_range: PartitionRange::new(
87 BlockSize::BLOCK_4X4,
88 BlockSize::BLOCK_64X64,
89 ),
90 },
91 transform: TransformSpeedSettings {
92 reduced_tx_set: false,
93 // TX domain distortion is always faster, with no significant quality change,
94 // although it will be ignored when Tune == Psychovisual.
95 tx_domain_distortion: true,
96 tx_domain_rate: false,
97 rdo_tx_decision: true,
98 enable_inter_tx_split: false,
99 },
100 prediction: PredictionSpeedSettings {
101 prediction_modes: PredictionModesSetting::ComplexAll,
102 fine_directional_intra: true,
103 },
104 motion: MotionSpeedSettings {
105 include_near_mvs: true,
106 use_satd_subpel: true,
107 me_allow_full_search: true,
108 },
109 }
110 }
111}
112
113impl SpeedSettings {
114 /// Set the speed setting according to a numeric speed preset.
115 pub fn from_preset(speed: u8) -> Self {
116 // The default settings are equivalent to speed 0
117 let mut settings = SpeedSettings::default();
118
119 if speed >= 1 {
120 settings.lru_on_skip = false;
121 settings.segmentation = SegmentationLevel::Simple;
122 }
123
124 if speed >= 2 {
125 settings.partition.non_square_partition_max_threshold =
126 BlockSize::BLOCK_8X8;
127
128 settings.prediction.prediction_modes =
129 PredictionModesSetting::ComplexKeyframes;
130 }
131
132 if speed >= 3 {
133 settings.rdo_lookahead_frames = 30;
134
135 settings.partition.partition_range =
136 PartitionRange::new(BlockSize::BLOCK_8X8, BlockSize::BLOCK_64X64);
137 }
138
139 if speed >= 4 {
140 settings.partition.encode_bottomup = false;
141 }
142
143 if speed >= 5 {
144 settings.sgr_complexity = SGRComplexityLevel::Reduced;
145 settings.motion.include_near_mvs = false;
146 }
147
148 if speed >= 6 {
149 settings.rdo_lookahead_frames = 20;
150
151 settings.transform.rdo_tx_decision = false;
152 settings.transform.reduced_tx_set = true;
153
154 settings.motion.me_allow_full_search = false;
155 }
156
157 if speed >= 7 {
158 settings.prediction.prediction_modes = PredictionModesSetting::Simple;
159 // Multiref is enabled automatically if low_latency is false.
160 //
161 // If low_latency is true, enabling multiref allows using multiple
162 // backwards references. low_latency false enables both forward and
163 // backwards references.
164 settings.multiref = false;
165 settings.fast_deblock = true;
166 }
167
168 if speed >= 8 {
169 settings.rdo_lookahead_frames = 10;
170 settings.lrf = false;
171 }
172
173 if speed >= 9 {
174 // 8x8 is fast enough to use until very high speed levels,
175 // because 8x8 with reduced TX set is faster but with equivalent
176 // or better quality compared to 16x16 (to which reduced TX set does not apply).
177 settings.partition.partition_range =
178 PartitionRange::new(BlockSize::BLOCK_16X16, BlockSize::BLOCK_32X32);
179
180 // FIXME: With unknown reasons, inter_tx_split does not work if reduced_tx_set is false
181 settings.transform.enable_inter_tx_split = true;
182 }
183
184 if speed >= 10 {
185 settings.scene_detection_mode = SceneDetectionSpeed::Fast;
186
187 settings.partition.partition_range =
188 PartitionRange::new(BlockSize::BLOCK_32X32, BlockSize::BLOCK_32X32);
189
190 settings.motion.use_satd_subpel = false;
191 }
192
193 settings
194 }
195}
196
197#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
198#[cfg_attr(test, derive(Default))]
199/// Speed settings related to transform size and type decision
200pub struct TransformSpeedSettings {
201 /// Enables reduced transform set.
202 ///
203 /// Enabled is faster.
204 pub reduced_tx_set: bool,
205
206 /// Enables using transform-domain distortion instead of pixel-domain.
207 ///
208 /// Enabled is faster.
209 pub tx_domain_distortion: bool,
210
211 /// Enables using transform-domain rate estimation.
212 ///
213 /// Enabled is faster.
214 pub tx_domain_rate: bool,
215
216 /// Enables searching transform size and type with RDO.
217 ///
218 /// Enabled is slower.
219 pub rdo_tx_decision: bool,
220
221 /// Enable tx split for inter mode block.
222 pub enable_inter_tx_split: bool,
223}
224
225#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
226#[cfg_attr(test, derive(Default))]
227/// Speed settings related to partition decision
228pub struct PartitionSpeedSettings {
229 /// Enables bottom-up encoding, rather than top-down.
230 ///
231 /// Enabled is slower.
232 pub encode_bottomup: bool,
233
234 /// Allow non-square partition type outside of frame borders
235 /// on any blocks at or below this size.
236 pub non_square_partition_max_threshold: BlockSize,
237
238 /// Range of partition sizes that can be used. Larger ranges are slower.
239 ///
240 /// Must be based on square block sizes, so e.g. 8×4 isn't allowed here.
241 pub partition_range: PartitionRange,
242}
243
244#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
245#[cfg_attr(test, derive(Default))]
246/// Speed settings related to motion estimation and motion vector selection
247pub struct MotionSpeedSettings {
248 /// Use SATD instead of SAD for subpixel search.
249 ///
250 /// Enabled is slower.
251 pub use_satd_subpel: bool,
252
253 /// Enables searching near motion vectors during RDO.
254 ///
255 /// Enabled is slower.
256 pub include_near_mvs: bool,
257
258 /// Enable full search in some parts of motion estimation. Allowing full
259 /// search is slower.
260 pub me_allow_full_search: bool,
261}
262
263#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
264#[cfg_attr(test, derive(Default))]
265/// Speed settings related to intra prediction mode selection
266pub struct PredictionSpeedSettings {
267 /// Prediction modes to search.
268 ///
269 /// Complex settings are slower.
270 pub prediction_modes: PredictionModesSetting,
271
272 /// Use fine directional intra prediction
273 pub fine_directional_intra: bool,
274}
275
276/// Range of block sizes to use.
277#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
278pub struct PartitionRange {
279 pub(crate) min: BlockSize,
280 pub(crate) max: BlockSize,
281}
282
283impl PartitionRange {
284 /// Creates a new partition range with min and max partition sizes.
285 ///
286 /// # Panics
287 ///
288 /// - Panics if `max` is larger than `min`.
289 /// - Panics if either `min` or `max` are not square.
290 pub fn new(min: BlockSize, max: BlockSize) -> Self {
291 assert!(max >= min);
292 // Topdown search checks the min block size for PARTITION_SPLIT only, so
293 // the min block size must be square.
294 assert!(min.is_sqr());
295 // Rectangular max partition sizes have not been tested.
296 assert!(max.is_sqr());
297
298 Self { min, max }
299 }
300}
301
302#[cfg(test)]
303impl Default for PartitionRange {
304 fn default() -> Self {
305 PartitionRange::new(BlockSize::BLOCK_4X4, BlockSize::BLOCK_64X64)
306 }
307}
308
309/// Prediction modes to search.
310#[derive(
311 Clone,
312 Copy,
313 Debug,
314 PartialOrd,
315 PartialEq,
316 Eq,
317 FromPrimitive,
318 Serialize,
319 Deserialize,
320)]
321pub enum SceneDetectionSpeed {
322 /// Fastest scene detection using pixel-wise comparison
323 Fast,
324 /// Scene detection using motion vectors and cost estimates
325 Standard,
326 /// Completely disable scene detection and only place keyframes
327 /// at fixed intervals.
328 None,
329}
330
331impl fmt::Display for SceneDetectionSpeed {
332 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
333 write!(
334 f,
335 "{}",
336 match self {
337 SceneDetectionSpeed::Fast => "Fast",
338 SceneDetectionSpeed::Standard => "Standard",
339 SceneDetectionSpeed::None => "None",
340 }
341 )
342 }
343}
344
345/// Prediction modes to search.
346#[derive(
347 Clone,
348 Copy,
349 Debug,
350 PartialOrd,
351 PartialEq,
352 Eq,
353 FromPrimitive,
354 Serialize,
355 Deserialize,
356)]
357pub enum PredictionModesSetting {
358 /// Only simple prediction modes.
359 Simple,
360 /// Search all prediction modes on key frames and simple modes on other
361 /// frames.
362 ComplexKeyframes,
363 /// Search all prediction modes on all frames.
364 ComplexAll,
365}
366
367impl fmt::Display for PredictionModesSetting {
368 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
369 write!(
370 f,
371 "{}",
372 match self {
373 PredictionModesSetting::Simple => "Simple",
374 PredictionModesSetting::ComplexKeyframes => "Complex-KFs",
375 PredictionModesSetting::ComplexAll => "Complex-All",
376 }
377 )
378 }
379}
380
381#[cfg(test)]
382impl Default for PredictionModesSetting {
383 fn default() -> Self {
384 PredictionModesSetting::Simple
385 }
386}
387
388/// Search level for self guided restoration
389#[derive(
390 Clone,
391 Copy,
392 Debug,
393 PartialOrd,
394 PartialEq,
395 Eq,
396 FromPrimitive,
397 Serialize,
398 Deserialize,
399)]
400pub enum SGRComplexityLevel {
401 /// Search all sgr parameters
402 Full,
403 /// Search a reduced set of sgr parameters
404 Reduced,
405}
406
407impl fmt::Display for SGRComplexityLevel {
408 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
409 write!(
410 f,
411 "{}",
412 match self {
413 SGRComplexityLevel::Full => "Full",
414 SGRComplexityLevel::Reduced => "Reduced",
415 }
416 )
417 }
418}
419
420/// Search level for segmentation
421#[derive(
422 Clone,
423 Copy,
424 Debug,
425 PartialOrd,
426 PartialEq,
427 Eq,
428 FromPrimitive,
429 Serialize,
430 Deserialize,
431)]
432pub enum SegmentationLevel {
433 /// No segmentation is signalled.
434 Disabled,
435 /// Segmentation index is derived from source statistics.
436 Simple,
437 /// Segmentation index range is derived from source statistics.
438 Complex,
439 /// Search all segmentation indices.
440 Full,
441}
442
443impl fmt::Display for SegmentationLevel {
444 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
445 write!(
446 f,
447 "{}",
448 match self {
449 SegmentationLevel::Disabled => "Disabled",
450 SegmentationLevel::Simple => "Simple",
451 SegmentationLevel::Complex => "Complex",
452 SegmentationLevel::Full => "Full",
453 }
454 )
455 }
456}
457