Unverified Commit 924a9999 authored by Josh Holmer's avatar Josh Holmer Committed by GitHub

Rebalance speed levels based on benchmarks (#1033)

Makes use of all 10 speed levels, and updates the CLI help text to
reflect which settings are enabled at specific speed levels.

This also changes the default speed level to 5.
parent 5fb15129
......@@ -82,7 +82,7 @@ pub struct EncoderConfig {
impl Default for EncoderConfig {
fn default() -> Self {
const DEFAULT_SPEED: usize = 3;
const DEFAULT_SPEED: usize = 5;
Self::with_speed_preset(DEFAULT_SPEED)
}
}
......@@ -166,34 +166,37 @@ impl SpeedSettings {
}
}
/// This preset is set this way because 8x8 with reduced TX set is faster but with equivalent
/// or better quality compared to 16x16 or 32x32 (to which reduced TX set does not apply).
fn min_block_size_preset(speed: usize) -> BlockSize {
if speed <= 1 {
if speed == 0 {
BlockSize::BLOCK_4X4
} else if speed <= 2 {
} else if speed <= 8 {
BlockSize::BLOCK_8X8
} else if speed <= 3 {
BlockSize::BLOCK_16X16
} else if speed <= 4 {
BlockSize::BLOCK_32X32
} else {
BlockSize::BLOCK_64X64
}
}
/// Multiref is enabled automatically if low_latency is false,
/// but if someone is setting low_latency to true manually,
/// multiref has a large speed penalty with low quality gain.
/// Because low_latency can be set manually, this setting is conservative.
fn multiref_preset(speed: usize) -> bool {
speed <= 2
speed <= 1
}
fn fast_deblock_preset(speed: usize) -> bool {
speed >= 4
speed >= 8
}
fn reduced_tx_set_preset(speed: usize) -> bool {
speed >= 2
speed >= 5
}
fn tx_domain_distortion_preset(speed: usize) -> bool {
speed >= 4
/// TX domain distortion is always faster, with no significant quality change
fn tx_domain_distortion_preset(_speed: usize) -> bool {
true
}
fn encode_bottomup_preset(speed: usize) -> bool {
......@@ -207,7 +210,7 @@ impl SpeedSettings {
fn prediction_modes_preset(speed: usize) -> PredictionModesSetting {
if speed <= 1 {
PredictionModesSetting::ComplexAll
} else if speed <= 3 {
} else if speed <= 5 {
PredictionModesSetting::ComplexKeyframes
} else {
PredictionModesSetting::Simple
......@@ -222,8 +225,13 @@ impl SpeedSettings {
speed == 10
}
fn diamond_me_preset(speed: usize) -> bool {
speed >= 3
/// Currently Diamond ME gives better quality than full search on most videos,
/// in addition to being faster.
/// There are a few outliers, such as the Wikipedia test clip.
///
/// TODO: Revisit this setting if full search quality improves in the future.
fn diamond_me_preset(_speed: usize) -> bool {
true
}
}
......
......@@ -37,6 +37,9 @@ pub fn parse_cli() -> CliOptions {
.about("AV1 video encoder")
.setting(AppSettings::DeriveDisplayOrder)
.setting(AppSettings::SubcommandsNegateReqs)
.arg(Arg::with_name("FULLHELP")
.help("Prints more detailed help information")
.long("fullhelp"))
// THREADS
.arg(
Arg::with_name("THREADS")
......@@ -49,7 +52,7 @@ pub fn parse_cli() -> CliOptions {
.arg(
Arg::with_name("INPUT")
.help("Uncompressed YUV4MPEG2 video input")
.required(true)
.required_unless("FULLHELP")
.index(1)
)
.arg(
......@@ -57,7 +60,7 @@ pub fn parse_cli() -> CliOptions {
.help("Compressed AV1 in IVF video output")
.short("o")
.long("output")
.required(true)
.required_unless("FULLHELP")
.takes_value(true)
)
.arg(
......@@ -99,11 +102,36 @@ pub fn parse_cli() -> CliOptions {
)
.arg(
Arg::with_name("SPEED")
.help("Speed level (0 is best quality, 10 is fastest)")
.help("Speed level (0 is best quality, 10 is fastest)\n\
Speeds 10 and 0 are extremes and are generally not recommended")
.long_help("Speed level (0 is best quality, 10 is fastest)\n\
Speeds 10 and 0 are extremes and are generally not recommended\n\
- 10 (fastest):\n\
Min block size 64x64, TX domain distortion, fast deblock, no scenechange detection\n\
- 9:\n\
Min block size 64x64, TX domain distortion, fast deblock\n\
- 8:\n\
Min block size 8x8, reduced TX set, TX domain distortion, fast deblock\n\
- 7:\n\
Min block size 8x8, reduced TX set, TX domain distortion\n\
- 6:\n\
Min block size 8x8, reduced TX set, TX domain distortion\n\
- 5 (default):\n\
Min block size 8x8, reduced TX set, TX domain distortion, complex pred modes for keyframes\n\
- 4:\n\
Min block size 8x8, TX domain distortion, complex pred modes for keyframes\n\
- 3:\n\
Min block size 8x8, TX domain distortion, complex pred modes for keyframes, RDO TX decision\n\
- 2:\n\
Min block size 8x8, TX domain distortion, complex pred modes for keyframes, RDO TX decision, include near MVs\n\
- 1:\n\
Min block size 8x8, TX domain distortion, complex pred modes, RDO TX decision, include near MVs\n\
- 0 (slowest):\n\
Min block size 4x4, TX domain distortion, complex pred modes, RDO TX decision, include near MVs, bottom-up encoding\n")
.short("s")
.long("speed")
.takes_value(true)
.default_value("3")
.default_value("5")
)
.arg(
Arg::with_name("MIN_KEYFRAME_INTERVAL")
......@@ -123,7 +151,8 @@ pub fn parse_cli() -> CliOptions {
)
.arg(
Arg::with_name("LOW_LATENCY")
.help("Low latency mode; disables frame reordering")
.help("Low latency mode; disables frame reordering\n\
Has a significant speed-to-quality trade-off")
.long("low_latency")
.takes_value(true)
.default_value("false")
......@@ -207,23 +236,6 @@ pub fn parse_cli() -> CliOptions {
.hidden(true)
.long("speed-test")
.takes_value(true)
.possible_values(&[
"baseline",
"min_block_size_4x4",
"min_block_size_8x8",
"min_block_size_32x32",
"min_block_size_64x64",
"multiref",
"fast_deblock",
"reduced_tx_set",
"tx_domain_distortion",
"encode_bottomup",
"rdo_tx_decision",
"prediction_modes_keyframes",
"prediction_modes_all",
"include_near_mvs",
"no_scene_detection",
])
)
.subcommand(SubCommand::with_name("advanced")
.setting(AppSettings::Hidden)
......@@ -239,6 +251,11 @@ pub fn parse_cli() -> CliOptions {
let matches = app.clone().get_matches();
if matches.is_present("FULLHELP") {
app.print_long_help().unwrap();
std::process::exit(0);
}
if let Some(threads) = matches.value_of("THREADS").map(|v| v.parse().expect("Threads must be an integer")) {
rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap();
}
......@@ -447,6 +464,9 @@ fn apply_speed_test_cfg(cfg: &mut EncoderConfig, setting: &str) {
"no_scene_detection" => {
cfg.speed_settings.no_scene_detection = true;
},
"diamond_me" => {
cfg.speed_settings.diamond_me = true;
}
setting => {
panic!("Unrecognized speed test setting {}", setting);
}
......
......@@ -175,7 +175,7 @@ test_dimensions!{
fn dimension(w: usize, h: usize) {
let quantizer = 100;
let limit = 1;
let speed = 4;
let speed = 10;
encode_decode(w, h, speed, quantizer, limit, 8, Default::default(), 15, 15, true, 0);
}
......@@ -185,7 +185,7 @@ fn quantizer() {
let limit = 5;
let w = 64;
let h = 80;
let speed = 4;
let speed = 10;
for b in DIMENSION_OFFSETS.iter() {
for &q in [80, 100, 120].iter() {
......@@ -199,7 +199,7 @@ fn bitrate() {
let limit = 5;
let w = 64;
let h = 80;
let speed = 4;
let speed = 10;
for &q in [172, 220, 252, 255].iter() {
for &r in [100, 1000, 10_000].iter() {
......@@ -213,7 +213,7 @@ fn keyframes() {
let limit = 12;
let w = 64;
let h = 80;
let speed = 10;
let speed = 9;
let q = 100;
encode_decode(w, h, speed, q, limit, 8, Default::default(), 6, 6, true, 0);
......@@ -258,13 +258,16 @@ fn odd_size_frame_with_full_rdo() {
}
#[test]
fn high_bd() {
fn all_bit_depths() {
let quantizer = 100;
let limit = 3; // Include inter frames
let speed = 0; // Test as many tools as possible
let w = 64;
let h = 80;
// 8-bit
encode_decode(w, h, speed, quantizer, limit, 8, Default::default(), 15, 15, true, 0);
// 10-bit
encode_decode(w, h, speed, quantizer, limit, 10, Default::default(), 15, 15, true, 0);
......@@ -282,6 +285,9 @@ fn chroma_sampling() {
// TODO: bump keyint when inter is supported
// 4:2:0
encode_decode(w, h, speed, quantizer, limit, 8, ChromaSampling::Cs420, 1, 1, true, 0);
// 4:2:2
encode_decode(w, h, speed, quantizer, limit, 8, ChromaSampling::Cs422, 1, 1, true, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment