rav1e/api/config/
speedsettings.rs

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}