Skip to content

Commit

Permalink
Add developer CLI flags for tuning encoder internals
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
shssoichiro committed Dec 6, 2022
1 parent a12951c commit 91ca870
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 24 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/rav1e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ on:

jobs:
rustfmt-clippy:

runs-on: ubuntu-22.04

steps:
Expand Down Expand Up @@ -193,7 +192,7 @@ jobs:
- name: Check extra features
if: matrix.toolchain == 'stable' && matrix.conf == 'check-extra-feats'
run: |
cargo check --features=check_asm,capi,dump_lookahead_data,serialize,bench --all-targets
cargo check --features=check_asm,capi,dump_lookahead_data,serialize,bench,devel --all-targets
- name: Check extra features
if: matrix.toolchain == 'stable' && matrix.conf == 'check-unstable-feats'
run: |
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ default-run = "rav1e"

[features]
unstable = []
# Exposes extra flags for tuning compiler internals.
# Intended to be used by developers to find ideal internal settings.
devel = []
channel-api = ["crossbeam"]
decode_test = ["aom-sys"]
decode_test_dav1d = ["dav1d-sys"]
Expand Down
45 changes: 45 additions & 0 deletions src/api/config/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,50 @@ pub struct EncoderConfig {

/// Settings which affect the encoding speed vs. quality trade-off.
pub speed_settings: SpeedSettings,

/// Advanced settings which are intended for use by developers.
/// Non-developers should use the default values.
pub advanced_flags: AdvancedTuning,
}

/// Advanced settings that are intended for use by developers
/// for tuning compiler internals.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct AdvancedTuning {
/// Controls the strength of the deblock filter, as a multiplier to the default.
pub deblock_strength: f32,
/// Controls the sharpness of the deblock filter. Accepts a value from 0-7.
pub deblock_sharpness: u8,
/// Controls the ratio between intra frame and inter frame quantizers, as a multiplier.
/// Default is 1.0. Higher values create a higher quantizer difference, while lower values
/// create a lower quantizer difference. A value of 0.0 would mean that I and P quantizers
/// are the same.
pub ip_ratio: f32,
/// Controls the ratio between "P"-frame and "B"-frame quantizers, as a multiplier.
/// Default is 1.0. Higher values create a higher quantizer difference, while lower values
/// create a lower quantizer difference. A value of 0.0 would mean that P and B quantizers
/// are the same.
pub pb_ratio: f32,
/// Controls the ratio between frame quantizers in the levels of the pyramid betweem "B"-frames,
/// as a multiplier. Default is 1.0. Higher values create a higher quantizer difference,
/// while lower values create a lower quantizer difference. A value of 0.0 would mean that
/// B0 and B1 quantizers are the same.
pub b_ratio: f32,
/// Controls the strength of temporal RDO, as a multiplier to the default.
pub temporal_rdo_strength: f32,
}

impl Default for AdvancedTuning {
fn default() -> Self {
Self {
deblock_strength: 1.0,
deblock_sharpness: 0,
ip_ratio: 1.0,
pb_ratio: 1.0,
b_ratio: 1.0,
temporal_rdo_strength: 1.0,
}
}
}

/// Default preset for `EncoderConfig`: it is a balance between quality and
Expand Down Expand Up @@ -171,6 +215,7 @@ impl EncoderConfig {
tile_rows: 0,
tiles: 0,
speed_settings: SpeedSettings::from_preset(speed),
advanced_flags: Default::default(),
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/api/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2165,6 +2165,7 @@ fn log_q_exp_overflow() {
},
..Default::default()
},
advanced_flags: Default::default(),
};
let config = Config::new().with_encoder_config(enc).with_threads(1);

Expand Down Expand Up @@ -2242,6 +2243,7 @@ fn guess_frame_subtypes_assert() {
},
..Default::default()
},
advanced_flags: Default::default(),
};
let config = Config::new().with_encoder_config(enc).with_threads(1);

Expand Down
62 changes: 61 additions & 1 deletion src/bin/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,53 @@ pub struct CliOptions {
#[clap(long, short, value_parser, help_heading = "DEBUGGING")]
pub reconstruction: Option<PathBuf>,

/// Controls the strength of the deblock filter, as a multiplier to the default.
#[cfg(feature = "devel")]
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
pub deblock_strength: f32,
/// Controls the sharpness of the deblock filter. Accepts a value from 0-7.
#[cfg(feature = "devel")]
#[clap(long, value_parser = clap::value_parser!(u8).range(0..=7), default_value_t=0, help_heading = "ADVANCED")]
pub deblock_sharpness: u8,
/// Controls the ratio between intra frame and inter frame quantizers, as a multiplier.
/// Higher values create a higher quantizer difference, while lower values
/// create a lower quantizer difference. A value of 0.0 would mean that I and P quantizers
/// are the same.
#[cfg(feature = "devel")]
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
pub ip_ratio: f32,
/// Controls the ratio between "P"-frame and "B"-frame quantizers, as a multiplier.
/// Default is 1.0. Higher values create a higher quantizer difference, while lower values
/// create a lower quantizer difference. A value of 0.0 would mean that P and B quantizers
/// are the same.
#[cfg(feature = "devel")]
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
pub pb_ratio: f32,
/// Controls the ratio between frame quantizers in the levels of the pyramid betweem "B"-frames,
/// as a multiplier. Default is 1.0. Higher values create a higher quantizer difference,
/// while lower values create a lower quantizer difference. A value of 0.0 would mean that
/// B0 and B1 quantizers are the same.
#[cfg(feature = "devel")]
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
pub b_ratio: f32,
/// Controls the strength of temporal RDO, as a multiplier to the default.
#[cfg(feature = "devel")]
#[clap(long, value_parser = positive_float, default_value_t=1.0f32, help_heading = "ADVANCED")]
pub temporal_rdo_strength: f32,

#[clap(subcommand)]
pub command: Option<Commands>,
}

