Skip to content

Commit f37702c

Browse files
committed
Add developer CLI flags for tuning encoder internals
Currently adds the following: - `--deblock-strength` - `--deblock-sharpness` - `--ip-qidx-ratio` - `--pb-qidx-ratio` - `--b-qidx-ratio` - `--temporal-rdo-strength` These flags will be available only if the `devel` feature flag is active, as they are intended to be used to ease development and not to be tweaked by end users. rav1e continues to subscribe to the philosophy that end users should not need to be cargo culting their command lines to get optimal results, and we would prefer to tune the encoder internals so that users do not have to.
1 parent f869e16 commit f37702c

File tree

9 files changed

+212
-24
lines changed

9 files changed

+212
-24
lines changed

.github/workflows/rav1e.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ on:
1212

1313
jobs:
1414
rustfmt-clippy:
15-
1615
runs-on: ubuntu-22.04
1716

1817
steps:
@@ -193,7 +192,7 @@ jobs:
193192
- name: Check extra features
194193
if: matrix.toolchain == 'stable' && matrix.conf == 'check-extra-feats'
195194
run: |
196-
cargo check --features=check_asm,capi,dump_lookahead_data,serialize,bench --all-targets
195+
cargo check --features=check_asm,capi,dump_lookahead_data,serialize,bench,devel --all-targets
197196
- name: Check extra features
198197
if: matrix.toolchain == 'stable' && matrix.conf == 'check-unstable-feats'
199198
run: |

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ default-run = "rav1e"
2424

2525
[features]
2626
unstable = []
27+
# Exposes extra flags for tuning compiler internals.
28+
# Intended to be used by developers to find ideal internal settings.
29+
devel = []
2730
channel-api = ["crossbeam"]
2831
decode_test = ["aom-sys"]
2932
decode_test_dav1d = ["dav1d-sys"]

src/api/config/encoder.rs

+45
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,50 @@ pub struct EncoderConfig {
108108

109109
/// Settings which affect the encoding speed vs. quality trade-off.
110110
pub speed_settings: SpeedSettings,
111+
112+
/// Advanced settings which are intended for use by developers.
113+
/// Non-developers should use the default values.
114+
pub advanced_flags: AdvancedTuning,
115+
}
116+
117+
/// Advanced settings that are intended for use by developers
118+
/// for tuning compiler internals.
119+
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
120+
pub struct AdvancedTuning {
121+
/// Controls the strength of the deblock filter, as a multiplier to the default.
122+
pub deblock_strength: f32,
123+
/// Controls the sharpness of the deblock filter. Accepts a value from 0-7.
124+
pub deblock_sharpness: u8,
125+
/// Controls the ratio between intra frame and inter frame quantizers, as a multiplier.
126+
/// Default is 1.0. Higher values create a higher quantizer difference, while lower values
127+
/// create a lower quantizer difference. A value of 0.0 would mean that I and P quantizers
128+
/// are the same.
129+
pub ip_qidx_ratio: f32,
130+
/// Controls the ratio between "P"-frame and "B"-frame quantizers, as a multiplier.
131+
/// Default is 1.0. Higher values create a higher quantizer difference, while lower values
132+
/// create a lower quantizer difference. A value of 0.0 would mean that P and B quantizers
133+
/// are the same.
134+
pub pb_qidx_ratio: f32,
135+
/// Controls the ratio between frame quantizers in the levels of the pyramid betweem "B"-frames,
136+
/// as a multiplier. Default is 1.0. Higher values create a higher quantizer difference,
137+
/// while lower values create a lower quantizer difference. A value of 0.0 would mean that
138+
/// B0 and B1 quantizers are the same.
139+
pub b_qidx_ratio: f32,
140+
/// Controls the strength of temporal RDO, as a multiplier to the default.
141+
pub temporal_rdo_strength: f32,
142+
}
143+
144+
impl Default for AdvancedTuning {
145+
fn default() -> Self {
146+
Self {
147+
deblock_strength: 1.0,
148+
deblock_sharpness: 0,
149+
ip_qidx_ratio: 1.0,
150+
pb_qidx_ratio: 1.0,
151+
b_qidx_ratio: 1.0,
152+
temporal_rdo_strength: 1.0,
153+
}
154+
}
111155
}
112156

