Commit 56de6a44 authored by Josh Holmer's avatar Josh Holmer Committed by Thomas Daede

Refactor speed level to act as an initialization preset

This opens the path to finer control by the user over the encoding
options, and centralizes the speed preset logic in one location.

Closes #290
parent 12737f26
...@@ -47,7 +47,7 @@ fn write_b_bench(b: &mut Bencher, tx_size: TxSize, qindex: usize) { ...@@ -47,7 +47,7 @@ fn write_b_bench(b: &mut Bencher, tx_size: TxSize, qindex: usize) {
aom_dsp_rtcd(); aom_dsp_rtcd();
} }
let config = let config =
EncoderConfig { quantizer: qindex, speed: 10, ..Default::default() }; EncoderConfig { quantizer: qindex, speed_settings: SpeedSettings::from_preset(10), ..Default::default() };
let mut fi = FrameInvariants::new(1024, 1024, config); let mut fi = FrameInvariants::new(1024, 1024, config);
let mut w = ec::WriterEncoder::new(); let mut w = ec::WriterEncoder::new();
let fc = CDFContext::new(fi.base_q_idx); let fc = CDFContext::new(fi.base_q_idx);
...@@ -113,7 +113,7 @@ fn cdef_frame(c: &mut Criterion) { ...@@ -113,7 +113,7 @@ fn cdef_frame(c: &mut Criterion) {
fn cdef_frame_bench(b: &mut Bencher, w: usize, h: usize) { fn cdef_frame_bench(b: &mut Bencher, w: usize, h: usize) {
let config = let config =
EncoderConfig { quantizer: 100, speed: 10, ..Default::default() }; EncoderConfig { quantizer: 100, speed_settings: SpeedSettings::from_preset(10), ..Default::default() };
let fi = FrameInvariants::new(w, h, config); let fi = FrameInvariants::new(w, h, config);
let mut bc = BlockContext::new(fi.sb_width * 16, fi.sb_height * 16); let mut bc = BlockContext::new(fi.sb_width * 16, fi.sb_height * 16);
let mut fs = FrameState::new(&fi); let mut fs = FrameState::new(&fi);
...@@ -135,7 +135,7 @@ fn cfl_rdo(c: &mut Criterion) { ...@@ -135,7 +135,7 @@ fn cfl_rdo(c: &mut Criterion) {
fn cfl_rdo_bench(b: &mut Bencher, bsize: BlockSize) { fn cfl_rdo_bench(b: &mut Bencher, bsize: BlockSize) {
let config = let config =
EncoderConfig { quantizer: 100, speed: 10, ..Default::default() }; EncoderConfig { quantizer: 100, speed_settings: SpeedSettings::from_preset(10), ..Default::default() };
let fi = FrameInvariants::new(1024, 1024, config); let fi = FrameInvariants::new(1024, 1024, config);
let mut fs = FrameState::new(&fi); let mut fs = FrameState::new(&fi);
let offset = BlockOffset { x: 1, y: 1 }; let offset = BlockOffset { x: 1, y: 1 };
......
...@@ -33,16 +33,117 @@ pub struct EncoderConfig { ...@@ -33,16 +33,117 @@ pub struct EncoderConfig {
pub key_frame_interval: u64, pub key_frame_interval: u64,
pub low_latency: bool, pub low_latency: bool,
pub quantizer: usize, pub quantizer: usize,
pub speed: usize, pub tune: Tune,
pub tune: Tune pub speed_settings: SpeedSettings,
} }
impl Default for EncoderConfig { impl Default for EncoderConfig {
fn default() -> Self { fn default() -> Self {
EncoderConfig { key_frame_interval: 30, low_latency: true, quantizer: 100, speed: 0, tune: Tune::Psnr } const DEFAULT_SPEED: usize = 3;
Self::with_speed_preset(DEFAULT_SPEED)
} }
} }
impl EncoderConfig {
pub fn with_speed_preset(speed: usize) -> Self {
EncoderConfig {
key_frame_interval: 30,
low_latency: true,
quantizer: 100,
tune: Tune::Psnr,
speed_settings: SpeedSettings::from_preset(speed)
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct SpeedSettings {
pub min_block_size: BlockSize,
pub multiref: bool,
pub fast_deblock: bool,
pub reduced_tx_set: bool,
pub tx_domain_distortion: bool,
pub encode_bottomup: bool,
pub rdo_tx_decision: bool,
pub prediction_modes: PredictionModesSetting,
pub include_near_mvs: bool,
}
impl SpeedSettings {
pub fn from_preset(speed: usize) -> Self {
SpeedSettings {
min_block_size: Self::min_block_size_preset(speed),
multiref: Self::multiref_preset(speed),
fast_deblock: Self::fast_deblock_preset(speed),
reduced_tx_set: Self::reduced_tx_set_preset(speed),
tx_domain_distortion: Self::tx_domain_distortion_preset(speed),
encode_bottomup: Self::encode_bottomup_preset(speed),
rdo_tx_decision: Self::rdo_tx_decision_preset(speed),
prediction_modes: Self::prediction_modes_preset(speed),
include_near_mvs: Self::include_near_mvs_preset(speed),
}
}
fn min_block_size_preset(speed: usize) -> BlockSize {
if speed <= 1 {
BlockSize::BLOCK_4X4
} else if speed <= 2 {
BlockSize::BLOCK_8X8
} else if speed <= 3 {
BlockSize::BLOCK_16X16
} else if speed <= 4 {
BlockSize::BLOCK_32X32
} else {
BlockSize::BLOCK_64X64
}
}
fn multiref_preset(speed: usize) -> bool {
speed <= 2
}
fn fast_deblock_preset(speed: usize) -> bool {
speed >= 4
}
fn reduced_tx_set_preset(speed: usize) -> bool {
speed >= 2
}
fn tx_domain_distortion_preset(speed: usize) -> bool {
speed >= 1
}
fn encode_bottomup_preset(speed: usize) -> bool {
speed == 0
}
fn rdo_tx_decision_preset(speed: usize) -> bool {
speed <= 3
}
fn prediction_modes_preset(speed: usize) -> PredictionModesSetting {
if speed <= 1 {
PredictionModesSetting::ComplexAll
} else if speed <= 3 {
PredictionModesSetting::ComplexKeyframes
} else {
PredictionModesSetting::Simple
}
}
fn include_near_mvs_preset(speed: usize) -> bool {
speed <= 2
}
}
#[derive(Clone, Copy, Debug, PartialOrd, PartialEq)]
pub enum PredictionModesSetting {
Simple,
ComplexKeyframes,
ComplexAll,
}
/// Frame-specific information /// Frame-specific information
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct FrameInfo { pub struct FrameInfo {
...@@ -67,7 +168,7 @@ impl Config { ...@@ -67,7 +168,7 @@ impl Config {
"low_latency" => self.enc.low_latency = value.parse().map_err(|_e| ParseError)?, "low_latency" => self.enc.low_latency = value.parse().map_err(|_e| ParseError)?,
"key_frame_interval" => self.enc.key_frame_interval = value.parse().map_err(|_e| ParseError)?, "key_frame_interval" => self.enc.key_frame_interval = value.parse().map_err(|_e| ParseError)?,
"quantizer" => self.enc.quantizer = value.parse().map_err(|_e| ParseError)?, "quantizer" => self.enc.quantizer = value.parse().map_err(|_e| ParseError)?,
"speed" => self.enc.speed = value.parse().map_err(|_e| ParseError)?, "speed" => self.enc.speed_settings = SpeedSettings::from_preset(value.parse().map_err(|_e| ParseError)?),
"tune" => self.enc.tune = value.parse().map_err(|_e| ParseError)?, "tune" => self.enc.tune = value.parse().map_err(|_e| ParseError)?,
_ => return Err(InvalidKey) _ => return Err(InvalidKey)
} }
...@@ -182,7 +283,7 @@ impl Context { ...@@ -182,7 +283,7 @@ impl Context {
let key_frame_interval: u64 = self.fi.config.key_frame_interval; let key_frame_interval: u64 = self.fi.config.key_frame_interval;
let reorder = !self.fi.config.low_latency; let reorder = !self.fi.config.low_latency;
let multiref = reorder || self.fi.config.speed <= 2; let multiref = reorder || self.fi.config.speed_settings.multiref;
let pyramid_depth = if reorder { 2 } else { 0 }; let pyramid_depth = if reorder { 2 } else { 0 };
let group_src_len = 1 << pyramid_depth; let group_src_len = 1 << pyramid_depth;
......
use clap::{App, Arg}; use clap::{App, Arg, ArgMatches};
use rav1e::*; use rav1e::*;
use std::fmt; use std::fmt;
use std::fs::File; use std::fs::File;
...@@ -101,29 +101,33 @@ pub fn parse_cli() -> CliOptions { ...@@ -101,29 +101,33 @@ pub fn parse_cli() -> CliOptions {
.map(|f| Box::new(File::create(&f).unwrap()) as Box<dyn Write>) .map(|f| Box::new(File::create(&f).unwrap()) as Box<dyn Write>)
}; };
let config = EncoderConfig {
key_frame_interval: matches.value_of("KEYFRAME_INTERVAL").unwrap().parse().unwrap(),
low_latency: matches.value_of("LOW_LATENCY").unwrap().parse().unwrap(),
quantizer: matches.value_of("QP").unwrap().parse().unwrap(),
speed: matches.value_of("SPEED").unwrap().parse().unwrap(),
tune: matches.value_of("TUNE").unwrap().parse().unwrap()
};
// Validate arguments
if config.quantizer == 0 {
unimplemented!();
} else if config.quantizer > 255 || config.speed > 10 {
panic!("argument out of range");
}
CliOptions { CliOptions {
io, io,
enc: config, enc: parse_config(&matches),
limit: matches.value_of("LIMIT").unwrap().parse().unwrap(), limit: matches.value_of("LIMIT").unwrap().parse().unwrap(),
verbose: matches.is_present("VERBOSE"), verbose: matches.is_present("VERBOSE"),
} }
} }
fn parse_config(matches: &ArgMatches) -> EncoderConfig {
let speed = matches.value_of("SPEED").unwrap().parse().unwrap();
let quantizer = matches.value_of("QP").unwrap().parse().unwrap();
// Validate arguments
if quantizer == 0 {
unimplemented!("Lossless encoding not yet implemented");
} else if quantizer > 255 || speed > 10 {
panic!("argument out of range");
}
let mut cfg = EncoderConfig::with_speed_preset(speed);
cfg.key_frame_interval = matches.value_of("KEYFRAME_INTERVAL").unwrap().parse().unwrap();
cfg.low_latency = matches.value_of("LOW_LATENCY").unwrap().parse().unwrap();
cfg.tune = matches.value_of("TUNE").unwrap().parse().unwrap();
cfg.quantizer = quantizer;
cfg
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct FrameSummary { pub struct FrameSummary {
/// Frame size in bytes /// Frame size in bytes
......
...@@ -1343,7 +1343,7 @@ pub fn deblock_filter_optimize( ...@@ -1343,7 +1343,7 @@ pub fn deblock_filter_optimize(
fi: &FrameInvariants, fs: &mut FrameState, bc: &mut BlockContext, fi: &FrameInvariants, fs: &mut FrameState, bc: &mut BlockContext,
bit_depth: usize bit_depth: usize
) { ) {
if fi.config.speed > 3 { if fi.config.speed_settings.fast_deblock {
let q = ac_q(fi.base_q_idx, bit_depth) as i32; let q = ac_q(fi.base_q_idx, bit_depth) as i32;
let level = clamp( let level = clamp(
match bit_depth { match bit_depth {
......
...@@ -467,11 +467,7 @@ impl FrameInvariants { ...@@ -467,11 +467,7 @@ impl FrameInvariants {
// Speed level decides the minimum partition size, i.e. higher speed --> larger min partition size, // Speed level decides the minimum partition size, i.e. higher speed --> larger min partition size,
// with exception that SBs on right or bottom frame borders split down to BLOCK_4X4. // with exception that SBs on right or bottom frame borders split down to BLOCK_4X4.
// At speed = 0, RDO search is exhaustive. // At speed = 0, RDO search is exhaustive.
let mut min_partition_size = if config.speed <= 1 { BlockSize::BLOCK_4X4 } let mut min_partition_size = config.speed_settings.min_block_size;
else if config.speed <= 2 { BlockSize::BLOCK_8X8 }
else if config.speed <= 3 { BlockSize::BLOCK_16X16 }
else if config.speed <= 4 { BlockSize::BLOCK_32X32 }
else { BlockSize::BLOCK_64X64 };
if config.tune == Tune::Psychovisual { if config.tune == Tune::Psychovisual {
if min_partition_size < BlockSize::BLOCK_8X8 { if min_partition_size < BlockSize::BLOCK_8X8 {
...@@ -480,8 +476,8 @@ impl FrameInvariants { ...@@ -480,8 +476,8 @@ impl FrameInvariants {
println!("If tune=Psychovisual is used, min partition size is enforced to 8x8"); println!("If tune=Psychovisual is used, min partition size is enforced to 8x8");
} }
} }
let use_reduced_tx_set = config.speed > 1; let use_reduced_tx_set = config.speed_settings.reduced_tx_set;
let use_tx_domain_distortion = config.tune == Tune::Psnr && config.speed >= 1; let use_tx_domain_distortion = config.tune == Tune::Psnr && config.speed_settings.tx_domain_distortion;
FrameInvariants { FrameInvariants {
width, width,
...@@ -2275,7 +2271,7 @@ fn encode_tile(sequence: &mut Sequence, fi: &FrameInvariants, fs: &mut FrameStat ...@@ -2275,7 +2271,7 @@ fn encode_tile(sequence: &mut Sequence, fi: &FrameInvariants, fs: &mut FrameStat
} }
// Encode SuperBlock // Encode SuperBlock
if fi.config.speed == 0 { if fi.config.speed_settings.encode_bottomup {
encode_partition_bottomup(sequence, fi, fs, &mut cw, encode_partition_bottomup(sequence, fi, fs, &mut cw,
&mut w_pre_cdef, &mut w_post_cdef, &mut w_pre_cdef, &mut w_post_cdef,
BlockSize::BLOCK_64X64, &bo, &pmvs); BlockSize::BLOCK_64X64, &bo, &pmvs);
......
...@@ -38,6 +38,7 @@ use FrameType; ...@@ -38,6 +38,7 @@ use FrameType;
use Tune; use Tune;
use Sequence; use Sequence;
use encoder::ReferenceMode; use encoder::ReferenceMode;
use api::PredictionModesSetting;
#[derive(Clone)] #[derive(Clone)]
pub struct RDOOutput { pub struct RDOOutput {
...@@ -289,7 +290,7 @@ pub fn rdo_tx_size_type( ...@@ -289,7 +290,7 @@ pub fn rdo_tx_size_type(
let tx_set = get_tx_set(tx_size, is_inter, fi.use_reduced_tx_set); let tx_set = get_tx_set(tx_size, is_inter, fi.use_reduced_tx_set);
let tx_type = let tx_type =
if tx_set > TxSet::TX_SET_DCTONLY && fi.config.speed <= 3 && !skip { if tx_set > TxSet::TX_SET_DCTONLY && fi.config.speed_settings.rdo_tx_decision && !skip {
rdo_tx_type_decision( rdo_tx_type_decision(
fi, fi,
fs, fs,
...@@ -356,8 +357,8 @@ pub fn rdo_mode_decision( ...@@ -356,8 +357,8 @@ pub fn rdo_mode_decision(
// Exclude complex prediction modes at higher speed levels // Exclude complex prediction modes at higher speed levels
let intra_mode_set = if (fi.frame_type == FrameType::KEY let intra_mode_set = if (fi.frame_type == FrameType::KEY
&& fi.config.speed <= 3) && fi.config.speed_settings.prediction_modes >= PredictionModesSetting::ComplexKeyframes)
|| (fi.frame_type == FrameType::INTER && fi.config.speed <= 1) || (fi.frame_type == FrameType::INTER && fi.config.speed_settings.prediction_modes >= PredictionModesSetting::ComplexAll)
{ {
RAV1E_INTRA_MODES RAV1E_INTRA_MODES
} else { } else {
...@@ -409,7 +410,7 @@ pub fn rdo_mode_decision( ...@@ -409,7 +410,7 @@ pub fn rdo_mode_decision(
if mv_stack.len() >= 2 { if mv_stack.len() >= 2 {
mode_set.push((PredictionMode::GLOBALMV, i)); mode_set.push((PredictionMode::GLOBALMV, i));
} }
let include_near_mvs = fi.config.speed <= 2; let include_near_mvs = fi.config.speed_settings.include_near_mvs;
if include_near_mvs { if include_near_mvs {
if mv_stack.len() >= 3 { if mv_stack.len() >= 3 {
mode_set.push((PredictionMode::NEAR1MV, i)); mode_set.push((PredictionMode::NEAR1MV, i));
......
...@@ -79,7 +79,8 @@ fn setup_encoder( ...@@ -79,7 +79,8 @@ fn setup_encoder(
aom_dsp_rtcd(); aom_dsp_rtcd();
} }
let enc = EncoderConfig { quantizer, speed, ..Default::default() }; let mut enc = EncoderConfig::with_speed_preset(speed);
enc.quantizer = quantizer;
let cfg = Config { let cfg = Config {
frame_info: FrameInfo { width: w, height: h, bit_depth, chroma_sampling }, frame_info: FrameInfo { width: w, height: h, bit_depth, chroma_sampling },
......
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