Unverified Commit f0a917ee authored by fbossen's avatar fbossen Committed by GitHub

Reuse probabilities from previous frame (#509)

Add reference frame structure to capture YUV data and probabilities
of a previously decoded frame.
Symbol counts are reset and not carried from one frame to the next.
Error resilient mode is disabled to support this feature.
parent 3df9da28
......@@ -15,6 +15,7 @@ mod common;
use common::*;
use rav1e::*;
use rav1e::partition::LAST_FRAME;
fn main() {
let (mut io, config) = EncoderConfig::from_cli();
......@@ -68,7 +69,8 @@ fn main() {
if fi.frame_type == FrameType::KEY { ALL_REF_FRAMES_MASK } else { 1 };
fi.intra_only = fi.frame_type == FrameType::KEY
|| fi.frame_type == FrameType::INTRA_ONLY;
fi.use_prev_frame_mvs = !(fi.intra_only || fi.error_resilient);
fi.primary_ref_frame =
if fi.intra_only || fi.error_resilient { PRIMARY_REF_NONE } else { (LAST_FRAME - LAST_FRAME) as u32 };
if !process_frame(
&mut sequence,
......
......@@ -957,6 +957,86 @@ impl CDFContext {
}
}
pub fn reset_counts(&mut self) {
macro_rules! reset_1d {
($field:expr) => (let r = $field.last_mut().unwrap(); *r = 0;)
}
macro_rules! reset_2d {
($field:expr) => (for mut x in $field.iter_mut() { reset_1d!(x); })
}
macro_rules! reset_3d {
($field:expr) => (for mut x in $field.iter_mut() { reset_2d!(x); })
}
macro_rules! reset_4d {
($field:expr) => (for mut x in $field.iter_mut() { reset_3d!(x); })
}
for i in 0..4 { self.partition_cdf[i][4] = 0; }
for i in 4..16 { self.partition_cdf[i][10] = 0; }
for i in 16..20 { self.partition_cdf[i][8] = 0; }
reset_3d!(self.kf_y_cdf);
reset_2d!(self.y_mode_cdf);
for i in 0..INTRA_MODES {
self.uv_mode_cdf[0][i][UV_INTRA_MODES - 1] = 0;
self.uv_mode_cdf[1][i][UV_INTRA_MODES] = 0;
}
reset_1d!(self.cfl_sign_cdf);
reset_2d!(self.cfl_alpha_cdf);
reset_2d!(self.newmv_cdf);
reset_2d!(self.zeromv_cdf);
reset_2d!(self.refmv_cdf);
for i in 0..TX_SIZES {
for j in 0..INTRA_MODES {
self.intra_tx_cdf[1][i][j][7] = 0;
self.intra_tx_cdf[2][i][j][5] = 0;
}
self.inter_tx_cdf[1][i][16] = 0;
self.inter_tx_cdf[2][i][12] = 0;
self.inter_tx_cdf[3][i][2] = 0;
}
reset_2d!(self.skip_cdfs);
reset_2d!(self.intra_inter_cdfs);
reset_2d!(self.angle_delta_cdf);
reset_2d!(self.filter_intra_cdfs);
reset_3d!(self.single_ref_cdfs);
reset_2d!(self.drl_cdfs);
reset_2d!(self.deblock_delta_multi_cdf);
reset_1d!(self.deblock_delta_cdf);
reset_1d!(self.nmv_context.joints_cdf);
for i in 0..2 {
reset_1d!(self.nmv_context.comps[i].classes_cdf);
reset_2d!(self.nmv_context.comps[i].class0_fp_cdf);
reset_1d!(self.nmv_context.comps[i].fp_cdf);
reset_1d!(self.nmv_context.comps[i].sign_cdf);
reset_1d!(self.nmv_context.comps[i].class0_hp_cdf);
reset_1d!(self.nmv_context.comps[i].hp_cdf);
reset_1d!(self.nmv_context.comps[i].class0_cdf);
reset_2d!(self.nmv_context.comps[i].bits_cdf);
}
// lv_map
reset_3d!(self.txb_skip_cdf);
reset_3d!(self.dc_sign_cdf);
reset_4d!(self.eob_extra_cdf);
reset_3d!(self.eob_flag_cdf16);
reset_3d!(self.eob_flag_cdf32);
reset_3d!(self.eob_flag_cdf64);
reset_3d!(self.eob_flag_cdf128);
reset_3d!(self.eob_flag_cdf256);
reset_3d!(self.eob_flag_cdf512);
reset_3d!(self.eob_flag_cdf1024);
reset_4d!(self.coeff_base_eob_cdf);
reset_4d!(self.coeff_base_cdf);
reset_4d!(self.coeff_br_cdf);
}
pub fn build_map(&self) -> Vec<(&'static str, usize, usize)> {
use std::mem::size_of_val;
......@@ -1096,6 +1176,12 @@ impl CDFContext {
}
}
impl fmt::Debug for CDFContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CDFContext contains too many numbers to print :-(")
}
}
#[cfg(test)]
mod test {
#[test]
......@@ -1794,7 +1880,7 @@ pub struct ContextWriterCheckpoint {
#[derive(Clone)]
pub struct ContextWriter {
pub bc: BlockContext,
fc: CDFContext,
pub fc: CDFContext,
#[cfg(debug)]
fc_map: Option<FieldMap> // For debugging purposes
}
......
......@@ -38,9 +38,15 @@ impl Frame {
}
}
#[derive(Debug, Clone)]
pub struct ReferenceFrame {
pub frame: Frame,
pub cdfs: CDFContext,
}
#[derive(Debug)]
pub struct ReferenceFramesSet {
pub frames: [Option<Rc<Frame>>; (REF_FRAMES as usize)],
pub frames: [Option<Rc<ReferenceFrame>>; (REF_FRAMES as usize)],
pub deblock: [DeblockState; (REF_FRAMES as usize)]
}
......@@ -57,7 +63,7 @@ const MAX_NUM_TEMPORAL_LAYERS: usize = 8;
const MAX_NUM_SPATIAL_LAYERS: usize = 4;
const MAX_NUM_OPERATING_POINTS: usize = MAX_NUM_TEMPORAL_LAYERS * MAX_NUM_SPATIAL_LAYERS;
const PRIMARY_REF_NONE: u32 = 7;
pub const PRIMARY_REF_NONE: u32 = 7;
const PRIMARY_REF_BITS: u32 = 3;
arg_enum!{
......@@ -218,6 +224,7 @@ pub struct FrameState {
pub input: Frame,
pub rec: Frame,
pub qc: QuantizationContext,
pub cdfs: CDFContext,
}
impl FrameState {
......@@ -226,6 +233,7 @@ impl FrameState {
input: Frame::new(fi.padded_w, fi.padded_h),
rec: Frame::new(fi.padded_w, fi.padded_h),
qc: Default::default(),
cdfs: CDFContext::new(0),
}
}
}
......@@ -345,7 +353,7 @@ impl FrameInvariants {
number: 0,
show_frame: true,
showable_frame: true,
error_resilient: true,
error_resilient: false,
intra_only: false,
allow_high_precision_mv: false,
frame_type: FrameType::KEY,
......@@ -385,6 +393,7 @@ impl FrameInvariants {
input: Frame::new(self.padded_w, self.padded_h),
rec: Frame::new(self.padded_w, self.padded_h),
qc: Default::default(),
cdfs: CDFContext::new(0),
}
}
}
......@@ -1801,7 +1810,16 @@ fn encode_partition_topdown(seq: &Sequence, fi: &FrameInvariants, fs: &mut Frame
fn encode_tile(sequence: &mut Sequence, fi: &FrameInvariants, fs: &mut FrameState, bit_depth: usize) -> Vec<u8> {
let mut w = WriterEncoder::new();
let fc = CDFContext::new(fi.config.quantizer as u8);
let fc = if fi.primary_ref_frame == PRIMARY_REF_NONE {
CDFContext::new(fi.config.quantizer as u8)
} else {
match fi.rec_buffer.frames[fi.ref_frames[fi.primary_ref_frame as usize]] {
Some(ref rec) => rec.cdfs.clone(),
None => CDFContext::new(fi.config.quantizer as u8)
}
};
let bc = BlockContext::new(fi.w_in_b, fi.h_in_b);
let mut cw = ContextWriter::new(fc, bc);
......@@ -1842,6 +1860,9 @@ fn encode_tile(sequence: &mut Sequence, fi: &FrameInvariants, fs: &mut FrameStat
cdef_filter_frame(fi, &mut fs.rec, &mut cw.bc, bit_depth);
}
fs.cdfs = cw.fc.clone();
fs.cdfs.reset_counts();
let mut h = w.done();
h.push(0); // superframe anti emulation
h
......@@ -1866,7 +1887,7 @@ pub fn encode_frame(sequence: &mut Sequence, fi: &mut FrameInvariants, fs: &mut
if fi.show_existing_frame {
match fi.rec_buffer.frames[0] {
Some(ref rec) => for p in 0..3 {
fs.rec.planes[p].data.copy_from_slice(rec.planes[p].data.as_slice());
fs.rec.planes[p].data.copy_from_slice(rec.frame.planes[p].data.as_slice());
},
None => (),
}
......@@ -1901,7 +1922,7 @@ pub fn encode_frame(sequence: &mut Sequence, fi: &mut FrameInvariants, fs: &mut
}
pub fn update_rec_buffer(fi: &mut FrameInvariants, fs: FrameState) {
let rfs = Rc::new(fs.rec);
let rfs = Rc::new(ReferenceFrame { frame: fs.rec, cdfs: fs.cdfs } );
for i in 0..(REF_FRAMES as usize) {
if (fi.refresh_frame_flags & (1 << i)) != 0 {
fi.rec_buffer.frames[i] = Some(Rc::clone(&rfs));
......
......@@ -36,7 +36,7 @@ pub fn motion_estimation(fi: &FrameInvariants, fs: &mut FrameState, bsize: Block
for x in (x_lo..x_hi).step_by(1) {
let mut sad = 0 as u32;
let mut plane_org = fs.input.planes[0].slice(&po);
let mut plane_ref = rec.planes[0].slice(&PlaneOffset { x: x, y: y });
let mut plane_ref = rec.frame.planes[0].slice(&PlaneOffset { x: x, y: y });
for _r in 0..blk_h {
{
......
......@@ -628,7 +628,7 @@ impl PredictionMode {
match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME]] {
Some(ref rec) => {
let rec_cfg = &rec.planes[p].cfg;
let rec_cfg = &rec.frame.planes[p].cfg;
let shift_row = 3 + rec_cfg.ydec;
let shift_col = 3 + rec_cfg.xdec;
let row_offset = mv.row as i32 >> shift_row;
......@@ -652,7 +652,7 @@ impl PredictionMode {
let rs = cmp::min(ref_height as i32 - 1, cmp::max(0, po.y as i32 + row_offset + r as i32)) as usize;
let cs = cmp::min(ref_width as i32 - 1, cmp::max(0, po.x as i32 + col_offset + c as i32)) as usize;
let output_index = r * stride + c;
slice[output_index] = rec.planes[p].p(cs, rs);
slice[output_index] = rec.frame.planes[p].p(cs, rs);
}
}
}
......@@ -663,7 +663,7 @@ impl PredictionMode {
for k in 0..8 {
let rs = cmp::min(ref_height as i32 - 1, cmp::max(0, po.y as i32 + row_offset + r as i32 - 3 + k as i32)) as usize;
let cs = cmp::min(ref_width as i32 - 1, cmp::max(0, po.x as i32 + col_offset + c as i32)) as usize;
sum += rec.planes[p].p(cs, rs) as i32 * SUBPEL_FILTERS[y_filter_idx][row_frac as usize][k];
sum += rec.frame.planes[p].p(cs, rs) as i32 * SUBPEL_FILTERS[y_filter_idx][row_frac as usize][k];
}
let output_index = r * stride + c;
let val = ((sum + 64) >> 7).max(0).min(max_sample_val);
......@@ -678,7 +678,7 @@ impl PredictionMode {
for k in 0..8 {
let rs = cmp::min(ref_height as i32 - 1, cmp::max(0, po.y as i32 + row_offset + r as i32)) as usize;
let cs = cmp::min(ref_width as i32 - 1, cmp::max(0, po.x as i32 + col_offset + c as i32 - 3 + k as i32)) as usize;
sum += rec.planes[p].p(cs, rs) as i32 * SUBPEL_FILTERS[x_filter_idx][col_frac as usize][k];
sum += rec.frame.planes[p].p(cs, rs) as i32 * SUBPEL_FILTERS[x_filter_idx][col_frac as usize][k];
}
let output_index = r * stride + c;
let val = ((((sum + 4) >> 3) + 8) >> 4).max(0).min(max_sample_val);
......@@ -695,7 +695,7 @@ impl PredictionMode {
for k in 0..8 {
let rs = cmp::min(ref_height as i32 - 1, cmp::max(0, po.y as i32 + row_offset + r as i32 - 3)) as usize;
let cs = cmp::min(ref_width as i32 - 1, cmp::max(0, po.x as i32 + col_offset + c as i32 - 3 + k as i32)) as usize;
sum += rec.planes[p].p(cs, rs) as i32 * SUBPEL_FILTERS[x_filter_idx][col_frac as usize][k];
sum += rec.frame.planes[p].p(cs, rs) as i32 * SUBPEL_FILTERS[x_filter_idx][col_frac as usize][k];
}
let val = (sum + 4) >> 3;
intermediate[r][c] = val as i16;
......
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