hash based motion estimation for screen data
Change-Id: Iec7969ffd8f53ca2f4eefd1d757cfec7b3bde131
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index 4efadff..02ac6ef 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -2562,10 +2562,45 @@
(*x->ex_search_count_ptr <= max_ex) && !cpi->rc.is_src_frame_alt_ref;
}
+#if CONFIG_HASH_ME
+#define MAX_HASH_MV_TABLE_SIZE 5
+static void add_to_sort_table(block_hash block_hashes[MAX_HASH_MV_TABLE_SIZE],
+ int costs[MAX_HASH_MV_TABLE_SIZE], int *existing,
+ int max_size, block_hash curr_block,
+ int curr_cost) {
+ if (*existing < max_size) {
+ block_hashes[*existing] = curr_block;
+ costs[*existing] = curr_cost;
+ (*existing)++;
+ } else {
+ int max_cost = 0;
+ int max_cost_idx = 0;
+ for (int i = 0; i < max_size; i++) {
+ if (costs[i] > max_cost) {
+ max_cost = costs[i];
+ max_cost_idx = i;
+ }
+ }
+
+ if (curr_cost < max_cost) {
+ block_hashes[max_cost_idx] = curr_block;
+ costs[max_cost_idx] = curr_cost;
+ }
+ }
+}
+#endif
+
+#if CONFIG_HASH_ME
+int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
+ MV *mvp_full, int step_param, int error_per_bit,
+ int *cost_list, const MV *ref_mv, int var_max, int rd,
+ int x_pos, int y_pos) {
+#else
int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
MV *mvp_full, int step_param, int error_per_bit,
int *cost_list, const MV *ref_mv, int var_max,
int rd) {
+#endif
const SPEED_FEATURES *const sf = &cpi->sf;
const SEARCH_METHODS method = sf->mv.search_method;
const aom_variance_fn_ptr_t *fn_ptr = &cpi->fn_ptr[bsize];
@@ -2637,6 +2672,80 @@
if (method != NSTEP && rd && var < var_max)
var = av1_get_mvpred_var(x, &x->best_mv.as_mv, ref_mv, fn_ptr, 1);
+#if CONFIG_HASH_ME
+ do {
+ if (!cpi->common.allow_screen_content_tools) {
+ break;
+ }
+ // already single ME
+ // get block size and original buffer of current block
+ const int block_height = block_size_high[bsize];
+ const int block_width = block_size_wide[bsize];
+ if (block_height == block_width && x_pos >= 0 && y_pos >= 0) {
+ if (block_width == 8 || block_width == 16 || block_width == 32 ||
+ block_width == 64) {
+ uint8_t *what = x->plane[0].src.buf;
+ const int what_stride = x->plane[0].src.stride;
+ block_hash block_hashes[MAX_HASH_MV_TABLE_SIZE];
+ int costs[MAX_HASH_MV_TABLE_SIZE];
+ int existing = 0;
+ int i;
+ uint32_t hash_value1, hash_value2;
+ MV best_hash_mv;
+ int best_hash_cost = INT_MAX;
+
+ // for the hashMap
+ hash_table *ref_frame_hash =
+ get_ref_frame_hash_map(cpi, x->e_mbd.mi[0]->mbmi.ref_frame[0]);
+
+ av1_get_block_hash_value(what, what_stride, block_width, &hash_value1,
+ &hash_value2);
+
+ const int count = av1_hash_table_count(ref_frame_hash, hash_value1);
+ if (count == 0) {
+ break;
+ }
+
+ Iterator iterator =
+ av1_hash_get_first_iterator(ref_frame_hash, hash_value1);
+ for (i = 0; i < count; i++, iterator_increment(&iterator)) {
+ block_hash ref_block_hash = *(block_hash *)(iterator_get(&iterator));
+ if (hash_value2 == ref_block_hash.hash_value2) {
+ int refCost =
+ abs(ref_block_hash.x - x_pos) + abs(ref_block_hash.y - y_pos);
+ add_to_sort_table(block_hashes, costs, &existing,
+ MAX_HASH_MV_TABLE_SIZE, ref_block_hash, refCost);
+ }
+ }
+
+ if (existing == 0) {
+ break;
+ }
+
+ for (i = 0; i < existing; i++) {
+ MV hash_mv;
+ hash_mv.col = block_hashes[i].x - x_pos;
+ hash_mv.row = block_hashes[i].y - y_pos;
+ if (!is_mv_in(&x->mv_limits, &hash_mv)) {
+ continue;
+ }
+ int currHashCost = av1_get_mvpred_var(x, &hash_mv, ref_mv, fn_ptr, 1);
+ if (currHashCost < best_hash_cost) {
+ best_hash_cost = currHashCost;
+ best_hash_mv = hash_mv;
+ }
+ }
+
+ if (best_hash_cost < var) {
+ x->second_best_mv = x->best_mv;
+ x->best_mv.as_mv = best_hash_mv;
+ var = best_hash_cost;
+ }
+ }
+ }
+ } while (0);
+#endif
+
return var;
}