113157
/// Default preset for `EncoderConfig`: it is a balance between quality and
@@ -163,6 +207,7 @@ impl EncoderConfig {
163207
tile_rows: 0,
164208
tiles: 0,
165209
speed_settings: SpeedSettings::from_preset(speed),
210+
advanced_flags: Default::default(),
166211
}
167212
}
168213

src/api/test.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2164,6 +2164,7 @@ fn log_q_exp_overflow() {
21642164
},
21652165
..Default::default()
21662166
},
2167+
advanced_flags: Default::default(),
21672168
};
21682169
let config = Config::new().with_encoder_config(enc).with_threads(1);
21692170

@@ -2240,6 +2241,7 @@ fn guess_frame_subtypes_assert() {
22402241
},
22412242
..Default::default()
22422243
},
2244+
advanced_flags: Default::default(),
22432245
};
22442246
let config = Config::new().with_encoder_config(enc).with_threads(1);
22452247

src/bin/common.rs

+61-1
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,53 @@ pub struct CliOptions {
242242
#[clap(long, short, value_parser, help_heading = "DEBUGGING")]
243243
pub reconstruction: Option<PathBuf>,
244244

245+
/// Controls the strength of the deblock filter, as a multiplier to the default.
246+
#[cfg(feature = "devel")]
247+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
248+
pub deblock_strength: f32,
249+
/// Controls the sharpness of the deblock filter. Accepts a value from 0-7.
250+
#[cfg(feature = "devel")]
251+
#[clap(long, value_parser = clap::value_parser!(u8).range(0..=7), default_value_t=0, help_heading = "ADVANCED")]
252+
pub deblock_sharpness: u8,
253+
/// Controls the ratio between intra frame and inter frame quantizers, as a multiplier.
254+
/// Higher values create a higher quantizer difference, while lower values
255+
/// create a lower quantizer difference. A value of 0.0 would mean that I and P quantizers
256+
/// are the same.
257+
#[cfg(feature = "devel")]
258+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
259+
pub ip_qidx_ratio: f32,
260+
/// Controls the ratio between "P"-frame and "B"-frame quantizers, as a multiplier.
261+
/// Default is 1.0. Higher values create a higher quantizer difference, while lower values
262+
/// create a lower quantizer difference. A value of 0.0 would mean that P and B quantizers
263+
/// are the same.
264+
#[cfg(feature = "devel")]
265+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
266+
pub pb_qidx_ratio: f32,
267+
/// Controls the ratio between frame quantizers in the levels of the pyramid betweem "B"-frames,
268+
/// as a multiplier. Default is 1.0. Higher values create a higher quantizer difference,
269+
/// while lower values create a lower quantizer difference. A value of 0.0 would mean that
270+
/// B0 and B1 quantizers are the same.
271+
#[cfg(feature = "devel")]
272+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
273+
pub b_qidx_ratio: f32,
274+
/// Controls the strength of temporal RDO, as a multiplier to the default.
275+
#[cfg(feature = "devel")]
276+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
277+
pub temporal_rdo_strength: f32,
278+
245279
#[clap(subcommand)]
246280
pub command: Option<Commands>,
247281
}
248282

283+
#[cfg(feature = "devel")]
284+
fn positive_float(input: &str) -> Result<f32, String> {
285+
let value = input.parse::<f32>().map_err(|e| e.to_string())?;
286+
if value < 0.0 {
287+
return Err("Value must not be negative".to_string());
288+
}
289+
Ok(value)
290+
}
291+
249292
fn get_version() -> &'static str {
250293
static VERSION_STR: Lazy<String> = Lazy::new(|| {
251294
format!(
@@ -299,7 +342,7 @@ pub enum Commands {
299342
#[clap(long, short, value_parser)]
300343
save_config: Option<PathBuf>,
301344
/// Load the encoder configuration from a toml file
302-
#[clap(long, short, value_parser, conflicts_with = "save-config")]
345+
#[clap(long, short, value_parser, conflicts_with = "save_config")]
303346
load_config: Option<PathBuf>,
304347
},
305348
}
@@ -484,6 +527,18 @@ pub fn parse_cli() -> Result<ParsedCliOptions, CliError> {
484527
})
485528
}
486529

