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) {
aom_dsp_rtcd();
}
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 w = ec::WriterEncoder::new();
let fc = CDFContext::new(fi.base_q_idx);
......@@ -113,7 +113,7 @@ fn cdef_frame(c: &mut Criterion) {
fn cdef_frame_bench(b: &mut Bencher, w: usize, h: usize) {
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 mut bc = BlockContext::new(fi.sb_width * 16, fi.sb_height * 16);
let mut fs = FrameState::new(&fi);
......@@ -135,7 +135,7 @@ fn cfl_rdo(c: &mut Criterion) {
fn cfl_rdo_bench(b: &mut Bencher, bsize: BlockSize) {
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 mut fs = FrameState::new(&fi);
let offset = BlockOffset { x: 1, y: 1 };
......
......@@ -33,16 +33,117 @@ pub struct EncoderConfig {
pub key_frame_interval: u64,
pub low_latency: bool,
pub quantizer: usize,
pub speed: usize,
pub tune: Tune
pub tune: Tune,
pub speed_settings: SpeedSettings,
}
impl Default for EncoderConfig {
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
#[derive(Clone, Copy, Debug)]
pub struct FrameInfo {
......@@ -67,7 +168,7 @@ impl Config {
"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)?,
"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)?,
_ => return Err(InvalidKey)
}
......@@ -182,7 +283,7 @@ impl Context {
let key_frame_interval: u64 = self.fi.config.key_frame_interval;
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 group_src_len = 1 << pyramid_depth;
......
use clap::{App, Arg};
use clap::{App, Arg, ArgMatches};
use rav1e::*;
use std::fmt;
use std::fs::File;
......@@ -101,29 +101,33 @@ pub fn parse_cli() -> CliOptions {
.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 {
io,
enc: config,
enc: parse_config(&matches),
limit: matches.value_of("LIMIT").unwrap().parse().unwrap(),
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)]
pub struct FrameSummary {
/// Frame size in bytes
......
......@@ -1343,7 +1343,7 @@ pub fn deblock_filter_optimize(
fi: &FrameInvariants, fs: &mut FrameState, bc: &mut BlockContext,
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 level = clamp(
match bit_depth {
......
......@@ -467,11 +467,7 @@ impl FrameInvariants {
// 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.
// At speed = 0, RDO search is exhaustive.
let mut min_partition_size = if config.speed <= 1 { BlockSize::BLOCK_4X4 }
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 };
let mut min_partition_size = config.speed_settings.min_block_size;
if config.tune == Tune::Psychovisual {
if min_partition_size < BlockSize::BLOCK_8X8 {
......@@ -480,8 +476,8 @@ impl FrameInvariants {
println!("If tune=Psychovisual is used, min partition size is enforced to 8x8");
}
}
let use_reduced_tx_set = config.speed > 1;
let use_tx_domain_distortion = config.tune == Tune::Psnr && 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_settings.tx_domain_distortion;
FrameInvariants {
width,
......@@ -2275,7 +2271,7 @@ fn encode_tile(sequence: &mut Sequence, fi: &FrameInvariants, fs: &mut FrameStat
}
// Encode SuperBlock
if fi.config.speed == 0 {
if fi.config.speed_settings.encode_bottomup {
encode_partition_bottomup(sequence, fi, fs, &mut cw,
&mut w_pre_cdef, &mut w_post_cdef,
BlockSize::BLOCK_64X64, &bo, &pmvs);
......
......@@ -38,6 +38,7 @@ use FrameType;
use Tune;
use Sequence;
use encoder::ReferenceMode;
use api::PredictionModesSetting;
#[derive(Clone)]
pub struct RDOOutput {
......@@ -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_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(
fi,
fs,
......@@ -356,8 +357,8 @@ pub fn rdo_mode_decision(
// Exclude complex prediction modes at higher speed levels
let intra_mode_set = if (fi.frame_type == FrameType::KEY
&& fi.config.speed <= 3)
|| (fi.frame_type == FrameType::INTER && fi.config.speed <= 1)
&& fi.config.speed_settings.prediction_modes >= PredictionModesSetting::ComplexKeyframes)
|| (fi.frame_type == FrameType::INTER && fi.config.speed_settings.prediction_modes >= PredictionModesSetting::ComplexAll)
{
RAV1E_INTRA_MODES
} else {
......@@ -409,7 +410,7 @@ pub fn rdo_mode_decision(
if mv_stack.len() >= 2 {
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 mv_stack.len() >= 3 {
mode_set.push((PredictionMode::NEAR1MV, i));
......
......@@ -79,7 +79,8 @@ fn setup_encoder(
aom_dsp_rtcd();
}
let enc = EncoderConfig { quantizer, speed, ..Default::default() };
let mut enc = EncoderConfig::with_speed_preset(speed);
enc.quantizer = quantizer;
let cfg = Config {
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