Commit cc5d35d8 authored by RogerZhou's avatar RogerZhou Committed by Roger Zhou

hash based motion estimation for screen data

Change-Id: Iec7969ffd8f53ca2f4eefd1d757cfec7b3bde131
parent 3824f8ad
......@@ -476,6 +476,15 @@ if (CONFIG_WARPED_MOTION OR CONFIG_GLOBAL_MOTION)
endif ()
endif ()
if (CONFIG_HASH_ME)
set(AOM_AV1_ENCODER_SOURCES
${AOM_AV1_ENCODER_SOURCES}
"${AOM_ROOT}/av1/encoder/hash_motion.h"
"${AOM_ROOT}/av1/encoder/hash_motion.c"
"${AOM_ROOT}/third_party/vector/vector.h"
"${AOM_ROOT}/third_party/vector/vector.c")
endif ()
# Setup AV1 common/decoder/encoder targets. The libaom target must exist before
# this function is called.
function (setup_av1_targets)
......
......@@ -108,6 +108,12 @@ AV1_CX_SRCS-yes += encoder/temporal_filter.c
AV1_CX_SRCS-yes += encoder/temporal_filter.h
AV1_CX_SRCS-yes += encoder/mbgraph.c
AV1_CX_SRCS-yes += encoder/mbgraph.h
ifeq ($(CONFIG_HASH_ME),yes)
AV1_CX_SRCS-yes += ../third_party/vector/vector.h
AV1_CX_SRCS-yes += ../third_party/vector/vector.c
AV1_CX_SRCS-yes += encoder/hash_motion.c
AV1_CX_SRCS-yes += encoder/hash_motion.h
endif
ifeq ($(CONFIG_CDEF),yes)
AV1_CX_SRCS-yes += encoder/pickcdef.c
endif
......
......@@ -86,6 +86,9 @@ void av1_free_ref_frame_buffers(BufferPool *pool) {
aom_free(pool->frame_bufs[i].mvs);
pool->frame_bufs[i].mvs = NULL;
aom_free_frame_buffer(&pool->frame_bufs[i].buf);
#if CONFIG_HASH_ME
av1_hash_table_destroy(&pool->frame_bufs[i].hash_table);
#endif
}
}
......
......@@ -38,6 +38,10 @@
#if CONFIG_CFL
#include "av1/common/cfl.h"
#endif
#if CONFIG_HASH_ME
// TODO(youzhou@microsoft.com): Encoder only. Move it out of common
#include "av1/encoder/hash_motion.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
......@@ -127,6 +131,9 @@ typedef struct {
#endif // CONFIG_GLOBAL_MOTION
aom_codec_frame_buffer_t raw_frame_buffer;
YV12_BUFFER_CONFIG buf;
#if CONFIG_HASH_ME
hash_table hash_table;
#endif
#if CONFIG_TEMPMV_SIGNALING
uint8_t intra_only;
#endif
......
......@@ -45,6 +45,9 @@
#endif
#include "av1/encoder/ethread.h"
#include "av1/encoder/firstpass.h"
#if CONFIG_HASH_ME
#include "av1/encoder/hash_motion.h"
#endif
#include "av1/encoder/mbgraph.h"
#include "av1/encoder/picklpf.h"
#if CONFIG_LOOP_RESTORATION
......@@ -5362,6 +5365,11 @@ static void init_ref_frame_bufs(AV1_COMMON *cm) {
cm->ref_frame_map[i] = INVALID_IDX;
pool->frame_bufs[i].ref_count = 0;
}
#if CONFIG_HASH_ME
for (i = 0; i < FRAME_BUFFERS; ++i) {
av1_hash_table_init(&pool->frame_bufs[i].hash_table);
}
#endif
}
static void check_initial_width(AV1_COMP *cpi,
......@@ -6085,6 +6093,71 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
Pass0Encode(cpi, size, dest, 0, frame_flags);
}
#endif
#if CONFIG_HASH_ME
if (oxcf->pass != 1 && cpi->common.allow_screen_content_tools) {
// add to hash table
const int pic_width = cpi->source->y_crop_width;
const int pic_height = cpi->source->y_crop_height;
uint32_t *block_hash_values[2][2];
int8_t *is_block_same[2][3];
int k, j;
for (k = 0; k < 2; k++) {
for (j = 0; j < 2; j++) {
CHECK_MEM_ERROR(cm, block_hash_values[k][j],
aom_malloc(sizeof(uint32_t) * pic_width * pic_height));
}
for (j = 0; j < 3; j++) {
CHECK_MEM_ERROR(cm, is_block_same[k][j],
aom_malloc(sizeof(int8_t) * pic_width * pic_height));
}
}
av1_hash_table_create(&cm->cur_frame->hash_table);
av1_generate_block_2x2_hash_value(cpi->source, block_hash_values[0],
is_block_same[0]);
av1_generate_block_hash_value(cpi->source, 4, block_hash_values[0],
block_hash_values[1], is_block_same[0],
is_block_same[1]);
av1_generate_block_hash_value(cpi->source, 8, block_hash_values[1],
block_hash_values[0], is_block_same[1],
is_block_same[0]);
av1_add_to_hash_map_by_row_with_precal_data(
&cm->cur_frame->hash_table, block_hash_values[0], is_block_same[0][2],
pic_width, pic_height, 8);
av1_generate_block_hash_value(cpi->source, 16, block_hash_values[0],
block_hash_values[1], is_block_same[0],
is_block_same[1]);
av1_add_to_hash_map_by_row_with_precal_data(
&cm->cur_frame->hash_table, block_hash_values[1], is_block_same[1][2],
pic_width, pic_height, 16);
av1_generate_block_hash_value(cpi->source, 32, block_hash_values[1],
block_hash_values[0], is_block_same[1],
is_block_same[0]);
av1_add_to_hash_map_by_row_with_precal_data(
&cm->cur_frame->hash_table, block_hash_values[0], is_block_same[0][2],
pic_width, pic_height, 32);
av1_generate_block_hash_value(cpi->source, 64, block_hash_values[0],
block_hash_values[1], is_block_same[0],
is_block_same[1]);
av1_add_to_hash_map_by_row_with_precal_data(
&cm->cur_frame->hash_table, block_hash_values[1], is_block_same[1][2],
pic_width, pic_height, 64);
for (k = 0; k < 2; k++) {
for (j = 0; j < 2; j++) {
aom_free(block_hash_values[k][j]);
}
for (j = 0; j < 3; j++) {
aom_free(is_block_same[k][j]);
}
}
}
#endif
#if CONFIG_NO_FRAME_CONTEXT_SIGNALING
cm->frame_contexts[cm->new_fb_idx] = *cm->fc;
#else
......
......@@ -692,6 +692,17 @@ static INLINE int get_ref_frame_buf_idx(const AV1_COMP *cpi,
return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : INVALID_IDX;
}
#if CONFIG_HASH_ME
static INLINE hash_table *get_ref_frame_hash_map(const AV1_COMP *cpi,
MV_REFERENCE_FRAME ref_frame) {
const AV1_COMMON *const cm = &cpi->common;
const int buf_idx = get_ref_frame_buf_idx(cpi, ref_frame);
return buf_idx != INVALID_IDX
? &cm->buffer_pool->frame_bufs[buf_idx].hash_table
: NULL;
}
#endif
static INLINE YV12_BUFFER_CONFIG *get_ref_frame_buffer(
const AV1_COMP *cpi, MV_REFERENCE_FRAME ref_frame) {
const AV1_COMMON *const cm = &cpi->common;
......
This diff is collapsed.
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AV1_ENCODER_HASH_MOTION_H_
#define AV1_ENCODER_HASH_MOTION_H_
#include "./aom_config.h"
#include "aom/aom_integer.h"
#include "aom_scale/yv12config.h"
#include "third_party/vector/vector.h"
#ifdef __cplusplus
extern "C" {
#endif
// store a block's hash info.
// x and y are the position from the top left of the picture
// hash_value2 is used to store the second hash value
typedef struct _block_hash {
int16_t x;
int16_t y;
uint32_t hash_value2;
} block_hash;
typedef struct _hash_table { Vector **p_lookup_table; } hash_table;
void av1_hash_table_init(hash_table *p_hash_table);
void av1_hash_table_destroy(hash_table *p_hash_table);
void av1_hash_table_create(hash_table *p_hash_table);
int32_t av1_hash_table_count(hash_table *p_hash_table, uint32_t hash_value);
Iterator av1_hash_get_first_iterator(hash_table *p_hash_table,
uint32_t hash_value);
int32_t av1_has_exact_match(hash_table *p_hash_table, uint32_t hash_value1,
uint32_t hash_value2);
void av1_generate_block_2x2_hash_value(const YV12_BUFFER_CONFIG *picture,
uint32_t *pic_block_hash[2],
int8_t *pic_block_same_info[3]);
void av1_generate_block_hash_value(const YV12_BUFFER_CONFIG *picture,
int block_size,
uint32_t *src_pic_block_hash[2],
uint32_t *dst_pic_block_hash[2],
int8_t *src_pic_block_same_info[3],
int8_t *dst_pic_block_same_info[3]);
void av1_add_to_hash_map_by_row_with_precal_data(hash_table *p_hash_table,
uint32_t *pic_hash[2],
int8_t *pic_is_same,
int pic_width, int pic_height,
int block_size);
// check whether the block starts from (x_start, y_start) with the size of
// block_size x block_size has the same color in all rows
int av1_hash_is_horizontal_perfect(const YV12_BUFFER_CONFIG *picture,
int block_size, int x_start, int y_start);
// check whether the block starts from (x_start, y_start) with the size of
// block_size x block_size has the same color in all columns
int av1_hash_is_vertical_perfect(const YV12_BUFFER_CONFIG *picture,
int block_size, int x_start, int y_start);
void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size,
uint32_t *hash_value1, uint32_t *hash_value2);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AV1_ENCODER_HASH_MOTION_H_
......@@ -2562,10 +2562,45 @@ static int is_exhaustive_allowed(const AV1_COMP *const cpi, MACROBLOCK *x) {
(*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 @@ int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
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;
}
......
......@@ -131,10 +131,17 @@ int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range,
struct AV1_COMP;
#if CONFIG_HASH_ME
int av1_full_pixel_search(const struct 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 struct 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
#if CONFIG_MOTION_VAR
int av1_obmc_full_pixel_diamond(const struct AV1_COMP *cpi, MACROBLOCK *x,
......
......@@ -7173,9 +7173,16 @@ static void single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x,
switch (mbmi->motion_mode) {
case SIMPLE_TRANSLATION:
#endif // CONFIG_MOTION_VAR
#if CONFIG_HASH_ME
bestsme = av1_full_pixel_search(cpi, x, bsize, &mvp_full, step_param,
sadpb, cond_cost_list(cpi, cost_list),
&ref_mv, INT_MAX, 1);
&ref_mv, INT_MAX, 1, (MI_SIZE * mi_col),
(MI_SIZE * mi_row));
#else
bestsme = av1_full_pixel_search(cpi, x, bsize, &mvp_full, step_param, sadpb,
cond_cost_list(cpi, cost_list), &ref_mv,
INT_MAX, 1);
#endif
#if CONFIG_MOTION_VAR
break;
case OBMC_CAUSAL:
......@@ -9793,9 +9800,15 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x,
mvp_full.row >>= 3;
int sadpb = x->sadperbit16;
int cost_list[5];
#if CONFIG_HASH_ME
int bestsme = av1_full_pixel_search(cpi, x, bsize, &mvp_full, step_param,
sadpb, cond_cost_list(cpi, cost_list),
&dv_ref.as_mv, INT_MAX, 1, -1, -1);
#else
int bestsme = av1_full_pixel_search(cpi, x, bsize, &mvp_full, step_param,
sadpb, cond_cost_list(cpi, cost_list),
&dv_ref.as_mv, INT_MAX, 1);
#endif
x->mv_limits = tmp_mv_limits;
if (bestsme == INT_MAX) continue;
......
......@@ -340,6 +340,7 @@ EXPERIMENT_LIST="
uv_lvl
no_frame_context_signaling
txmg
hash_me
"
CONFIG_LIST="
dependency_tracking
......
This diff is collapsed.
/*
The MIT License(MIT)
Copyright(c) 2016 Peter Goldsborough
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files(the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef VECTOR_H
#define VECTOR_H
#include <stdbool.h>
#include <stddef.h>
/***** DEFINITIONS *****/
#define VECTOR_MINIMUM_CAPACITY 2
#define VECTOR_GROWTH_FACTOR 2
#define VECTOR_SHRINK_THRESHOLD (1 / 4)
#define VECTOR_ERROR -1
#define VECTOR_SUCCESS 0
#define VECTOR_UNINITIALIZED NULL
#define VECTOR_INITIALIZER \
{ 0, 0, 0, VECTOR_UNINITIALIZED }
/***** STRUCTURES *****/
typedef struct Vector {
size_t size;
size_t capacity;
size_t element_size;
void *data;
} Vector;
typedef struct Iterator {
void *pointer;
size_t element_size;
} Iterator;
/***** METHODS *****/
/* Constructor */
int vector_setup(Vector *vector, size_t capacity, size_t element_size);
/* Copy Constructor */
int vector_copy(Vector *destination, Vector *source);
/* Copy Assignment */
int vector_copy_assign(Vector *destination, Vector *source);
/* Move Constructor */
int vector_move(Vector *destination, Vector *source);
/* Move Assignment */
int vector_move_assign(Vector *destination, Vector *source);
int vector_swap(Vector *destination, Vector *source);
/* Destructor */
int vector_destroy(Vector *vector);
/* Insertion */
int vector_push_back(Vector *vector, void *element);
int vector_push_front(Vector *vector, void *element);
int vector_insert(Vector *vector, size_t index, void *element);
int vector_assign(Vector *vector, size_t index, void *element);
/* Deletion */
int vector_pop_back(Vector *vector);
int vector_pop_front(Vector *vector);
int vector_erase(Vector *vector, size_t index);
int vector_clear(Vector *vector);
/* Lookup */
void *vector_get(Vector *vector, size_t index);
const void *vector_const_get(const Vector *vector, size_t index);
void *vector_front(Vector *vector);
void *vector_back(Vector *vector);
#define VECTOR_GET_AS(type, vector_pointer, index) \
*((type *)vector_get((vector_pointer), (index)))
/* Information */
bool vector_is_initialized(const Vector *vector);
size_t vector_byte_size(const Vector *vector);
size_t vector_free_space(const Vector *vector);
bool vector_is_empty(const Vector *vector);
/* Memory management */
int vector_resize(Vector *vector, size_t new_size);
int vector_reserve(Vector *vector, size_t minimum_capacity);
int vector_shrink_to_fit(Vector *vector);
/* Iterators */
Iterator vector_begin(Vector *vector);
Iterator vector_end(Vector *vector);
Iterator vector_iterator(Vector *vector, size_t index);
void *iterator_get(Iterator *iterator);
#define ITERATOR_GET_AS(type, iterator) *((type *)iterator_get((iterator)))
int iterator_erase(Vector *vector, Iterator *iterator);
void iterator_increment(Iterator *iterator);
void iterator_decrement(Iterator *iterator);
void *iterator_next(Iterator *iterator);
void *iterator_previous(Iterator *iterator);
bool iterator_equals(Iterator *first, Iterator *second);
bool iterator_is_before(Iterator *first, Iterator *second);
bool iterator_is_after(Iterator *first, Iterator *second);
size_t iterator_index(Vector *vector, Iterator *iterator);
#define VECTOR_FOR_EACH(vector_pointer, iterator_name) \
for (Iterator(iterator_name) = vector_begin((vector_pointer)), \
end = vector_end((vector_pointer)); \
!iterator_equals(&(iterator_name), &end); \
iterator_increment(&(iterator_name)))
/***** PRIVATE *****/
#define MAX(a, b) ((a) > (b) ? (a) : (b))
bool _vector_should_grow(Vector *vector);
bool _vector_should_shrink(Vector *vector);
size_t _vector_free_bytes(const Vector *vector);
void *_vector_offset(Vector *vector, size_t index);
const void *_vector_const_offset(const Vector *vector, size_t index);
void _vector_assign(Vector *vector, size_t index, void *element);
int _vector_move_right(Vector *vector, size_t index);
void _vector_move_left(Vector *vector, size_t index);
int _vector_adjust_capacity(Vector *vector);
int _vector_reallocate(Vector *vector, size_t new_capacity);
void _vector_swap(size_t *first, size_t *second);
#endif /* VECTOR_H */
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