Analyze motion field to produce reference motion vectors

This commit allows the codec to analyze the motion field in the
avaiable above and left neighboring area to produce a set of
reference motion vectors for each reference frame. These reference
motion vectors are ranked according to the likelihood that it will
be picked.

Change-Id: I82e6cd990a7716848bb7b6f5f2b1829966ff2483
This commit is contained in:
Jingning Han
2015-11-23 12:05:48 -08:00
parent c335bfeb56
commit 254d3e172a
3 changed files with 241 additions and 0 deletions

View File

@@ -200,6 +200,9 @@ typedef uint8_t PREDICTION_MODE;
/* Segment Feature Masks */
#define MAX_MV_REF_CANDIDATES 2
#if CONFIG_REF_MV
#define MAX_REF_MV_STACK_SIZE 16
#endif
#define INTRA_INTER_CONTEXTS 4
#define COMP_INTER_CONTEXTS 5

View File

@@ -11,6 +11,232 @@
#include "vp10/common/mvref_common.h"
#if CONFIG_REF_MV
static void scan_row_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd,
const int mi_row, const int mi_col, int block,
const MV_REFERENCE_FRAME ref_frame,
int row_offset,
CANDIDATE_MV *ref_mv_stack,
int *refmv_count) {
const TileInfo *const tile = &xd->tile;
int i;
for (i = 0; i < xd->n8_w && *refmv_count < MAX_REF_MV_STACK_SIZE;) {
POSITION mi_pos;
mi_pos.row = row_offset;
mi_pos.col = i;
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, &mi_pos)) {
const MODE_INFO *const candidate_mi =
xd->mi[mi_pos.row * xd->mi_stride + mi_pos.col];
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
const int len = VPXMIN(xd->n8_w,
num_8x8_blocks_wide_lookup[candidate->sb_type]);
const int weight = len;
int index = 0, ref;
for (ref = 0; ref < 2; ++ref) {
if (candidate->ref_frame[ref] == ref_frame) {
int_mv this_refmv =
get_sub_block_mv(candidate_mi, ref, mi_pos.col, block);
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int)
break;
if (index < *refmv_count)
ref_mv_stack[index].weight += weight;
// Add a new item to the list.
if (index == *refmv_count) {
ref_mv_stack[index].this_mv = this_refmv;
ref_mv_stack[index].weight = weight;
++(*refmv_count);
}
}
}
i += len;
} else {
++i;
}
}
}
static void scan_col_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd,
const int mi_row, const int mi_col, int block,
const MV_REFERENCE_FRAME ref_frame,
int col_offset,
CANDIDATE_MV *ref_mv_stack,
int *refmv_count) {
const TileInfo *const tile = &xd->tile;
int i;
for (i = 0; i < xd->n8_h && *refmv_count < MAX_REF_MV_STACK_SIZE;) {
POSITION mi_pos;
mi_pos.row = i;
mi_pos.col = col_offset;
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, &mi_pos)) {
const MODE_INFO *const candidate_mi =
xd->mi[mi_pos.row * xd->mi_stride + mi_pos.col];
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
const int len = VPXMIN(xd->n8_h,
num_8x8_blocks_high_lookup[candidate->sb_type]);
const int weight = len;
int index = 0, ref;
for (ref = 0; ref < 2; ++ref) {
if (candidate->ref_frame[ref] == ref_frame) {
int_mv this_refmv =
get_sub_block_mv(candidate_mi, ref, mi_pos.col, block);
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int)
break;
if (index < *refmv_count)
ref_mv_stack[index].weight += weight;
if (index == *refmv_count) {
ref_mv_stack[index].this_mv = this_refmv;
ref_mv_stack[index].weight = weight;
++(*refmv_count);
}
}
}
i += len;
} else {
++i;
}
}
}
static void scan_blk_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd,
const int mi_row, const int mi_col, int block,
const MV_REFERENCE_FRAME ref_frame,
int row_offset, int col_offset,
CANDIDATE_MV *ref_mv_stack,
int *refmv_count) {
const TileInfo *const tile = &xd->tile;
POSITION mi_pos;
mi_pos.row = row_offset;
mi_pos.col = col_offset;
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, &mi_pos) &&
*refmv_count < MAX_REF_MV_STACK_SIZE) {
const MODE_INFO *const candidate_mi =
xd->mi[mi_pos.row * xd->mi_stride + mi_pos.col];
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
const int len = 1;
const int weight = len;
int index = 0, ref;
for (ref = 0; ref < 2; ++ref) {
if (candidate->ref_frame[ref] == ref_frame) {
int_mv this_refmv =
get_sub_block_mv(candidate_mi, ref, mi_pos.col, block);
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int)
break;
if (index < *refmv_count)
ref_mv_stack[index].weight += weight;
if (index == *refmv_count) {
ref_mv_stack[index].this_mv = this_refmv;
ref_mv_stack[index].weight = weight;
++(*refmv_count);
}
}
}
} // Analyze a single 8x8 block motion information.
}
static void setup_ref_mv_list(const VP10_COMMON *cm, const MACROBLOCKD *xd,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
int_mv *mv_ref_list,
int block, int mi_row, int mi_col,
uint8_t *mode_context) {
int idx, refmv_count = 0, nearest_refmv_count = 0;
const int bw = num_8x8_blocks_wide_lookup[mi->mbmi.sb_type] << 3;
const int bh = num_8x8_blocks_high_lookup[mi->mbmi.sb_type] << 3;
CANDIDATE_MV ref_mv_stack[MAX_REF_MV_STACK_SIZE];
CANDIDATE_MV tmp_mv;
int len, nr_len;
(void) mode_context;
memset(ref_mv_stack, 0, sizeof(ref_mv_stack));
// Scan the first above row mode info.
scan_row_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-1, ref_mv_stack, &refmv_count);
// Scan the first left column mode info.
scan_col_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-1, ref_mv_stack, &refmv_count);
nearest_refmv_count = refmv_count;
// Analyze the top-left corner block mode info.
// scan_blk_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
// -1, -1, ref_mv_stack, &refmv_count);
// Scan the second outer area.
scan_row_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-2, ref_mv_stack, &refmv_count);
scan_col_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-2, ref_mv_stack, &refmv_count);
// Scan the third outer area.
scan_row_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-3, ref_mv_stack, &refmv_count);
scan_col_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-3, ref_mv_stack, &refmv_count);
// Scan the fourth outer area.
scan_row_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-4, ref_mv_stack, &refmv_count);
// Scan the third left row mode info.
scan_col_mbmi(cm, xd, mi_row, mi_col, block, ref_frame,
-4, ref_mv_stack, &refmv_count);
// Rank the likelihood and assign nearest and near mvs.
len = nearest_refmv_count;
while (len > 0) {
nr_len = 0;
for (idx = 1; idx < len; ++idx) {
if (ref_mv_stack[idx - 1].weight < ref_mv_stack[idx].weight) {
tmp_mv = ref_mv_stack[idx - 1];
ref_mv_stack[idx - 1] = ref_mv_stack[idx];
ref_mv_stack[idx] = tmp_mv;
nr_len = idx;
}
}
len = nr_len;
}
len = refmv_count;
while (len > nearest_refmv_count) {
nr_len = nearest_refmv_count;
for (idx = nearest_refmv_count + 1; idx < len; ++idx) {
if (ref_mv_stack[idx - 1].weight < ref_mv_stack[idx].weight) {
tmp_mv = ref_mv_stack[idx - 1];
ref_mv_stack[idx - 1] = ref_mv_stack[idx];
ref_mv_stack[idx] = tmp_mv;
nr_len = idx;
}
}
len = nr_len;
}
for (idx = 0; idx < VPXMIN(MAX_MV_REF_CANDIDATES, refmv_count); ++idx) {
mv_ref_list[idx].as_int = ref_mv_stack[idx].this_mv.as_int;
clamp_mv_ref(&mv_ref_list[idx].as_mv, bw, bh, xd);
}
}
#endif
// This function searches the neighbourhood of a given MB/SB
// to try and find candidate reference vectors.
static void find_mv_refs_idx(const VP10_COMMON *cm, const MACROBLOCKD *xd,
@@ -153,6 +379,11 @@ void vp10_find_mv_refs(const VP10_COMMON *cm, const MACROBLOCKD *xd,
uint8_t *mode_context) {
find_mv_refs_idx(cm, xd, mi, ref_frame, mv_ref_list, -1,
mi_row, mi_col, sync, data, mode_context);
#if CONFIG_REF_MV
setup_ref_mv_list(cm, xd, mi, ref_frame, mv_ref_list, -1,
mi_row, mi_col, mode_context);
#endif
}
static void lower_mv_precision(MV *mv, int allow_hp) {

View File

@@ -24,6 +24,13 @@ typedef struct position {
int col;
} POSITION;
#if CONFIG_REF_MV
typedef struct candidate_mv {
int_mv this_mv;
int weight;
} CANDIDATE_MV;
#endif
typedef enum {
BOTH_ZERO = 0,
ZERO_PLUS_PREDICTED = 1,