Skip to content

Commit a5222bd

Browse files
committed
Add developer CLI flags for tuning encoder internals
Currently adds the following: - `--deblock-strength` - `--deblock-sharpness` - `--ip-ratio` - `--pb-ratio` - `--b-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 f2c08ff commit a5222bd

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
@@ -114,6 +114,50 @@ pub struct EncoderConfig {
114114

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

119163
/// Default preset for `EncoderConfig`: it is a balance between quality and
@@ -171,6 +215,7 @@ impl EncoderConfig {
171215
tile_rows: 0,
172216
tiles: 0,
173217
speed_settings: SpeedSettings::from_preset(speed),
218+
advanced_flags: Default::default(),
174219
}
175220
}
176221

src/api/test.rs

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

@@ -2242,6 +2243,7 @@ fn guess_frame_subtypes_assert() {
22422243
},
22432244
..Default::default()
22442245
},
2246+
advanced_flags: Default::default(),
22452247
};
22462248
let config = Config::new().with_encoder_config(enc).with_threads(1);
22472249

src/bin/common.rs

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

252+
/// Controls the strength of the deblock filter, as a multiplier to the default.
253+
#[cfg(feature = "devel")]
254+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
255+
pub deblock_strength: f32,
256+
/// Controls the sharpness of the deblock filter. Accepts a value from 0-7.
257+
#[cfg(feature = "devel")]
258+
#[clap(long, value_parser = clap::value_parser!(u8).range(0..=7), default_value_t=0, help_heading = "ADVANCED")]
259+
pub deblock_sharpness: u8,
260+
/// Controls the ratio between intra frame and inter frame quantizers, as a multiplier.
261+
/// Higher values create a higher quantizer difference, while lower values
262+
/// create a lower quantizer difference. A value of 0.0 would mean that I and P 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 ip_ratio: f32,
267+
/// Controls the ratio between "P"-frame and "B"-frame quantizers, as a multiplier.
268+
/// Default is 1.0. Higher values create a higher quantizer difference, while lower values
269+
/// create a lower quantizer difference. A value of 0.0 would mean that P and B quantizers
270+
/// are the same.
271+
#[cfg(feature = "devel")]
272+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
273+
pub pb_ratio: f32,
274+
/// Controls the ratio between frame quantizers in the levels of the pyramid betweem "B"-frames,
275+
/// as a multiplier. Default is 1.0. Higher values create a higher quantizer difference,
276+
/// while lower values create a lower quantizer difference. A value of 0.0 would mean that
277+
/// B0 and B1 quantizers are the same.
278+
#[cfg(feature = "devel")]
279+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
280+
pub b_ratio: f32,
281+
/// Controls the strength of temporal RDO, as a multiplier to the default.
282+
#[cfg(feature = "devel")]
283+
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
284+
pub temporal_rdo_strength: f32,
285+
252286
#[clap(subcommand)]
253287
pub command: Option<Commands>,
254288
}
255289

290+
#[cfg(feature = "devel")]
291+
fn positive_float(input: &str) -> Result<f32, String> {
292+
let value = input.parse::<f32>().map_err(|e| e.to_string())?;
293+
if value < 0.0 {
294+
return Err("Value must not be negative".to_string());
295+
}
296+
Ok(value)
297+
}
298+
256299
fn get_version() -> &'static str {
257300
static VERSION_STR: Lazy<String> = Lazy::new(|| {
258301
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_ratio: cli.ip_ratio,
536+
pb_ratio: cli.pb_ratio,
537+
b_ratio: cli.b_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;
@@ -689,5 +744,10 @@ fn parse_config(matches: &CliOptions) -> Result<EncoderConfig, CliError> {
689744
cfg.speed_settings.scene_detection_mode = SceneDetectionSpeed::None;
690745
}
691746

747+
#[cfg(feature = "devel")]
748+
{
749+
cfg.advanced_flags = parse_advanced_flags(matches);
750+
}
751+
692752
Ok(cfg)
693753
}

src/encoder.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ impl<T: Pixel> FrameState<T> {
466466
cdfs: CDFContext::new(0),
467467
context_update_tile_id: 0,
468468
max_tile_size_bytes: 0,
469-
deblock: Default::default(),
469+
deblock: DeblockState::new(&fi.config, fi.frame_type),
470470
segmentation: Default::default(),
471471
restoration: rs,
472472
frame_me_stats: me_stats,
@@ -497,7 +497,7 @@ impl<T: Pixel> FrameState<T> {
497497
cdfs: CDFContext::new(0),
498498
context_update_tile_id: 0,
499499
max_tile_size_bytes: 0,
500-
deblock: Default::default(),
500+
deblock: DeblockState::new(&fi.config, fi.frame_type),
501501
segmentation: Default::default(),
502502
restoration: rs,
503503
frame_me_stats: FrameMEStats::new_arc_array(fi.w_in_b, fi.h_in_b),
@@ -539,6 +539,22 @@ pub struct DeblockState {
539539
pub block_delta_multi: bool,
540540
}
541541

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

src/fuzzing.rs

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

263264
let frame_count =

0 commit comments

Comments
 (0)