530+
#[cfg(feature = "devel")]
531+
const fn parse_advanced_flags(cli: &CliOptions) -> AdvancedTuning {
532+
AdvancedTuning {
533+
deblock_strength: cli.deblock_strength,
534+
deblock_sharpness: cli.deblock_sharpness,
535+
ip_qidx_ratio: cli.ip_qidx_ratio,
536+
pb_qidx_ratio: cli.pb_qidx_ratio,
537+
b_qidx_ratio: cli.b_qidx_ratio,
538+
temporal_rdo_strength: cli.temporal_rdo_strength,
539+
}
540+
}
541+
487542
fn parse_config(matches: &CliOptions) -> Result<EncoderConfig, CliError> {
488543
let maybe_quantizer = matches.quantizer;
489544
let maybe_bitrate = matches.bitrate;
@@ -674,5 +729,10 @@ fn parse_config(matches: &CliOptions) -> Result<EncoderConfig, CliError> {
674729
cfg.speed_settings.scene_detection_mode = SceneDetectionSpeed::None;
675730
}
676731

732+
#[cfg(feature = "devel")]
733+
{
734+
cfg.advanced_flags = parse_advanced_flags(matches);
735+
}
736+
677737
Ok(cfg)
678738
}

src/encoder.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ impl<T: Pixel> FrameState<T> {
470470
cdfs: CDFContext::new(0),
471471
context_update_tile_id: 0,
472472
max_tile_size_bytes: 0,
473-
deblock: Default::default(),
473+
deblock: DeblockState::new(&fi.config, fi.frame_type),
474474
segmentation: Default::default(),
475475
restoration: rs,
476476
frame_me_stats: me_stats,
@@ -501,7 +501,7 @@ impl<T: Pixel> FrameState<T> {
501501
cdfs: CDFContext::new(0),
502502
context_update_tile_id: 0,
503503
max_tile_size_bytes: 0,
504-
deblock: Default::default(),
504+
deblock: DeblockState::new(&fi.config, fi.frame_type),
505505
segmentation: Default::default(),
506506
restoration: rs,
507507
frame_me_stats: FrameMEStats::new_arc_array(fi.w_in_b, fi.h_in_b),
@@ -543,6 +543,22 @@ pub struct DeblockState {
543543
pub block_delta_multi: bool,
544544
}
545545

546+
impl DeblockState {
547+
pub fn new(config: &EncoderConfig, frame_type: FrameType) -> Self {
548+
let mut state = DeblockState { ..Default::default() };
549+
if frame_type == FrameType::INTER {
550+
// Apply deblock strength only to inter frames
551+
for level in &mut state.levels {
552+
*level = ((*level as f32) * config.advanced_flags.deblock_strength)
553+
.min(MAX_LOOP_FILTER as f32)
554+
.round() as u8;
555+
}
556+
}
557+
state.sharpness = config.advanced_flags.deblock_sharpness;
558+
state
559+
}
560+
}
561+
546562
impl Default for DeblockState {
547563
fn default() -> Self {
548564
DeblockState {

src/fuzzing.rs

+1
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ impl Arbitrary for ArbitraryEncoder {
257257
switch_frame_interval: u.int_in_range(0..=3)?,
258258
tune: *u.choose(&[Tune::Psnr, Tune::Psychovisual])?,
259259
film_grain_params: None,
260+
advanced_flags: Default::default(),
260261
};
261262

262263
let frame_count =

0 commit comments

Comments
 (0)