#[cfg(feature = "devel")]
fn positive_float(input: &str) -> Result<f32, String> {
let value = input.parse::<f32>().map_err(|e| e.to_string())?;
if value < 0.0 {
return Err("Value must not be negative".to_string());
}
Ok(value)
}

fn get_version() -> &'static str {
static VERSION_STR: Lazy<String> = Lazy::new(|| {
format!(
Expand Down Expand Up @@ -299,7 +342,7 @@ pub enum Commands {
#[clap(long, short, value_parser)]
save_config: Option<PathBuf>,
/// Load the encoder configuration from a toml file
#[clap(long, short, value_parser, conflicts_with = "save-config")]
#[clap(long, short, value_parser, conflicts_with = "save_config")]
load_config: Option<PathBuf>,
},
}
Expand Down Expand Up @@ -484,6 +527,18 @@ pub fn parse_cli() -> Result<ParsedCliOptions, CliError> {
})
}

#[cfg(feature = "devel")]
const fn parse_advanced_flags(cli: &CliOptions) -> AdvancedTuning {
AdvancedTuning {
deblock_strength: cli.deblock_strength,
deblock_sharpness: cli.deblock_sharpness,
ip_ratio: cli.ip_ratio,
pb_ratio: cli.pb_ratio,
b_ratio: cli.b_ratio,
temporal_rdo_strength: cli.temporal_rdo_strength,
}
}

fn parse_config(matches: &CliOptions) -> Result<EncoderConfig, CliError> {
let maybe_quantizer = matches.quantizer;
let maybe_bitrate = matches.bitrate;
Expand Down Expand Up @@ -689,5 +744,10 @@ fn parse_config(matches: &CliOptions) -> Result<EncoderConfig, CliError> {
cfg.speed_settings.scene_detection_mode = SceneDetectionSpeed::None;
}

#[cfg(feature = "devel")]
{
cfg.advanced_flags = parse_advanced_flags(matches);
}

Ok(cfg)
}
20 changes: 18 additions & 2 deletions src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ impl<T: Pixel> FrameState<T> {
cdfs: CDFContext::new(0),
context_update_tile_id: 0,
max_tile_size_bytes: 0,
deblock: Default::default(),
deblock: DeblockState::new(&fi.config, fi.frame_type),
segmentation: Default::default(),
restoration: rs,
frame_me_stats: me_stats,
Expand Down Expand Up @@ -497,7 +497,7 @@ impl<T: Pixel> FrameState<T> {
cdfs: CDFContext::new(0),
context_update_tile_id: 0,
max_tile_size_bytes: 0,
deblock: Default::default(),
deblock: DeblockState::new(&fi.config, fi.frame_type),
segmentation: Default::default(),
restoration: rs,
frame_me_stats: FrameMEStats::new_arc_array(fi.w_in_b, fi.h_in_b),
Expand Down Expand Up @@ -539,6 +539,22 @@ pub struct DeblockState {
pub block_delta_multi: bool,
}

impl DeblockState {
pub fn new(config: &EncoderConfig, frame_type: FrameType) -> Self {
let mut state = DeblockState { ..Default::default() };
if frame_type == FrameType::INTER {
// Apply deblock strength only to inter frames
for level in &mut state.levels {
*level = ((*level as f32) * config.advanced_flags.deblock_strength)
.min(MAX_LOOP_FILTER as f32)
.round() as u8;
}
}
state.sharpness = config.advanced_flags.deblock_sharpness;
state
}
}

impl Default for DeblockState {
fn default() -> Self {
DeblockState {
Expand Down
1 change: 1 addition & 0 deletions src/fuzzing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ impl Arbitrary for ArbitraryEncoder {
switch_frame_interval: u.int_in_range(0..=3)?,
tune: *u.choose(&[Tune::Psnr, Tune::Psychovisual])?,
film_grain_params: None,
advanced_flags: Default::default(),
};

let frame_count =
Expand Down
Loading

0 comments on commit 91ca870

Please sign in to comment.