Commit a6132e1b authored by Timothy B. Terriberry's avatar Timothy B. Terriberry Committed by David Michael Barr

Compute and store lambda in the FrameInvariants.

Instead of calculating it on the fly from the quantizer wherever it
 happens to be needed.
This will allow us to choose lambda with more precision than a
 single quantizer step size later on, for more precise rate
 targeting.

This results in no change in quality.
parent 153fabf5
......@@ -576,6 +576,8 @@ pub struct FrameInvariants {
pub base_q_idx: u8,
pub dc_delta_q: [i8; 3],
pub ac_delta_q: [i8; 3],
pub lambda: f64,
pub me_lambda: f64,
pub me_range_scale: u8,
pub use_tx_domain_distortion: bool,
pub inter_cfg: Option<InterPropsConfig>,
......@@ -639,6 +641,8 @@ impl FrameInvariants {
base_q_idx: config.quantizer as u8,
dc_delta_q: [0; 3],
ac_delta_q: [0; 3],
lambda: 0.0,
me_lambda: 0.0,
me_range_scale: 1,
use_tx_domain_distortion,
inter_cfg: None,
......@@ -657,8 +661,9 @@ impl FrameInvariants {
fi.show_existing_frame = false;
fi.frame_to_show_map_idx = 0;
let q_boost = 15;
fi.base_q_idx = (fi.config.quantizer.max(1 + q_boost).min(255 + q_boost) - q_boost) as u8;
fi.cdef_bits = 3;
let qi = (fi.config.quantizer.max(1 + q_boost).min(255 + q_boost)
- q_boost) as u8;
fi.set_quantizer(qi);
fi.primary_ref_frame = PRIMARY_REF_NONE;
fi.number = segment_start_frame;
for i in 0..INTER_REFS_PER_FRAME {
......@@ -754,8 +759,8 @@ impl FrameInvariants {
};
let q_drop = 15 * lvl as usize;
fi.base_q_idx = (fi.config.quantizer.min(255 - q_drop) + q_drop) as u8;
fi.cdef_bits = 3 - ((fi.base_q_idx.max(128) - 128) >> 5);
let qi = (fi.config.quantizer.min(255 - q_drop) + q_drop) as u8;
fi.set_quantizer(qi);
let second_ref_frame = if !inter_cfg.multiref {
NONE_FRAME
} else if !inter_cfg.reorder || inter_cfg.idx_in_group == 0 {
......@@ -815,6 +820,24 @@ impl FrameInvariants {
fi.me_range_scale = (inter_cfg.group_src_len >> lvl) as u8;
(fi, true)
}
pub fn set_quantizer(&mut self, qi: u8) {
self.base_q_idx = qi;
// TODO: Separate qi values for each color plane.
if self.frame_type != FrameType::KEY {
self.cdef_bits = 3 - ((self.base_q_idx.max(128) - 128) >> 5);
} else {
self.cdef_bits = 3;
}
let q = dc_q(self.base_q_idx, self.dc_delta_q[0], self.sequence.bit_depth)
as f64;
// Convert q into Q0 precision, given that libaom quantizers are Q3
let q0 = q / 8.0;
// Lambda formula from doc/theoretical_results.lyx in the daala repo.
// Use Q0 quantizer since lambda will be applied to Q0 pixel domain.
self.lambda = q0 * q0 * std::f64::consts::LN_2 / 6.0;
self.me_lambda = self.lambda.sqrt();
}
}
impl fmt::Display for FrameInvariants {
......@@ -2434,7 +2457,8 @@ fn encode_partition_bottomup(
let w: &mut dyn Writer = if cw.bc.cdef_coded {w_post_cdef} else {w_pre_cdef};
let tell = w.tell_frac();
cw.write_partition(w, bo, PartitionType::PARTITION_NONE, bsize);
cost = (w.tell_frac() - tell) as f64 * get_lambda(fi)/ ((1 << OD_BITRES) as f64);
cost =
(w.tell_frac() - tell) as f64 * fi.lambda / ((1 << OD_BITRES) as f64);
}
let pmv_idx = if bsize.greater_than(BlockSize::BLOCK_32X32) {
......@@ -2490,7 +2514,8 @@ fn encode_partition_bottomup(
let w: &mut dyn Writer = if cw.bc.cdef_coded {w_post_cdef} else {w_pre_cdef};
let tell = w.tell_frac();
cw.write_partition(w, bo, partition, bsize);
rd_cost = (w.tell_frac() - tell) as f64 * get_lambda(fi)/ ((1 << OD_BITRES) as f64);
rd_cost = (w.tell_frac() - tell) as f64 * fi.lambda
/ ((1 << OD_BITRES) as f64);
}
let four_partitions = [
......
......@@ -16,7 +16,6 @@ use crate::FrameInvariants;
use crate::FrameState;
use crate::partition::*;
use crate::plane::*;
use crate::rdo::get_lambda_sqrt;
#[cfg(all(target_arch = "x86_64", not(windows), feature = "nasm"))]
mod nasm {
......@@ -168,7 +167,7 @@ pub fn motion_estimation(
let mut best_mv = MotionVector { row: 0, col: 0 };
// 0.5 is a fudge factor
let lambda = (get_lambda_sqrt(fi) * 256.0 * 0.5) as u32;
let lambda = (fi.me_lambda * 256.0 * 0.5) as u32;
full_search(
x_lo,
......@@ -335,7 +334,7 @@ pub fn estimate_motion_ss4(
let mut best_mv = MotionVector { row: 0, col: 0 };
// Divide by 16 to account for subsampling, 0.125 is a fudge factor
let lambda = (get_lambda_sqrt(fi) * 256.0 / 16.0 * 0.125) as u32;
let lambda = (fi.me_lambda * 256.0 / 16.0 * 0.125) as u32;
full_search(
x_lo,
......@@ -381,7 +380,7 @@ pub fn estimate_motion_ss2(
let mut best_mv = MotionVector { row: 0, col: 0 };
// Divide by 4 to account for subsampling, 0.125 is a fudge factor
let lambda = (get_lambda_sqrt(fi) * 256.0 / 4.0 * 0.125) as u32;
let lambda = (fi.me_lambda * 256.0 / 4.0 * 0.125) as u32;
for omv in pmvs.iter() {
if let Some(pmv) = omv {
......
......@@ -27,7 +27,6 @@ use crate::motion_compensate;
use crate::partition::*;
use crate::plane::*;
use crate::predict::{RAV1E_INTRA_MODES, RAV1E_INTER_MODES_MINIMAL, RAV1E_INTER_COMPOUND_MODES};
use crate::quantize::dc_q;
use crate::Tune;
use crate::write_tx_blocks;
use crate::write_tx_tree;
......@@ -136,35 +135,13 @@ pub fn sse_wxh(
sse
}
pub fn get_lambda(fi: &FrameInvariants) -> f64 {
let q = dc_q(fi.base_q_idx, fi.dc_delta_q[0], fi.sequence.bit_depth) as f64;
// Convert q into Q0 precision, given that libaom quantizers are Q3
let q0 = q / 8.0_f64;
// Lambda formula from doc/theoretical_results.lyx in the daala repo
// Use Q0 quantizer since lambda will be applied to Q0 pixel domain
q0 * q0 * std::f64::consts::LN_2 / 6.0
}
pub fn get_lambda_sqrt(fi: &FrameInvariants) -> f64 {
let q = dc_q(fi.base_q_idx, fi.dc_delta_q[0], fi.sequence.bit_depth) as f64;
// Convert q into Q0 precision, given that libaom quantizers are Q3
let q0 = q / 8.0_f64;
// Lambda formula from doc/theoretical_results.lyx in the daala repo
// Use Q0 quantizer since lambda will be applied to Q0 pixel domain
q0 * (std::f64::consts::LN_2 / 6.0).sqrt()
}
// Compute the rate-distortion cost for an encode
fn compute_rd_cost(
fi: &FrameInvariants, fs: &FrameState, w_y: usize, h_y: usize,
is_chroma_block: bool, bo: &BlockOffset, bit_cost: u32,
luma_only: bool
) -> f64 {
let lambda = get_lambda(fi);
let lambda = fi.lambda;
// Compute distortion
let po = bo.plane_offset(&fs.input.planes[0].cfg);
......@@ -236,7 +213,7 @@ fn compute_tx_rd_cost(
) -> f64 {
assert!(fi.config.tune == Tune::Psnr);
let lambda = get_lambda(fi);
let lambda = fi.lambda;
// Compute distortion
let mut distortion = if skip {
......@@ -1043,7 +1020,8 @@ pub fn rdo_partition_decision(
let w: &mut dyn Writer = if cw.bc.cdef_coded {w_post_cdef} else {w_pre_cdef};
let tell = w.tell_frac();
cw.write_partition(w, bo, partition, bsize);
cost = (w.tell_frac() - tell) as f64 * get_lambda(fi)/ ((1 << OD_BITRES) as f64);
cost = (w.tell_frac() - tell) as f64 * fi.lambda
/ ((1 << OD_BITRES) as f64);
}
let mut rd_cost_sum = 0.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