vpx/vp9/common/vp9_pred_common.c
Guillaume Martres acf0d56f0b Get rid of "this_mi", use "mi_8x8[0]" everywhere instead
The only case where they were intentionally pointing to different
structures was in mbgraph, and this didn't have the expected behavior
because both of these pointers are used interchangeably through the code

Change-Id: I979251782f90885fe962305bcc845bc05907f80c
2013-10-16 16:24:03 -07:00

412 lines
18 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 <limits.h>
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_pred_common.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/common/vp9_treecoder.h"
// Returns a context number for the given MB prediction signal
unsigned char vp9_get_pred_context_switchable_interp(const MACROBLOCKD *xd) {
const MODE_INFO * const above_mi = xd->mi_8x8[-xd->mode_info_stride];
const MODE_INFO * const left_mi = xd->mi_8x8[-1];
const int left_in_image = xd->left_available && left_mi;
const int above_in_image = xd->up_available && above_mi;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
// left
const int left_mv_pred = left_in_image ? is_inter_mode(left_mi->mbmi.mode)
: 0;
const int left_interp = left_in_image && left_mv_pred
? left_mi->mbmi.interp_filter
: SWITCHABLE_FILTERS;
// above
const int above_mv_pred = above_in_image ? is_inter_mode(above_mi->mbmi.mode)
: 0;
const int above_interp = above_in_image && above_mv_pred
? above_mi->mbmi.interp_filter
: SWITCHABLE_FILTERS;
if (left_interp == above_interp)
return left_interp;
else if (left_interp == SWITCHABLE_FILTERS &&
above_interp != SWITCHABLE_FILTERS)
return above_interp;
else if (left_interp != SWITCHABLE_FILTERS &&
above_interp == SWITCHABLE_FILTERS)
return left_interp;
else
return SWITCHABLE_FILTERS;
}
// Returns a context number for the given MB prediction signal
unsigned char vp9_get_pred_context_intra_inter(const MACROBLOCKD *xd) {
const MODE_INFO * const above_mi = xd->mi_8x8[-xd->mode_info_stride];
const MODE_INFO * const left_mi = xd->mi_8x8[-1];
const MB_MODE_INFO *const above_mbmi = above_mi ? &above_mi->mbmi : 0;
const MB_MODE_INFO *const left_mbmi = left_mi ? &left_mi->mbmi : 0;
const int left_in_image = xd->left_available && left_mi;
const int above_in_image = xd->up_available && above_mi;
const int left_intra = left_in_image ? !is_inter_block(left_mbmi) : 1;
const int above_intra = above_in_image ? !is_inter_block(above_mbmi) : 1;
// The mode info data structure has a one element border above and to the
// left of the entries corresponding to real macroblocks.
// The prediction flags in these dummy entries are initialized to 0.
// 0 - inter/inter, inter/--, --/inter, --/--
// 1 - intra/inter, inter/intra
// 2 - intra/--, --/intra
// 3 - intra/intra
if (above_in_image && left_in_image) // both edges available
return left_intra && above_intra ? 3
: left_intra || above_intra;
else if (above_in_image || left_in_image) // one edge available
return 2 * (above_in_image ? above_intra : left_intra);
else
return 0;
}
// Returns a context number for the given MB prediction signal
unsigned char vp9_get_pred_context_comp_inter_inter(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MODE_INFO * const above_mi = xd->mi_8x8[-xd->mode_info_stride];
const MODE_INFO * const left_mi = xd->mi_8x8[-1];
const MB_MODE_INFO *const above_mbmi = above_mi ? &above_mi->mbmi : 0;
const MB_MODE_INFO *const left_mbmi = left_mi ? &left_mi->mbmi : 0;
const int left_in_image = xd->left_available && left_mi;
const int above_in_image = xd->up_available && above_mi;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (above_in_image && left_in_image) { // both edges available
if (!has_second_ref(above_mbmi) && !has_second_ref(left_mbmi))
// neither edge uses comp pred (0/1)
pred_context = (above_mbmi->ref_frame[0] == cm->comp_fixed_ref) ^
(left_mbmi->ref_frame[0] == cm->comp_fixed_ref);
else if (!has_second_ref(above_mbmi))
// one of two edges uses comp pred (2/3)
pred_context = 2 + (above_mbmi->ref_frame[0] == cm->comp_fixed_ref ||
!is_inter_block(above_mbmi));
else if (!has_second_ref(left_mbmi))
// one of two edges uses comp pred (2/3)
pred_context = 2 + (left_mbmi->ref_frame[0] == cm->comp_fixed_ref ||
!is_inter_block(left_mbmi));
else // both edges use comp pred (4)
pred_context = 4;
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!has_second_ref(edge_mbmi))
// edge does not use comp pred (0/1)
pred_context = edge_mbmi->ref_frame[0] == cm->comp_fixed_ref;
else
// edge uses comp pred (3)
pred_context = 3;
} else { // no edges available (1)
pred_context = 1;
}
assert(pred_context >= 0 && pred_context < COMP_INTER_CONTEXTS);
return pred_context;
}
// Returns a context number for the given MB prediction signal
unsigned char vp9_get_pred_context_comp_ref_p(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MODE_INFO * const above_mi = xd->mi_8x8[-cm->mode_info_stride];
const MODE_INFO * const left_mi = xd->mi_8x8[-1];
const MB_MODE_INFO *const above_mbmi = above_mi ? &above_mi->mbmi : 0;
const MB_MODE_INFO *const left_mbmi = left_mi ? &left_mi->mbmi : 0;
const int left_in_image = xd->left_available && left_mi;
const int above_in_image = xd->up_available && above_mi;
const int left_intra = left_in_image ? !is_inter_block(left_mbmi) : 1;
const int above_intra = above_in_image ? !is_inter_block(above_mbmi) : 1;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
const int fix_ref_idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
const int var_ref_idx = !fix_ref_idx;
if (above_in_image && left_in_image) { // both edges available
if (above_intra && left_intra) { // intra/intra (2)
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) // single pred (1/3)
pred_context = 1 + 2 * (edge_mbmi->ref_frame[0] != cm->comp_var_ref[1]);
else // comp pred (1/3)
pred_context = 1 + 2 * (edge_mbmi->ref_frame[var_ref_idx]
!= cm->comp_var_ref[1]);
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && cm->comp_var_ref[1] == vrfa) {
pred_context = 0;
} else if (l_sg && a_sg) { // single/single
if ((vrfa == cm->comp_fixed_ref && vrfl == cm->comp_var_ref[0]) ||
(vrfl == cm->comp_fixed_ref && vrfa == cm->comp_var_ref[0]))
pred_context = 4;
else if (vrfa == vrfl)
pred_context = 3;
else
pred_context = 1;
} else if (l_sg || a_sg) { // single/comp
MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (vrfc == cm->comp_var_ref[1] && rfs != cm->comp_var_ref[1])
pred_context = 1;
else if (rfs == cm->comp_var_ref[1] && vrfc != cm->comp_var_ref[1])
pred_context = 2;
else
pred_context = 4;
} else if (vrfa == vrfl) { // comp/comp
pred_context = 4;
} else {
pred_context = 2;
}
}
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi)) {
pred_context = 2;
} else {
if (has_second_ref(edge_mbmi))
pred_context = 4 * (edge_mbmi->ref_frame[var_ref_idx]
!= cm->comp_var_ref[1]);
else
pred_context = 3 * (edge_mbmi->ref_frame[0] != cm->comp_var_ref[1]);
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
unsigned char vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd) {
int pred_context;
const MODE_INFO * const above_mi = xd->mi_8x8[-xd->mode_info_stride];
const MODE_INFO * const left_mi = xd->mi_8x8[-1];
const MB_MODE_INFO *const above_mbmi = above_mi ? &above_mi->mbmi : 0;
const MB_MODE_INFO *const left_mbmi = left_mi ? &left_mi->mbmi : 0;
const int left_in_image = xd->left_available && left_mi;
const int above_in_image = xd->up_available && above_mi;
const int left_intra = left_in_image ? !is_inter_block(left_mbmi) : 1;
const int above_intra = above_in_image ? !is_inter_block(above_mbmi) : 1;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (above_in_image && left_in_image) { // both edges available
if (above_intra && left_intra) { // intra/intra
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter or inter/intra
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi))
pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST_FRAME);
else
pred_context = 1 + (edge_mbmi->ref_frame[0] == LAST_FRAME ||
edge_mbmi->ref_frame[1] == LAST_FRAME);
} else { // inter/inter
if (!has_second_ref(above_mbmi) && !has_second_ref(left_mbmi)) {
pred_context = 2 * (above_mbmi->ref_frame[0] == LAST_FRAME) +
2 * (left_mbmi->ref_frame[0] == LAST_FRAME);
} else if (has_second_ref(above_mbmi) && has_second_ref(left_mbmi)) {
pred_context = 1 + (above_mbmi->ref_frame[0] == LAST_FRAME ||
above_mbmi->ref_frame[1] == LAST_FRAME ||
left_mbmi->ref_frame[0] == LAST_FRAME ||
left_mbmi->ref_frame[1] == LAST_FRAME);
} else {
const MV_REFERENCE_FRAME rfs = !has_second_ref(above_mbmi) ?
above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME crf1 = has_second_ref(above_mbmi) ?
above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME crf2 = has_second_ref(above_mbmi) ?
above_mbmi->ref_frame[1] : left_mbmi->ref_frame[1];
if (rfs == LAST_FRAME)
pred_context = 3 + (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
else
pred_context = crf1 == LAST_FRAME || crf2 == LAST_FRAME;
}
}
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi)) { // intra
pred_context = 2;
} else { // inter
if (!has_second_ref(edge_mbmi))
pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST_FRAME);
else
pred_context = 1 + (edge_mbmi->ref_frame[0] == LAST_FRAME ||
edge_mbmi->ref_frame[1] == LAST_FRAME);
}
} else { // no edges available
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
unsigned char vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd) {
int pred_context;
const MODE_INFO * const above_mi = xd->mi_8x8[-xd->mode_info_stride];
const MODE_INFO * const left_mi = xd->mi_8x8[-1];
const MB_MODE_INFO *const above_mbmi = above_mi ? &above_mi->mbmi : 0;
const MB_MODE_INFO *const left_mbmi = left_mi ? &left_mi->mbmi : 0;
const int left_in_image = xd->left_available && left_mi;
const int above_in_image = xd->up_available && above_mi;
const int left_intra = left_in_image ? !is_inter_block(left_mbmi) : 1;
const int above_intra = above_in_image ? !is_inter_block(above_mbmi) : 1;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (above_in_image && left_in_image) { // both edges available
if (above_intra && left_intra) { // intra/intra
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter or inter/intra
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) {
if (edge_mbmi->ref_frame[0] == LAST_FRAME)
pred_context = 3;
else
pred_context = 4 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME);
} else {
pred_context = 1 + 2 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME ||
edge_mbmi->ref_frame[1] == GOLDEN_FRAME);
}
} else { // inter/inter
if (!has_second_ref(above_mbmi) && !has_second_ref(left_mbmi)) {
if (above_mbmi->ref_frame[0] == LAST_FRAME &&
left_mbmi->ref_frame[0] == LAST_FRAME) {
pred_context = 3;
} else if (above_mbmi->ref_frame[0] == LAST_FRAME ||
left_mbmi->ref_frame[0] == LAST_FRAME) {
const MB_MODE_INFO *edge_mbmi =
above_mbmi->ref_frame[0] == LAST_FRAME ? left_mbmi : above_mbmi;
pred_context = 4 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME);
} else {
pred_context = 2 * (above_mbmi->ref_frame[0] == GOLDEN_FRAME) +
2 * (left_mbmi->ref_frame[0] == GOLDEN_FRAME);
}
} else if (has_second_ref(above_mbmi) && has_second_ref(left_mbmi)) {
if (above_mbmi->ref_frame[0] == left_mbmi->ref_frame[0] &&
above_mbmi->ref_frame[1] == left_mbmi->ref_frame[1])
pred_context = 3 * (above_mbmi->ref_frame[0] == GOLDEN_FRAME ||
above_mbmi->ref_frame[1] == GOLDEN_FRAME ||
left_mbmi->ref_frame[0] == GOLDEN_FRAME ||
left_mbmi->ref_frame[1] == GOLDEN_FRAME);
else
pred_context = 2;
} else {
const MV_REFERENCE_FRAME rfs = !has_second_ref(above_mbmi) ?
above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME crf1 = has_second_ref(above_mbmi) ?
above_mbmi->ref_frame[0] : left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME crf2 = has_second_ref(above_mbmi) ?
above_mbmi->ref_frame[1] : left_mbmi->ref_frame[1];
if (rfs == GOLDEN_FRAME)
pred_context = 3 + (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
else if (rfs == ALTREF_FRAME)
pred_context = crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME;
else
pred_context = 1 + 2 * (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
}
}
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi) ||
(edge_mbmi->ref_frame[0] == LAST_FRAME && !has_second_ref(edge_mbmi)))
pred_context = 2;
else if (!has_second_ref(edge_mbmi))
pred_context = 4 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME);
else
pred_context = 3 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME ||
edge_mbmi->ref_frame[1] == GOLDEN_FRAME);
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
// Returns a context number for the given MB prediction signal
// The mode info data structure has a one element border above and to the
// left of the entries corresponding to real blocks.
// The prediction flags in these dummy entries are initialized to 0.
unsigned char vp9_get_pred_context_tx_size(const MACROBLOCKD *xd) {
const MODE_INFO * const above_mi = xd->mi_8x8[-xd->mode_info_stride];
const MODE_INFO * const left_mi = xd->mi_8x8[-1];
const MB_MODE_INFO *const above_mbmi = above_mi ? &above_mi->mbmi : 0;
const MB_MODE_INFO *const left_mbmi = left_mi ? &left_mi->mbmi : 0;
const int left_in_image = xd->left_available && left_mi;
const int above_in_image = xd->up_available && above_mi;
const int max_tx_size = max_txsize_lookup[xd->mi_8x8[0]->mbmi.sb_type];
int above_context = max_tx_size;
int left_context = max_tx_size;
if (above_in_image)
above_context = above_mbmi->skip_coeff ? max_tx_size
: above_mbmi->tx_size;
if (left_in_image)
left_context = left_mbmi->skip_coeff ? max_tx_size
: left_mbmi->tx_size;
if (!left_in_image)
left_context = above_context;
if (!above_in_image)
above_context = left_context;
return above_context + left_context > max_tx_size;
}
void vp9_set_pred_flag_seg_id(MACROBLOCKD *xd, uint8_t pred_flag) {
xd->mi_8x8[0]->mbmi.seg_id_predicted = pred_flag;
}
int vp9_get_segment_id(VP9_COMMON *cm, const uint8_t *segment_ids,
BLOCK_SIZE bsize, int mi_row, int mi_col) {
const int mi_offset = mi_row * cm->mi_cols + mi_col;
const int bw = 1 << mi_width_log2(bsize);
const int bh = 1 << mi_height_log2(bsize);
const int xmis = MIN(cm->mi_cols - mi_col, bw);
const int ymis = MIN(cm->mi_rows - mi_row, bh);
int x, y, segment_id = INT_MAX;
for (y = 0; y < ymis; y++)
for (x = 0; x < xmis; x++)
segment_id = MIN(segment_id,
segment_ids[mi_offset + y * cm->mi_cols + x]);
assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);
return segment_id;
}