830 lines
28 KiB
C
830 lines
28 KiB
C
/*
|
|
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "vp9/common/vp9_mvref_common.h"
|
|
|
|
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
// This function returns either the appropriate subblock or block's mv,
|
|
// depending on whether block_size < 8x8 for both current block and the
|
|
// examined candidate block.
|
|
static int_mv get_subblock_mv(const MODE_INFO *candidate,
|
|
const MODE_INFO *current,
|
|
int curr_blk_idx, int ref,
|
|
int search_row, int search_col) {
|
|
int candidate_type = candidate->mbmi.sb_type;
|
|
|
|
if (curr_blk_idx >= 0 && candidate_type < BLOCK_8X8) {
|
|
int candidate_blk_idx = 0;
|
|
assert(current->mbmi.sb_type < BLOCK_8X8);
|
|
|
|
// Both current block and the candidate block are in sub8x8 mode
|
|
if ((search_row == -1 && search_col == 0) || // top
|
|
(search_row == 0 && search_col == -1)) { // left
|
|
int i = curr_blk_idx + current->mbmi.sb_type * 4;
|
|
int j = (search_row == 0); // top: 0; left: 1
|
|
|
|
candidate_blk_idx = idx_to_subblock_top_left[i][j][candidate_type];
|
|
return (candidate_blk_idx >= 0) ?
|
|
candidate->bmi[candidate_blk_idx].as_mv[ref] :
|
|
candidate->mbmi.mv[ref];
|
|
} else if ((search_row == -1 && search_col == 1) || // top_right
|
|
(search_row == -1 && search_col == -1)) { // top_left
|
|
candidate_blk_idx =
|
|
idx_to_subblock_topright_topleft[search_col == -1][candidate_type];
|
|
return candidate->bmi[candidate_blk_idx].as_mv[ref];
|
|
}
|
|
}
|
|
|
|
return candidate->mbmi.mv[ref];
|
|
}
|
|
|
|
static int get_mvref_zone_idx(const TileInfo *const tile, int bsize,
|
|
int mi_row, int mi_col) {
|
|
int mvref_zone_idx = 0;
|
|
int row_8x8 = mi_row % 8;
|
|
int col_8x8 = mi_col % 8;
|
|
|
|
switch (bsize) {
|
|
case BLOCK_4X4:
|
|
case BLOCK_4X8:
|
|
case BLOCK_8X4:
|
|
case BLOCK_8X8:
|
|
mvref_zone_idx =
|
|
(mi_col >= (tile->mi_col_end - 1) || // right-most column
|
|
(mv_ref_topright_avail_8x8[row_8x8][col_8x8] == 0)) ? 1 : 0;
|
|
break;
|
|
default:
|
|
// Only <= BLOCK_8X8 are supported currently
|
|
assert(0);
|
|
break;
|
|
}
|
|
return mvref_zone_idx;
|
|
}
|
|
|
|
// This function searches the neighbourhood of a given MB/SB
|
|
// to try to find candidate reference vectors.
|
|
static void find_mv_refs_idx_8x8(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
|
const TileInfo *const tile,
|
|
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
|
int_mv *mv_ref_list,
|
|
int block, int mi_row, int mi_col) {
|
|
int_mv mv_ref_candidates[MAX_MV_REF_CANDIDATES + 1];
|
|
const int *ref_sign_bias = cm->ref_frame_sign_bias;
|
|
int i;
|
|
int refmv_count = 0;
|
|
int different_ref_found = 0;
|
|
|
|
int zone_idx = get_mvref_zone_idx(tile, mi->mbmi.sb_type, mi_row, mi_col);
|
|
int max_nearest_blks = (zone_idx == 0) ? 4 : 3;
|
|
const POSITION *mv_ref_search = mv_ref_blocks_8x8[zone_idx];
|
|
|
|
// Zero out the mv reference vector list
|
|
vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
|
|
vpx_memset(mv_ref_candidates, 0,
|
|
sizeof(*mv_ref_candidates) * (MAX_MV_REF_CANDIDATES + 1));
|
|
|
|
// The nearest 4 (when top right is available) or 3 neighboring blocks
|
|
// are treated differently:
|
|
// If their block size < 8x8, we get the mv from the bmi substructure.
|
|
for (i = 0; i < max_nearest_blks; ++i) {
|
|
const POSITION *const mv_ref = &mv_ref_search[i];
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
|
const MODE_INFO *const candidate_mi =
|
|
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi;
|
|
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
|
|
|
|
different_ref_found = 1;
|
|
|
|
if (candidate->ref_frame[0] == ref_frame) {
|
|
ADD_MV_REF_CANDIDATE(get_subblock_mv(
|
|
candidate_mi, mi, block, 0, mv_ref->row, mv_ref->col));
|
|
} else if (candidate->ref_frame[1] == ref_frame) {
|
|
ADD_MV_REF_CANDIDATE(get_subblock_mv(
|
|
candidate_mi, mi, block, 1, mv_ref->row, mv_ref->col));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the rest of the neighbors in much the same way as before
|
|
// except we don't need to keep track of subblocks.
|
|
for (; i < MVREF_NEIGHBOURS; ++i) {
|
|
const POSITION *const mv_ref = &mv_ref_search[i];
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
|
const MB_MODE_INFO *const candidate =
|
|
&xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi->mbmi;
|
|
|
|
different_ref_found = 1;
|
|
|
|
if (candidate->ref_frame[0] == ref_frame)
|
|
ADD_MV_REF_CANDIDATE(candidate->mv[0]);
|
|
else if (candidate->ref_frame[1] == ref_frame)
|
|
ADD_MV_REF_CANDIDATE(candidate->mv[1]);
|
|
}
|
|
}
|
|
|
|
// Since we couldn't find 3 mvs from the same reference frame,
|
|
// go back through the neighbors and find motion vectors from
|
|
// different reference frames.
|
|
if (different_ref_found) {
|
|
for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
|
|
const POSITION *mv_ref = &mv_ref_search[i];
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
|
const MB_MODE_INFO *const candidate =
|
|
&xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi->mbmi;
|
|
|
|
// If the candidate is INTRA we don't want to consider its mv.
|
|
IF_DIFF_REF_FRAME_ADD_MV_CANDIDATE(candidate);
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
if (refmv_count == 2) {
|
|
mv_ref_list[0].as_mv.row =
|
|
(mv_ref_candidates[0].as_mv.row + mv_ref_candidates[1].as_mv.row) >> 1;
|
|
mv_ref_list[0].as_mv.col =
|
|
(mv_ref_candidates[0].as_mv.col + mv_ref_candidates[1].as_mv.col) >> 1;
|
|
mv_ref_list[1].as_int = mv_ref_candidates[2].as_int;
|
|
} else {
|
|
for (i = 0; i < 2; ++i) {
|
|
mv_ref_list[i].as_int = mv_ref_candidates[i].as_int;
|
|
}
|
|
}
|
|
|
|
// Clamp vectors
|
|
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
|
|
clamp_mv_ref(&mv_ref_list[i].as_mv, xd);
|
|
}
|
|
|
|
typedef enum MV_SEARCH_POS {
|
|
TOP = 0,
|
|
LEFT = 1,
|
|
TOPLEFT = 2,
|
|
TOPRIGHT = 3,
|
|
TOPRIGHT_ALT = 4,
|
|
NUM_SEARCH_POS = 5
|
|
} MV_SEARCH_POS;
|
|
|
|
// Adaptive median
|
|
static int get_adaptive_median(int topright, int left, int topleft) {
|
|
int a = topright;
|
|
int b = left;
|
|
int c = topright + left - topleft;
|
|
|
|
if (a >= b) {
|
|
if (b >= c) return b;
|
|
else if (a >= c) return c;
|
|
else return a;
|
|
} else {
|
|
if (b < c) return b;
|
|
else if (a >= c) return a;
|
|
else return c;
|
|
}
|
|
}
|
|
|
|
// This function searches the neighbourhood of a given MB/SB to try
|
|
// to find the nearestmv through adaptive median filtering.
|
|
static int find_best_mvref_8x8(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
|
const TileInfo *const tile,
|
|
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
|
int_mv *best_mvref,
|
|
int block, int mi_row, int mi_col) {
|
|
int i;
|
|
int zone_idx = get_mvref_zone_idx(tile, mi->mbmi.sb_type, mi_row, mi_col);
|
|
int max_nearest_blks = (zone_idx == 0) ? 4 : 3;
|
|
|
|
const POSITION adapt_median_neighbor_pos[NUM_SEARCH_POS - 1] = {
|
|
// TOP, LEFT, TOPLEFT, TOPRIGHT
|
|
{-1, 0}, {0, -1}, {-1, -1}, {-1, 1}
|
|
};
|
|
int_mv mv_ref_mvs[NUM_SEARCH_POS];
|
|
int is_avail[NUM_SEARCH_POS] = { 0, 0, 0, 0, 0 };
|
|
|
|
vpx_memset(mv_ref_mvs, 0, sizeof(mv_ref_mvs[0]) * NUM_SEARCH_POS);
|
|
|
|
// If the neighboring block size < 8x8, the mv is obtained from
|
|
// the bmi substructure.
|
|
for (i = 0; i < max_nearest_blks; ++i) {
|
|
const POSITION *const mv_ref_pos = &adapt_median_neighbor_pos[i];
|
|
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref_pos)) {
|
|
const MODE_INFO *const candidate_mi =
|
|
xd->mi[mv_ref_pos->col + mv_ref_pos->row * xd->mi_stride].src_mi;
|
|
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
|
|
|
|
if (candidate->ref_frame[0] == ref_frame) {
|
|
mv_ref_mvs[i] = get_subblock_mv(candidate_mi, mi, block, 0,
|
|
mv_ref_pos->row, mv_ref_pos->col);
|
|
is_avail[i] = 1;
|
|
} else if (candidate->ref_frame[1] == ref_frame) {
|
|
mv_ref_mvs[i] = get_subblock_mv(candidate_mi, mi, block, 1,
|
|
mv_ref_pos->row, mv_ref_pos->col);
|
|
is_avail[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_avail[TOP] && is_avail[TOPRIGHT]) {
|
|
mv_ref_mvs[TOPRIGHT_ALT].as_mv.row =
|
|
(mv_ref_mvs[TOP].as_mv.row + mv_ref_mvs[TOPRIGHT].as_mv.row) >> 1;
|
|
mv_ref_mvs[TOPRIGHT_ALT].as_mv.col =
|
|
(mv_ref_mvs[TOP].as_mv.col + mv_ref_mvs[TOPRIGHT].as_mv.col) >> 1;
|
|
} else if (is_avail[TOP]) {
|
|
mv_ref_mvs[TOPRIGHT_ALT].as_int = mv_ref_mvs[TOP].as_int;
|
|
} else if (is_avail[TOPRIGHT]) {
|
|
mv_ref_mvs[TOPRIGHT_ALT].as_int = mv_ref_mvs[TOPRIGHT].as_int;
|
|
}
|
|
|
|
if (is_avail[TOP] || is_avail[LEFT] || is_avail[TOPLEFT] ||
|
|
is_avail[TOPRIGHT]) {
|
|
best_mvref->as_mv.row = get_adaptive_median(
|
|
mv_ref_mvs[TOPRIGHT_ALT].as_mv.row,
|
|
mv_ref_mvs[LEFT].as_mv.row,
|
|
mv_ref_mvs[TOPLEFT].as_mv.row);
|
|
best_mvref->as_mv.col = get_adaptive_median(
|
|
mv_ref_mvs[TOPRIGHT_ALT].as_mv.col,
|
|
mv_ref_mvs[LEFT].as_mv.col,
|
|
mv_ref_mvs[TOPLEFT].as_mv.col);
|
|
|
|
// Clamp vectors
|
|
clamp_mv_ref(&(best_mvref->as_mv), xd);
|
|
return 1;
|
|
} else {
|
|
best_mvref->as_int = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
|
|
// This function searches the neighbourhood of a given MB/SB
|
|
// to try and find candidate reference vectors.
|
|
static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
|
const TileInfo *const tile,
|
|
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
|
int_mv *mv_ref_list,
|
|
int block, int mi_row, int mi_col) {
|
|
const int *ref_sign_bias = cm->ref_frame_sign_bias;
|
|
int i, refmv_count = 0;
|
|
const MODE_INFO *prev_mi = !cm->error_resilient_mode && cm->prev_mi
|
|
? cm->prev_mi[mi_row * xd->mi_stride + mi_col].src_mi
|
|
: NULL;
|
|
const MB_MODE_INFO *const prev_mbmi = prev_mi ? &prev_mi->mbmi : NULL;
|
|
const POSITION *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type];
|
|
int different_ref_found = 0;
|
|
#if !CONFIG_NEW_INTER
|
|
int context_counter = 0;
|
|
#endif // !CONFIG_NEW_INTER
|
|
|
|
// Blank the reference vector list
|
|
vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
|
|
|
|
// The nearest 2 blocks are treated differently
|
|
// if the size < 8x8 we get the mv from the bmi substructure,
|
|
// and we also need to keep a mode count.
|
|
for (i = 0; i < 2; ++i) {
|
|
const POSITION *const mv_ref = &mv_ref_search[i];
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
|
const MODE_INFO *const candidate_mi = xd->mi[mv_ref->col + mv_ref->row *
|
|
xd->mi_stride].src_mi;
|
|
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
|
|
// Keep counts for entropy encoding.
|
|
#if !CONFIG_NEW_INTER
|
|
context_counter += mode_2_counter[candidate->mode];
|
|
#endif // !CONFIG_NEW_INTER
|
|
different_ref_found = 1;
|
|
|
|
if (candidate->ref_frame[0] == ref_frame) {
|
|
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, mv_ref->col, block));
|
|
} else if (candidate->ref_frame[1] == ref_frame) {
|
|
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, mv_ref->col, block));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the rest of the neighbors in much the same way
|
|
// as before except we don't need to keep track of sub blocks or
|
|
// mode counts.
|
|
for (; i < MVREF_NEIGHBOURS; ++i) {
|
|
const POSITION *const mv_ref = &mv_ref_search[i];
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
|
const MB_MODE_INFO *const candidate = &xd->mi[mv_ref->col + mv_ref->row *
|
|
xd->mi_stride].src_mi->mbmi;
|
|
different_ref_found = 1;
|
|
|
|
if (candidate->ref_frame[0] == ref_frame)
|
|
ADD_MV_REF_LIST(candidate->mv[0]);
|
|
else if (candidate->ref_frame[1] == ref_frame)
|
|
ADD_MV_REF_LIST(candidate->mv[1]);
|
|
}
|
|
}
|
|
|
|
// Check the last frame's mode and mv info.
|
|
if (prev_mbmi) {
|
|
if (prev_mbmi->ref_frame[0] == ref_frame)
|
|
ADD_MV_REF_LIST(prev_mbmi->mv[0]);
|
|
else if (prev_mbmi->ref_frame[1] == ref_frame)
|
|
ADD_MV_REF_LIST(prev_mbmi->mv[1]);
|
|
}
|
|
|
|
// Since we couldn't find 2 mvs from the same reference frame
|
|
// go back through the neighbors and find motion vectors from
|
|
// different reference frames.
|
|
if (different_ref_found) {
|
|
for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
|
|
const POSITION *mv_ref = &mv_ref_search[i];
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
|
const MB_MODE_INFO *const candidate = &xd->mi[mv_ref->col + mv_ref->row
|
|
* xd->mi_stride].src_mi->mbmi;
|
|
|
|
// If the candidate is INTRA we don't want to consider its mv.
|
|
IF_DIFF_REF_FRAME_ADD_MV(candidate);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Since we still don't have a candidate we'll try the last frame.
|
|
if (prev_mbmi)
|
|
IF_DIFF_REF_FRAME_ADD_MV(prev_mbmi);
|
|
|
|
Done:
|
|
|
|
#if !CONFIG_NEW_INTER
|
|
mi->mbmi.mode_context[ref_frame] = counter_to_context[context_counter];
|
|
#endif // !CONFIG_NEW_INTER
|
|
|
|
// Clamp vectors
|
|
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
|
|
clamp_mv_ref(&mv_ref_list[i].as_mv, xd);
|
|
}
|
|
|
|
#if CONFIG_NEW_INTER
|
|
// This function keeps a mode count for a given MB/SB
|
|
void vp9_update_mv_context(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
|
const TileInfo *const tile,
|
|
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
|
int_mv *mv_ref_list,
|
|
int block, int mi_row, int mi_col) {
|
|
int i, refmv_count = 0;
|
|
const POSITION *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type];
|
|
int context_counter = 0;
|
|
|
|
// Blank the reference vector list
|
|
vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
|
|
|
|
// The nearest 2 blocks are examined only.
|
|
// If the size < 8x8, we get the mv from the bmi substructure;
|
|
for (i = 0; i < 2; ++i) {
|
|
const POSITION *const mv_ref = &mv_ref_search[i];
|
|
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
|
|
const MODE_INFO *const candidate_mi =
|
|
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi;
|
|
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
|
|
|
|
// Keep counts for entropy encoding.
|
|
context_counter += mode_2_counter[candidate->mode];
|
|
|
|
if (candidate->ref_frame[0] == ref_frame) {
|
|
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, mv_ref->col, block));
|
|
} else if (candidate->ref_frame[1] == ref_frame) {
|
|
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, mv_ref->col, block));
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
|
|
mi->mbmi.mode_context[ref_frame] = counter_to_context[context_counter];
|
|
}
|
|
#endif // CONFIG_NEW_INTER
|
|
|
|
void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
|
|
const TileInfo *const tile,
|
|
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
|
|
int_mv *mv_ref_list,
|
|
int mi_row, int mi_col) {
|
|
#if CONFIG_NEW_INTER
|
|
vp9_update_mv_context(cm, xd, tile, mi, ref_frame, mv_ref_list, -1,
|
|
mi_row, mi_col);
|
|
#if CONFIG_NEWMVREF
|
|
if (mi->mbmi.sb_type <= BLOCK_8X8) {
|
|
int_mv best_mvref;
|
|
find_best_mvref_8x8(cm, xd, tile, mi, ref_frame, &best_mvref,
|
|
-1, mi_row, mi_col);
|
|
find_mv_refs_idx_8x8(cm, xd, tile, mi, ref_frame, mv_ref_list,
|
|
-1, mi_row, mi_col);
|
|
if (best_mvref.as_int != 0) {
|
|
mv_ref_list[1].as_int = mv_ref_list[0].as_int;
|
|
mv_ref_list[0].as_int = best_mvref.as_int;
|
|
}
|
|
} else {
|
|
#endif // CONFIG_NEWMVREF
|
|
#endif // CONFIG_NEW_INTER
|
|
find_mv_refs_idx(cm, xd, tile, mi, ref_frame, mv_ref_list, -1,
|
|
mi_row, mi_col);
|
|
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
}
|
|
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
}
|
|
|
|
void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp,
|
|
int_mv *mvlist, int_mv *nearest, int_mv *near) {
|
|
int i;
|
|
// Make sure all the candidates are properly clamped etc
|
|
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
|
|
MV *mv = &mvlist[i].as_mv;
|
|
const int usehp = allow_hp && vp9_use_mv_hp(mv);
|
|
vp9_lower_mv_precision(mv, usehp);
|
|
clamp_mv2(mv, xd);
|
|
}
|
|
*nearest = mvlist[0];
|
|
*near = mvlist[1];
|
|
}
|
|
|
|
void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
|
|
const TileInfo *const tile,
|
|
int block, int ref, int mi_row, int mi_col,
|
|
#if CONFIG_NEW_INTER
|
|
int_mv *mv_list,
|
|
#endif // CONFIG_NEW_INTER
|
|
int_mv *nearest, int_mv *near) {
|
|
#if CONFIG_NEW_INTER
|
|
#if CONFIG_NEWMVREF
|
|
int_mv best_mvref;
|
|
#endif // CONFIG_NEWMVREF
|
|
#else
|
|
int_mv mv_list[MAX_MV_REF_CANDIDATES];
|
|
#endif // !CONFIG_NEW_INTER
|
|
MODE_INFO *const mi = xd->mi[0].src_mi;
|
|
b_mode_info *bmi = mi->bmi;
|
|
int n;
|
|
|
|
assert(MAX_MV_REF_CANDIDATES == 2);
|
|
|
|
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
find_best_mvref_8x8(cm, xd, tile, mi, mi->mbmi.ref_frame[ref],
|
|
&best_mvref, block, mi_row, mi_col);
|
|
find_mv_refs_idx_8x8(cm, xd, tile, mi, mi->mbmi.ref_frame[ref],
|
|
mv_list, block, mi_row, mi_col);
|
|
#else
|
|
find_mv_refs_idx(cm, xd, tile, mi, mi->mbmi.ref_frame[ref],
|
|
mv_list, block, mi_row, mi_col);
|
|
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
|
|
near->as_int = 0;
|
|
|
|
switch (block) {
|
|
case 0:
|
|
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
if (best_mvref.as_int != 0) {
|
|
nearest->as_int = best_mvref.as_int;
|
|
if (best_mvref.as_int != mv_list[0].as_int)
|
|
near->as_int = mv_list[0].as_int;
|
|
else
|
|
near->as_int = mv_list[1].as_int;
|
|
} else {
|
|
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
nearest->as_int = mv_list[0].as_int;
|
|
near->as_int = mv_list[1].as_int;
|
|
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
}
|
|
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
break;
|
|
case 1:
|
|
#if !CONFIG_NEW_INTER
|
|
case 2:
|
|
#endif // !CONFIG_NEW_INTER
|
|
nearest->as_int = bmi[0].as_mv[ref].as_int;
|
|
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
if (best_mvref.as_int != 0 &&
|
|
best_mvref.as_int != nearest->as_int)
|
|
near->as_int = best_mvref.as_int;
|
|
else
|
|
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
|
|
if (nearest->as_int != mv_list[n].as_int) {
|
|
near->as_int = mv_list[n].as_int;
|
|
break;
|
|
}
|
|
break;
|
|
#if CONFIG_NEW_INTER
|
|
case 2: {
|
|
#if CONFIG_NEWMVREF
|
|
if (bmi[0].as_mv[ref].as_int !=
|
|
bmi[1].as_mv[ref].as_int) {
|
|
// Average of TOP and TOPRIGHT
|
|
nearest->as_mv.row = (
|
|
bmi[0].as_mv[ref].as_mv.row +
|
|
bmi[1].as_mv[ref].as_mv.row) >> 1;
|
|
nearest->as_mv.col = (
|
|
bmi[0].as_mv[ref].as_mv.col +
|
|
bmi[1].as_mv[ref].as_mv.col) >> 1;
|
|
near->as_int = bmi[0].as_mv[ref].as_int;
|
|
} else {
|
|
nearest->as_int = bmi[0].as_mv[ref].as_int;
|
|
if (best_mvref.as_int != 0 &&
|
|
best_mvref.as_int != nearest->as_int) {
|
|
near->as_int = best_mvref.as_int;
|
|
} else {
|
|
for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
|
|
if (nearest->as_int != mv_list[n].as_int) {
|
|
near->as_int = mv_list[n].as_int;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
int_mv candidates[1 + MAX_MV_REF_CANDIDATES];
|
|
candidates[0] = bmi[1].as_mv[ref];
|
|
candidates[1] = mv_list[0];
|
|
candidates[2] = mv_list[1];
|
|
|
|
nearest->as_int = bmi[0].as_mv[ref].as_int;
|
|
for (n = 0; n < 1 + MAX_MV_REF_CANDIDATES; ++n)
|
|
if (nearest->as_int != candidates[n].as_int) {
|
|
near->as_int = candidates[n].as_int;
|
|
break;
|
|
}
|
|
#endif // CONFIG_NEWMVREF
|
|
break;
|
|
}
|
|
#endif // CONFIG_NEW_INTER
|
|
case 3: {
|
|
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
|
|
if (bmi[0].as_mv[ref].as_int != bmi[1].as_mv[ref].as_int ||
|
|
bmi[0].as_mv[ref].as_int != bmi[2].as_mv[ref].as_int ||
|
|
bmi[1].as_mv[ref].as_int != bmi[2].as_mv[ref].as_int) {
|
|
nearest->as_mv.row = get_adaptive_median(
|
|
bmi[1].as_mv[ref].as_mv.row,
|
|
bmi[2].as_mv[ref].as_mv.row,
|
|
bmi[0].as_mv[ref].as_mv.row);
|
|
nearest->as_mv.col = get_adaptive_median(
|
|
bmi[1].as_mv[ref].as_mv.col,
|
|
bmi[2].as_mv[ref].as_mv.col,
|
|
bmi[0].as_mv[ref].as_mv.col);
|
|
/*nearest->as_mv.row =
|
|
(bmi[0].as_mv[ref].as_mv.row +
|
|
bmi[1].as_mv[ref].as_mv.row +
|
|
(bmi[2].as_mv[ref].as_mv.row << 1)) >> 2;
|
|
nearest->as_mv.col =
|
|
(bmi[0].as_mv[ref].as_mv.col +
|
|
bmi[1].as_mv[ref].as_mv.col +
|
|
(bmi[2].as_mv[ref].as_mv.col << 1)) >> 2;*/
|
|
for (n = 2; n >= 0; --n)
|
|
if (nearest->as_int != bmi[n].as_mv[ref].as_int) {
|
|
near->as_int = bmi[n].as_mv[ref].as_int;
|
|
break;
|
|
}
|
|
} else {
|
|
nearest->as_int = bmi[2].as_mv[ref].as_int;
|
|
if (best_mvref.as_int != 0 &&
|
|
best_mvref.as_int != nearest->as_int) {
|
|
near->as_int = best_mvref.as_int;
|
|
} else {
|
|
for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
|
|
if (nearest->as_int != mv_list[n].as_int) {
|
|
near->as_int = mv_list[n].as_int;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
int_mv candidates[2 + MAX_MV_REF_CANDIDATES];
|
|
candidates[0] = bmi[1].as_mv[ref];
|
|
candidates[1] = bmi[0].as_mv[ref];
|
|
candidates[2] = mv_list[0];
|
|
candidates[3] = mv_list[1];
|
|
|
|
nearest->as_int = bmi[2].as_mv[ref].as_int;
|
|
for (n = 0; n < 2 + MAX_MV_REF_CANDIDATES; ++n)
|
|
if (nearest->as_int != candidates[n].as_int) {
|
|
near->as_int = candidates[n].as_int;
|
|
break;
|
|
}
|
|
#endif // CONFIG_NEW_INTER && CONFIG_NEWMREF
|
|
break;
|
|
}
|
|
default:
|
|
assert(0 && "Invalid block index.");
|
|
}
|
|
}
|
|
|
|
#if CONFIG_COPY_MODE
|
|
static int compare_interinfo(MB_MODE_INFO *mbmi, MB_MODE_INFO *ref_mbmi) {
|
|
if (mbmi == ref_mbmi) {
|
|
return 1;
|
|
} else {
|
|
int is_same;
|
|
#if CONFIG_INTERINTRA
|
|
MV_REFERENCE_FRAME mbmi_ref1_backup = mbmi->ref_frame[1];
|
|
MV_REFERENCE_FRAME refmbmi_ref1_backup = ref_mbmi->ref_frame[1];
|
|
|
|
if (mbmi->ref_frame[1] == INTRA_FRAME)
|
|
mbmi->ref_frame[1] = NONE;
|
|
if (ref_mbmi->ref_frame[1] == INTRA_FRAME)
|
|
ref_mbmi->ref_frame[1] = NONE;
|
|
#endif // CONFIG_INTERINTRA
|
|
if (mbmi->ref_frame[0] == ref_mbmi->ref_frame[0] &&
|
|
mbmi->ref_frame[1] == ref_mbmi->ref_frame[1]) {
|
|
if (mbmi->ref_frame[1] > INTRA_FRAME)
|
|
is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int &&
|
|
mbmi->mv[1].as_int == ref_mbmi->mv[1].as_int &&
|
|
mbmi->interp_filter == ref_mbmi->interp_filter;
|
|
else
|
|
is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int &&
|
|
mbmi->interp_filter == ref_mbmi->interp_filter;
|
|
} else {
|
|
is_same = 0;
|
|
}
|
|
#if CONFIG_INTERINTRA
|
|
mbmi->ref_frame[1] = mbmi_ref1_backup;
|
|
ref_mbmi->ref_frame[1] = refmbmi_ref1_backup;
|
|
#endif // CONFIG_INTERINTRA
|
|
|
|
return is_same;
|
|
}
|
|
}
|
|
|
|
static int check_inside(const TileInfo *const tile, int mi_row, int mi_col) {
|
|
return mi_row >= tile->mi_row_start && mi_col >= tile->mi_col_start &&
|
|
mi_row < tile->mi_row_end && mi_col < tile->mi_col_end;
|
|
}
|
|
|
|
static int is_right_available(BLOCK_SIZE bsize,
|
|
#if CONFIG_EXT_PARTITION
|
|
PARTITION_TYPE partition,
|
|
#endif
|
|
int mi_row, int mi_col) {
|
|
int depth, max_depth = (CODING_UNIT_SIZE_LOG2 - 2) -
|
|
MIN(b_width_log2_lookup[bsize], b_height_log2_lookup[bsize]);
|
|
int block[(CODING_UNIT_SIZE_LOG2 - 2)] = {0};
|
|
|
|
if (bsize == BLOCK_LARGEST)
|
|
return 1;
|
|
mi_row = mi_row % MI_BLOCK_SIZE;
|
|
mi_col = mi_col % MI_BLOCK_SIZE;
|
|
for (depth = 1; depth <= max_depth; depth++) {
|
|
block[depth] = (mi_row >> (MI_BLOCK_SIZE_LOG2 - depth)) * 2 +
|
|
(mi_col >> (MI_BLOCK_SIZE_LOG2 - depth));
|
|
mi_row = mi_row % (MI_BLOCK_SIZE >> depth);
|
|
mi_col = mi_col % (MI_BLOCK_SIZE >> depth);
|
|
}
|
|
|
|
if (b_width_log2_lookup[bsize] < b_height_log2_lookup[bsize]) {
|
|
if (block[max_depth] == 0)
|
|
return 1;
|
|
} else if (b_width_log2_lookup[bsize] > b_height_log2_lookup[bsize]) {
|
|
if (block[max_depth] > 0)
|
|
return 0;
|
|
} else {
|
|
#if CONFIG_EXT_PARTITION
|
|
if (block[max_depth] == 0)
|
|
return 1;
|
|
if (block[max_depth] == 2)
|
|
return partition != PARTITION_VERT_A;
|
|
#else
|
|
if (block[max_depth] == 0 || block[max_depth] == 2)
|
|
return 1;
|
|
#endif
|
|
else if (block[max_depth] == 3)
|
|
return 0;
|
|
}
|
|
|
|
for (depth = max_depth - 1; depth > 0; depth--) {
|
|
if (block[depth] == 0 || block[depth] == 2)
|
|
return 1;
|
|
else if (block[depth] == 3)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int is_second_rec(int mi_row, int mi_col, BLOCK_SIZE bsize) {
|
|
int bw = 4 << b_width_log2_lookup[bsize];
|
|
int bh = 4 << b_height_log2_lookup[bsize];
|
|
|
|
if (bw < bh)
|
|
return (mi_col << 3) % (bw << 1) == 0 ? 0 : 1;
|
|
else if (bh < bw)
|
|
return (mi_row << 3) % (bh << 1) == 0 ? 0 : 2;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int vp9_construct_ref_inter_list(VP9_COMMON *cm, MACROBLOCKD *xd,
|
|
const TileInfo *const tile,
|
|
BLOCK_SIZE bsize,
|
|
#if CONFIG_EXT_PARTITION
|
|
PARTITION_TYPE partition,
|
|
#endif
|
|
int mi_row, int mi_col,
|
|
MB_MODE_INFO *ref_list[2 *
|
|
(MI_BLOCK_SIZE + 1)]) {
|
|
int bw = 4 << b_width_log2_lookup[bsize];
|
|
int bh = 4 << b_height_log2_lookup[bsize];
|
|
int row_offset, col_offset;
|
|
int mi_offset;
|
|
MB_MODE_INFO *ref_mbmi;
|
|
int ref_index, ref_num = 0;
|
|
int row_offset_cand[2 * (MI_BLOCK_SIZE + 1)];
|
|
int col_offset_cand[2 * (MI_BLOCK_SIZE + 1)];
|
|
int offset_num = 0, i, switchflag;
|
|
int is_sec_rec = is_second_rec(mi_row, mi_col, bsize);
|
|
|
|
if (is_sec_rec != 2) {
|
|
row_offset_cand[offset_num] = -1; col_offset_cand[offset_num] = 0;
|
|
offset_num++;
|
|
}
|
|
if (is_sec_rec != 1) {
|
|
row_offset_cand[offset_num] = bh / (2 * MI_SIZE);
|
|
col_offset_cand[offset_num] = -1;
|
|
offset_num++;
|
|
}
|
|
|
|
row_offset = bh / MI_SIZE - 1;
|
|
col_offset = 1;
|
|
if (is_sec_rec < 2)
|
|
switchflag = 1;
|
|
else
|
|
switchflag = 0;
|
|
while ((is_sec_rec == 0 && ((row_offset >=0) ||
|
|
col_offset < (bw / MI_SIZE + 1))) ||
|
|
(is_sec_rec == 1 && col_offset < (bw / MI_SIZE + 1)) ||
|
|
(is_sec_rec == 2 && row_offset >=0)) {
|
|
switch (switchflag) {
|
|
case 0:
|
|
if (row_offset >= 0) {
|
|
if (row_offset != bh / (2 * MI_SIZE)) {
|
|
row_offset_cand[offset_num] = row_offset;
|
|
col_offset_cand[offset_num] = -1;
|
|
offset_num++;
|
|
}
|
|
row_offset--;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (col_offset < (bw / MI_SIZE + 1)) {
|
|
row_offset_cand[offset_num] = -1;
|
|
col_offset_cand[offset_num] = col_offset;
|
|
offset_num++;
|
|
col_offset++;
|
|
}
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
if (is_sec_rec == 0)
|
|
switchflag = 1 - switchflag;
|
|
}
|
|
row_offset_cand[offset_num] = -1;
|
|
col_offset_cand[offset_num] = -1;
|
|
offset_num++;
|
|
|
|
for (i = 0; i < offset_num; i++) {
|
|
row_offset = row_offset_cand[i];
|
|
col_offset = col_offset_cand[i];
|
|
if ((col_offset < (bw / MI_SIZE) ||
|
|
(col_offset == (bw / MI_SIZE) && is_right_available(bsize,
|
|
#if CONFIG_EXT_PARTITION
|
|
partition,
|
|
#endif
|
|
mi_row, mi_col)))
|
|
&& check_inside(tile, mi_row + row_offset, mi_col + col_offset)) {
|
|
mi_offset = row_offset * cm->mi_stride + col_offset;
|
|
ref_mbmi = &xd->mi[mi_offset].src_mi->mbmi;
|
|
if (is_inter_block(ref_mbmi)) {
|
|
for (ref_index = 0; ref_index < ref_num; ref_index++) {
|
|
if (compare_interinfo(ref_mbmi, ref_list[ref_index]))
|
|
break;
|
|
}
|
|
if (ref_index == ref_num) {
|
|
ref_list[ref_num] = ref_mbmi;
|
|
ref_num++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ref_num;
|
|
}
|
|
#endif // CONFIG_COPY_MODE
|
|
|
|
#if CONFIG_INTRABC
|
|
void vp9_find_ref_dv(int_mv *ref_dv, int mi_row, int mi_col) {
|
|
(void) mi_col;
|
|
if (mi_row < 8) {
|
|
ref_dv->as_mv.row = 0;
|
|
ref_dv->as_mv.col = -8 * 8;
|
|
} else {
|
|
ref_dv->as_mv.row = -8 * 8;
|
|
ref_dv->as_mv.col = 0;
|
|
}
|
|
}
|
|
#endif // CONFIG_INTRABC
|