Unverified Commit 8177ecd1 authored by fbossen's avatar fbossen Committed by GitHub

Add search for NEARESTMV mode (#518)

Move MV stack construction out of encoding function such that the
value of the nearest MV can be determined before encoding
parent 0830d658
......@@ -2099,11 +2099,14 @@ impl ContextWriter {
}
}
fn has_tr(&mut self, bo: &BlockOffset) -> bool {
fn has_tr(&mut self, bo: &BlockOffset, bsize: BlockSize, is_sec_rect: bool) -> bool {
let sb_mi_size = BlockSize::MI_SIZE_WIDE[BLOCK_64X64 as usize]; /* Assume 64x64 for now */
let mask_row = bo.y & LOCAL_BLOCK_MASK;
let mask_col = bo.x & LOCAL_BLOCK_MASK;
let mut bs = cmp::max(self.bc.at(bo).n4_w, self.bc.at(bo).n4_h);
let target_n4_w = bsize.width_mi();
let target_n4_h = bsize.height_mi();
let mut bs = target_n4_w.max(target_n4_h);
if bs > BlockSize::MI_SIZE_WIDE[BLOCK_64X64 as usize] {
return false;
......@@ -2127,20 +2130,20 @@ impl ContextWriter {
/* The left hand of two vertical rectangles always has a top right (as the
* block above will have been decoded) */
let blk = &self.bc.at(bo);
if (blk.n4_w < blk.n4_h) && !blk.is_sec_rect {
if (target_n4_w < target_n4_h) && !is_sec_rect {
has_tr = true;
}
/* The bottom of two horizontal rectangles never has a top right (as the block
* to the right won't have been decoded) */
if (blk.n4_w > blk.n4_h) && blk.is_sec_rect {
if (target_n4_w > target_n4_h) && is_sec_rect {
has_tr = false;
}
/* The bottom left square of a Vertical A (in the old format) does
* not have a top right as it is decoded before the right hand
* rectangle of the partition */
/*
if blk.partition == PartitionType::PARTITION_VERT_A {
if blk.n4_w == blk.n4_h {
if (mask_row & bs) != 0 {
......@@ -2148,6 +2151,7 @@ impl ContextWriter {
}
}
}
*/
has_tr
}
......@@ -2197,9 +2201,9 @@ impl ContextWriter {
fn scan_row_mbmi(&mut self, bo: &BlockOffset, row_offset: isize, max_row_offs: isize,
processed_rows: &mut isize, ref_frame: usize,
mv_stack: &mut Vec<CandidateMV>, newmv_count: &mut usize) -> bool {
mv_stack: &mut Vec<CandidateMV>, newmv_count: &mut usize, bsize: BlockSize) -> bool {
let bc = &self.bc;
let target_n4_w = bc.at(bo).n4_w;
let target_n4_w = bsize.width_mi();
let end_mi = cmp::min(cmp::min(target_n4_w, bc.cols - bo.x),
BlockSize::MI_SIZE_WIDE[BLOCK_64X64 as usize]);
......@@ -2250,9 +2254,10 @@ impl ContextWriter {
fn scan_col_mbmi(&mut self, bo: &BlockOffset, col_offset: isize, max_col_offs: isize,
processed_cols: &mut isize, ref_frame: usize,
mv_stack: &mut Vec<CandidateMV>, newmv_count: &mut usize) -> bool {
mv_stack: &mut Vec<CandidateMV>, newmv_count: &mut usize, bsize: BlockSize) -> bool {
let bc = &self.bc;
let target_n4_h = bc.at(bo).n4_h;
let target_n4_h = bsize.height_mi();
let end_mi = cmp::min(cmp::min(target_n4_h, bc.rows - bo.y),
BlockSize::MI_SIZE_HIGH[BLOCK_64X64 as usize]);
......@@ -2317,14 +2322,18 @@ impl ContextWriter {
}
}
fn setup_mvref_list(&mut self, bo: &BlockOffset, ref_frame: usize, mv_stack: &mut Vec<CandidateMV>) -> usize {
fn setup_mvref_list(&mut self, bo: &BlockOffset, ref_frame: usize, mv_stack: &mut Vec<CandidateMV>,
bsize: BlockSize, is_sec_rect: bool) -> usize {
let (_rf, _rf_num) = self.get_mvref_ref_frames(INTRA_FRAME);
let target_n4_h = bsize.height_mi();
let target_n4_w = bsize.width_mi();
let mut max_row_offs = 0 as isize;
let row_adj = (self.bc.at(bo).n4_h < BlockSize::MI_SIZE_HIGH[BLOCK_8X8 as usize]) && (bo.y & 0x01) != 0x0;
let row_adj = (target_n4_h < BlockSize::MI_SIZE_HIGH[BLOCK_8X8 as usize]) && (bo.y & 0x01) != 0x0;
let mut max_col_offs = 0 as isize;
let col_adj = (self.bc.at(bo).n4_w < BlockSize::MI_SIZE_WIDE[BLOCK_8X8 as usize]) && (bo.x & 0x01) != 0x0;
let col_adj = (target_n4_w < BlockSize::MI_SIZE_WIDE[BLOCK_8X8 as usize]) && (bo.x & 0x01) != 0x0;
let mut processed_rows = 0 as isize;
let mut processed_cols = 0 as isize;
......@@ -2336,7 +2345,7 @@ impl ContextWriter {
max_row_offs = -2 * MVREF_ROW_COLS as isize + row_adj as isize;
// limit max offset for small blocks
if self.bc.at(bo).n4_h < BlockSize::MI_SIZE_HIGH[BLOCK_8X8 as usize] {
if target_n4_h < BlockSize::MI_SIZE_HIGH[BLOCK_8X8 as usize] {
max_row_offs = -2 * 2 + row_adj as isize;
}
......@@ -2348,7 +2357,7 @@ impl ContextWriter {
max_col_offs = -2 * MVREF_ROW_COLS as isize + col_adj as isize;
// limit max offset for small blocks
if self.bc.at(bo).n4_w < BlockSize::MI_SIZE_WIDE[BLOCK_8X8 as usize] {
if target_n4_w < BlockSize::MI_SIZE_WIDE[BLOCK_8X8 as usize] {
max_col_offs = -2 * 2 + col_adj as isize;
}
......@@ -2361,17 +2370,16 @@ impl ContextWriter {
if max_row_offs.abs() >= 1 {
let found_match = self.scan_row_mbmi(bo, -1, max_row_offs, &mut processed_rows, ref_frame, mv_stack,
&mut newmv_count);
&mut newmv_count, bsize);
row_match |= found_match;
}
if max_col_offs.abs() >= 1 {
let found_match = self.scan_col_mbmi(bo, -1, max_col_offs, &mut processed_cols, ref_frame, mv_stack,
&mut newmv_count);
&mut newmv_count, bsize);
col_match |= found_match;
}
if self.has_tr(bo) {
let n4_w = self.bc.at(bo).n4_w;
let found_match = self.scan_blk_mbmi(&bo.with_offset(n4_w as isize, -1), ref_frame, mv_stack,
if self.has_tr(bo, bsize, is_sec_rect) {
let found_match = self.scan_blk_mbmi(&bo.with_offset(target_n4_w as isize, -1), ref_frame, mv_stack,
&mut newmv_count);
row_match |= found_match;
}
......@@ -2392,19 +2400,21 @@ impl ContextWriter {
if row_offset.abs() <= max_row_offs.abs() && row_offset.abs() > processed_rows {
let found_match = self.scan_row_mbmi(bo, row_offset, max_row_offs, &mut processed_rows, ref_frame, mv_stack,
&mut far_newmv_count);
&mut far_newmv_count, bsize);
row_match |= found_match;
}
if col_offset.abs() <= max_col_offs.abs() && col_offset.abs() > processed_cols {
let found_match = self.scan_col_mbmi(bo, col_offset, max_col_offs, &mut processed_cols, ref_frame, mv_stack,
&mut far_newmv_count);
&mut far_newmv_count, bsize);
col_match |= found_match;
}
}
let total_match = if row_match { 1 } else { 0 } + if col_match { 1 } else { 0 };
assert!(total_match >= nearest_match);
let mode_context = match nearest_match {
0 => cmp::min(total_match, 1) + (total_match << REFMV_OFFSET) ,
1 => 3 - cmp::min(newmv_count, 1) + ((2 + total_match) << REFMV_OFFSET) ,
......@@ -2424,7 +2434,7 @@ impl ContextWriter {
}
pub fn find_mvrefs(&mut self, bo: &BlockOffset, ref_frame: usize,
mv_stack: &mut Vec<CandidateMV>) -> usize {
mv_stack: &mut Vec<CandidateMV>, bsize: BlockSize, is_sec_rect: bool) -> usize {
if ref_frame < REF_FRAMES {
if ref_frame != INTRA_FRAME {
/* TODO: convert global mv to an mv here */
......@@ -2439,7 +2449,7 @@ impl ContextWriter {
/* TODO: Set the zeromv ref to 0 */
}
let mode_context = self.setup_mvref_list(bo, ref_frame, mv_stack);
let mode_context = self.setup_mvref_list(bo, ref_frame, mv_stack, bsize, is_sec_rect);
mode_context
}
......
......@@ -1291,7 +1291,8 @@ pub fn encode_block_b(seq: &Sequence, fi: &FrameInvariants, fs: &mut FrameState,
luma_mode: PredictionMode, chroma_mode: PredictionMode,
ref_frame: usize, mv: MotionVector,
bsize: BlockSize, bo: &BlockOffset, skip: bool, bit_depth: usize,
cfl: CFLParams, tx_size: TxSize, tx_type: TxType) {
cfl: CFLParams, tx_size: TxSize, tx_type: TxType,
mode_context: usize, mv_stack: &Vec<CandidateMV>) {
let is_inter = !luma_mode.is_intra();
if is_inter { assert!(luma_mode == chroma_mode); };
let sb_size = if seq.use_128x128_superblock {
......@@ -1315,8 +1316,6 @@ pub fn encode_block_b(seq: &Sequence, fi: &FrameInvariants, fs: &mut FrameState,
cw.bc.set_motion_vector(bo, bsize, mv);
cw.write_ref_frames(w, bo);
let mut mv_stack = Vec::new();
let mode_context = cw.find_mvrefs(bo, ref_frame, &mut mv_stack);
//let mode_context = if bo.x == 0 && bo.y == 0 { 0 } else if bo.x ==0 || bo.y == 0 { 51 } else { 85 };
// NOTE: Until rav1e supports other inter modes than GLOBALMV
cw.write_inter_mode(w, luma_mode, mode_context);
......@@ -1632,6 +1631,9 @@ fn encode_partition_bottomup(seq: &Sequence, fi: &FrameInvariants, fs: &mut Fram
let mut cdef_coded = cw.bc.cdef_coded;
rd_cost = mode_decision.rd_cost + cost;
let mut mv_stack = Vec::new();
let mode_context = cw.find_mvrefs(bo, ref_frame, &mut mv_stack, bsize, false);
let (tx_size, tx_type) =
rdo_tx_size_type(seq, fi, fs, cw, bsize, bo, mode_luma, ref_frame, mv, skip);
......@@ -1639,7 +1641,7 @@ fn encode_partition_bottomup(seq: &Sequence, fi: &FrameInvariants, fs: &mut Fram
bsize, bo, skip);
encode_block_b(seq, fi, fs, cw, if cdef_coded {w_post_cdef} else {w_pre_cdef},
mode_luma, mode_chroma, ref_frame, mv, bsize, bo, skip, seq.bit_depth, cfl,
tx_size, tx_type);
tx_size, tx_type, mode_context, &mv_stack);
best_decision = mode_decision;
}
......@@ -1696,6 +1698,9 @@ fn encode_partition_bottomup(seq: &Sequence, fi: &FrameInvariants, fs: &mut Fram
let skip = best_decision.skip;
let mut cdef_coded = cw.bc.cdef_coded;
let mut mv_stack = Vec::new();
let mode_context = cw.find_mvrefs(bo, ref_frame, &mut mv_stack, bsize, false);
let (tx_size, tx_type) =
rdo_tx_size_type(seq, fi, fs, cw, bsize, bo, mode_luma, ref_frame, mv, skip);
......@@ -1703,7 +1708,7 @@ fn encode_partition_bottomup(seq: &Sequence, fi: &FrameInvariants, fs: &mut Fram
bsize, bo, skip);
encode_block_b(seq, fi, fs, cw, if cdef_coded {w_post_cdef} else {w_pre_cdef},
mode_luma, mode_chroma, ref_frame, mv, bsize, bo, skip, seq.bit_depth, cfl,
tx_size, tx_type);
tx_size, tx_type, mode_context, &mv_stack);
}
}
......@@ -1783,12 +1788,15 @@ fn encode_partition_topdown(seq: &Sequence, fi: &FrameInvariants, fs: &mut Frame
let (tx_size, tx_type) =
rdo_tx_size_type(seq, fi, fs, cw, bsize, bo, mode_luma, ref_frame, mv, skip);
let mut mv_stack = Vec::new();
let mode_context = cw.find_mvrefs(bo, ref_frame, &mut mv_stack, bsize, false);
// FIXME: every final block that has gone through the RDO decision process is encoded twice
cdef_coded = encode_block_a(seq, cw, if cdef_coded {w_post_cdef} else {w_pre_cdef},
bsize, bo, skip);
encode_block_b(seq, fi, fs, cw, if cdef_coded {w_post_cdef} else {w_pre_cdef},
mode_luma, mode_chroma, ref_frame, mv, bsize, bo, skip, seq.bit_depth, cfl,
tx_size, tx_type);
tx_size, tx_type, mode_context, &mv_stack);
},
PartitionType::PARTITION_SPLIT => {
if rdo_output.part_modes.len() >= 4 {
......
......@@ -43,6 +43,7 @@ pub static RAV1E_INTRA_MODES_MINIMAL: &'static [PredictionMode] = &[
pub static RAV1E_INTER_MODES: &'static [PredictionMode] = &[
PredictionMode::GLOBALMV,
PredictionMode::NEARESTMV,
PredictionMode::NEWMV,
];
......
......@@ -264,6 +264,9 @@ pub fn rdo_mode_decision(
}
mode_set.extend_from_slice(intra_mode_set);
let mut mv_stack = Vec::new();
let mode_context = cw.find_mvrefs(bo, LAST_FRAME, &mut mv_stack, bsize, false);
for &luma_mode in &mode_set {
assert!(fi.frame_type == FrameType::INTER || luma_mode.is_intra());
......@@ -278,10 +281,10 @@ pub fn rdo_mode_decision(
}
let ref_frame = if luma_mode.is_intra() { INTRA_FRAME } else { LAST_FRAME };
let mv = if luma_mode != PredictionMode::NEWMV {
MotionVector { row: 0, col: 0 }
} else {
motion_estimation(fi, fs, bsize, bo, ref_frame)
let mv = match luma_mode {
PredictionMode::NEWMV => motion_estimation(fi, fs, bsize, bo, ref_frame),
PredictionMode::NEARESTMV => if mv_stack.len() > 0 { mv_stack[0].this_mv } else { MotionVector { row: 0, col: 0 } },
_ => MotionVector { row: 0, col: 0 }
};
let (tx_size, tx_type) =
......@@ -310,7 +313,7 @@ pub fn rdo_mode_decision(
encode_block_a(seq, cw, wr, bsize, bo, skip);
encode_block_b(seq, fi, fs, cw, wr, luma_mode, chroma_mode,
ref_frame, mv, bsize, bo, skip, seq.bit_depth, cfl, tx_size, tx_type);
ref_frame, mv, bsize, bo, skip, seq.bit_depth, cfl, tx_size, tx_type, mode_context, &mv_stack);
let cost = wr.tell_frac() - tell;
let rd = compute_rd_cost(
......@@ -341,6 +344,7 @@ pub fn rdo_mode_decision(
}
cw.bc.set_mode(bo, bsize, best_mode_luma);
cw.bc.set_motion_vector(bo, bsize, best_mv);
assert!(best_rd >= 0_f64);
......
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