From b6d766bf5e0cae21483dd5d7772b3110543d2990 Mon Sep 17 00:00:00 2001
From: Yushin Cho <cho.yushin@gmail.com>
Date: Wed, 12 Sep 2018 21:14:38 -0700
Subject: [PATCH] [WIP] ME use predicted search center for topdown partition
 search (#569)

ME use predicted search center for topdown partition search
---
 src/encoder.rs |  6 ++++--
 src/me.rs      | 10 +++++-----
 src/rdo.rs     | 19 +++++++++++--------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/src/encoder.rs b/src/encoder.rs
index 8bf74a38..69ddf1b2 100644
--- a/src/encoder.rs
+++ b/src/encoder.rs
@@ -1678,7 +1678,8 @@ fn encode_partition_bottomup(seq: &Sequence, fi: &FrameInvariants, fs: &mut Fram
             cw.write_partition(w, bo, partition, bsize);
             cost = (w.tell_frac() - tell) as f64 * get_lambda(fi, seq.bit_depth)/ ((1 << OD_BITRES) as f64);
         }
-        let mode_decision = rdo_mode_decision(seq, fi, fs, cw, bsize, bo).part_modes[0].clone();
+        let pmv = MotionVector { row: 0, col: 0 };
+        let mode_decision = rdo_mode_decision(seq, fi, fs, cw, bsize, bo, &pmv).part_modes[0].clone();
         let (mode_luma, mode_chroma) = (mode_decision.pred_mode_luma, mode_decision.pred_mode_chroma);
         let cfl = mode_decision.pred_cfl_params;
         let ref_frame = mode_decision.ref_frame;
@@ -1818,6 +1819,7 @@ fn encode_partition_topdown(seq: &Sequence, fi: &FrameInvariants, fs: &mut Frame
 
     let hbs = bs >> 1; // Half the block size in blocks
     let subsize = get_subsize(bsize, partition);
+    let pmv =  MotionVector { row: 0, col: 0 };
 
     if bsize >= BlockSize::BLOCK_8X8 {
         let w: &mut dyn Writer = if cw.bc.cdef_coded {w_post_cdef} else {w_pre_cdef};
@@ -1831,7 +1833,7 @@ fn encode_partition_topdown(seq: &Sequence, fi: &FrameInvariants, fs: &mut Frame
                     rdo_output.part_modes[0].clone()
                 } else {
                     // Make a prediction mode decision for blocks encoded with no rdo_partition_decision call (e.g. edges)
-                    rdo_mode_decision(seq, fi, fs, cw, bsize, bo).part_modes[0].clone()
+                    rdo_mode_decision(seq, fi, fs, cw, bsize, bo, &pmv).part_modes[0].clone()
                 };
 
             let mut mode_luma = part_decision.pred_mode_luma;
diff --git a/src/me.rs b/src/me.rs
index 8a6267e4..329fd129 100644
--- a/src/me.rs
+++ b/src/me.rs
@@ -41,7 +41,7 @@ pub fn get_sad(
 
 pub fn motion_estimation(
   fi: &FrameInvariants, fs: &mut FrameState, bsize: BlockSize,
-  bo: &BlockOffset, ref_frame: usize
+  bo: &BlockOffset, ref_frame: usize, pmv: &MotionVector
 ) -> MotionVector {
   match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME]] {
     Some(ref rec) => {
@@ -58,10 +58,10 @@ pub fn motion_estimation(
       let mvx_max = (fi.w_in_b - bo.x - blk_w / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_w;
       let mvy_min = -(bo.y as isize) * (8 * MI_SIZE) as isize - border_h;
       let mvy_max = (fi.h_in_b - bo.y - blk_h / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_h;
-      let x_lo = po.x + ((-range).max(mvx_min / 8));
-      let x_hi = po.x + (range.min(mvx_max / 8));
-      let y_lo = po.y + ((-range).max(mvy_min / 8));
-      let y_hi = po.y + (range.min(mvy_max / 8));
+      let x_lo = po.x + ((-range + (pmv.col / 8) as isize).max(mvx_min / 8));
+      let x_hi = po.x + ((range + (pmv.col / 8) as isize).min(mvx_max / 8));
+      let y_lo = po.y + ((-range + (pmv.row / 8) as isize).max(mvy_min / 8));
+      let y_hi = po.y + ((range + (pmv.row / 8) as isize).min(mvy_max / 8));
 
       let mut lowest_sad = 128 * 128 * 4096 as u32;
       let mut best_mv = MotionVector { row: 0, col: 0 };
diff --git a/src/rdo.rs b/src/rdo.rs
index b5fbb9fb..5198abf5 100755
--- a/src/rdo.rs
+++ b/src/rdo.rs
@@ -251,7 +251,8 @@ pub fn rdo_tx_size_type(
 // RDO-based mode decision
 pub fn rdo_mode_decision(
   seq: &Sequence, fi: &FrameInvariants, fs: &mut FrameState,
-  cw: &mut ContextWriter, bsize: BlockSize, bo: &BlockOffset
+  cw: &mut ContextWriter, bsize: BlockSize, bo: &BlockOffset,
+  pmv: &MotionVector
 ) -> RDOOutput {
   let mut best_mode_luma = PredictionMode::DC_PRED;
   let mut best_mode_chroma = PredictionMode::DC_PRED;
@@ -312,7 +313,7 @@ pub fn rdo_mode_decision(
     let ref_frame =
       if luma_mode_is_intra { INTRA_FRAME } else { LAST_FRAME };
     let mv = match luma_mode {
-      PredictionMode::NEWMV => motion_estimation(fi, fs, bsize, bo, ref_frame),
+      PredictionMode::NEWMV => motion_estimation(fi, fs, bsize, bo, ref_frame, pmv),
       PredictionMode::NEARESTMV => if mv_stack.len() > 0 {
         mv_stack[0].this_mv
       } else {
@@ -578,6 +579,7 @@ pub fn rdo_partition_decision(
 
     let mut rd: f64;
     let mut child_modes = std::vec::Vec::new();
+    let mut pmv =  MotionVector { row: 0, col: 0 };
 
     match partition {
       PartitionType::PARTITION_NONE => {
@@ -589,7 +591,7 @@ pub fn rdo_partition_decision(
           .part_modes
           .get(0)
           .unwrap_or(
-            &rdo_mode_decision(seq, fi, fs, cw, bsize, bo).part_modes[0]
+            &rdo_mode_decision(seq, fi, fs, cw, bsize, bo, &pmv).part_modes[0]
           ).clone();
         child_modes.push(mode_decision);
       }
@@ -599,32 +601,33 @@ pub fn rdo_partition_decision(
         if subsize == BlockSize::BLOCK_INVALID {
           continue;
         }
+        pmv = best_pred_modes[0].mv;
 
+        assert!(best_pred_modes.len() <= 4);
         let bs = bsize.width_mi();
         let hbs = bs >> 1; // Half the block size in blocks
-
         let offset = BlockOffset { x: bo.x, y: bo.y };
         let mode_decision =
-          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset).part_modes[0]
+          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset, &pmv).part_modes[0]
             .clone();
         child_modes.push(mode_decision);
 
         let offset = BlockOffset { x: bo.x + hbs as usize, y: bo.y };
         let mode_decision =
-          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset).part_modes[0]
+          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset, &pmv).part_modes[0]
             .clone();
         child_modes.push(mode_decision);
 
         let offset = BlockOffset { x: bo.x, y: bo.y + hbs as usize };
         let mode_decision =
-          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset).part_modes[0]
+          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset, &pmv).part_modes[0]
             .clone();
         child_modes.push(mode_decision);
 
         let offset =
           BlockOffset { x: bo.x + hbs as usize, y: bo.y + hbs as usize };
         let mode_decision =
-          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset).part_modes[0]
+          rdo_mode_decision(seq, fi, fs, cw, subsize, &offset, &pmv).part_modes[0]
             .clone();
         child_modes.push(mode_decision);
       }
-- 
GitLab