Commit 6ef805eb authored by Ronald S. Bultje's avatar Ronald S. Bultje

Change ref frame coding.

Code intra/inter, then comp/single, then the ref frame selection.
Use contextualization for all steps. Don't code two past frames
in comp pred mode.

Change-Id: I4639a78cd5cccb283023265dbcc07898c3e7cf95
parent 9062b92b
......@@ -24,11 +24,8 @@
#define BLOCK_SIZE_GROUPS 4
#define MAX_MB_SEGMENTS 8
#define MB_SEG_TREE_PROBS (MAX_MB_SEGMENTS-1)
#define PREDICTION_PROBS 3
#define DEFAULT_PRED_PROB_0 120
#define DEFAULT_PRED_PROB_1 80
#define DEFAULT_PRED_PROB_2 40
#define PREDICTION_PROBS 3
#define MBSKIP_CONTEXTS 3
......@@ -40,6 +37,10 @@
#define SEGMENT_ABSDATA 1
#define MAX_MV_REF_CANDIDATES 2
#define INTRA_INTER_CONTEXTS 4
#define COMP_INTER_CONTEXTS 5
#define REF_CONTEXTS 5
typedef enum {
PLANE_TYPE_Y_WITH_DC,
PLANE_TYPE_UV,
......@@ -200,7 +201,7 @@ static INLINE int mi_height_log2(BLOCK_SIZE_TYPE sb_type) {
typedef struct {
MB_PREDICTION_MODE mode, uv_mode;
MV_REFERENCE_FRAME ref_frame, second_ref_frame;
MV_REFERENCE_FRAME ref_frame[2];
TX_SIZE txfm_size;
int_mv mv[2]; // for each reference frame used
int_mv ref_mvs[MAX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
......@@ -215,7 +216,6 @@ typedef struct {
// Flags used for prediction status of various bistream signals
unsigned char seg_id_predicted;
unsigned char ref_predicted;
// Indicates if the mb is part of the image (1) vs border (0)
// This can be useful in determining whether the MB provides
......@@ -526,7 +526,7 @@ static TX_TYPE get_tx_type_4x4(const MACROBLOCKD *xd, int ib) {
TX_TYPE tx_type;
MODE_INFO *mi = xd->mode_info_context;
MB_MODE_INFO *const mbmi = &mi->mbmi;
if (xd->lossless || mbmi->ref_frame != INTRA_FRAME)
if (xd->lossless || mbmi->ref_frame[0] != INTRA_FRAME)
return DCT_DCT;
if (mbmi->sb_type < BLOCK_SIZE_SB8X8) {
tx_type = txfm_map(mi->bmi[ib].as_mode.first);
......
......@@ -129,6 +129,26 @@ struct vp9_token vp9_sb_mv_ref_encoding_array[VP9_INTER_MODES];
struct vp9_token vp9_partition_encodings[PARTITION_TYPES];
static const vp9_prob default_intra_inter_p[INTRA_INTER_CONTEXTS] = {
6, 87, 165, 213
};
static const vp9_prob default_comp_inter_p[COMP_INTER_CONTEXTS] = {
25, 66, 106, 142, 183
};
static const vp9_prob default_comp_ref_p[REF_CONTEXTS] = {
36, 93, 136, 205, 236
};
static const vp9_prob default_single_ref_p[REF_CONTEXTS][2] = {
{ 30, 17 },
{ 80, 66 },
{ 142, 129 },
{ 192, 178 },
{ 235, 248 },
};
void vp9_init_mbmode_probs(VP9_COMMON *x) {
vpx_memcpy(x->fc.uv_mode_prob, default_if_uv_probs,
sizeof(default_if_uv_probs));
......@@ -143,9 +163,14 @@ void vp9_init_mbmode_probs(VP9_COMMON *x) {
vpx_memcpy(x->fc.partition_prob, vp9_partition_probs,
sizeof(vp9_partition_probs));
x->ref_pred_probs[0] = DEFAULT_PRED_PROB_0;
x->ref_pred_probs[1] = DEFAULT_PRED_PROB_1;
x->ref_pred_probs[2] = DEFAULT_PRED_PROB_2;
vpx_memcpy(x->fc.intra_inter_prob, default_intra_inter_p,
sizeof(default_intra_inter_p));
vpx_memcpy(x->fc.comp_inter_prob, default_comp_inter_p,
sizeof(default_comp_inter_p));
vpx_memcpy(x->fc.comp_ref_prob, default_comp_ref_p,
sizeof(default_comp_ref_p));
vpx_memcpy(x->fc.single_ref_prob, default_single_ref_p,
sizeof(default_single_ref_p));
}
#if VP9_SWITCHABLE_FILTERS == 3
......@@ -246,6 +271,14 @@ void vp9_adapt_mode_context(VP9_COMMON *pc) {
#define MODE_COUNT_SAT 20
#define MODE_MAX_UPDATE_FACTOR 144
static int update_mode_ct(int pre_prob, int prob,
unsigned int branch_ct[2]) {
int factor, count = branch_ct[0] + branch_ct[1];
count = count > MODE_COUNT_SAT ? MODE_COUNT_SAT : count;
factor = (MODE_MAX_UPDATE_FACTOR * count / MODE_COUNT_SAT);
return weighted_prob(pre_prob, prob, factor);
}
static void update_mode_probs(int n_modes,
const vp9_tree_index *tree, unsigned int *cnt,
vp9_prob *pre_probs, vp9_prob *dst_probs,
......@@ -253,21 +286,22 @@ static void update_mode_probs(int n_modes,
#define MAX_PROBS 32
vp9_prob probs[MAX_PROBS];
unsigned int branch_ct[MAX_PROBS][2];
int t, count, factor;
int t;
assert(n_modes - 1 < MAX_PROBS);
vp9_tree_probs_from_distribution(tree, probs, branch_ct, cnt, tok0_offset);
for (t = 0; t < n_modes - 1; ++t) {
count = branch_ct[t][0] + branch_ct[t][1];
count = count > MODE_COUNT_SAT ? MODE_COUNT_SAT : count;
factor = (MODE_MAX_UPDATE_FACTOR * count / MODE_COUNT_SAT);
dst_probs[t] = weighted_prob(pre_probs[t], probs[t], factor);
}
for (t = 0; t < n_modes - 1; ++t)
dst_probs[t] = update_mode_ct(pre_probs[t], probs[t], branch_ct[t]);
}
static int update_mode_ct2(int pre_prob, unsigned int branch_ct[2]) {
return update_mode_ct(pre_prob, get_binary_prob(branch_ct[0],
branch_ct[1]), branch_ct);
}
// #define MODE_COUNT_TESTING
void vp9_adapt_mode_probs(VP9_COMMON *cm) {
int i;
int i, j;
FRAME_CONTEXT *fc = &cm->fc;
#ifdef MODE_COUNT_TESTING
int t;
......@@ -303,6 +337,20 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) {
printf("};\n");
#endif
for (i = 0; i < INTRA_INTER_CONTEXTS; i++)
fc->intra_inter_prob[i] = update_mode_ct2(fc->pre_intra_inter_prob[i],
fc->intra_inter_count[i]);
for (i = 0; i < COMP_INTER_CONTEXTS; i++)
fc->comp_inter_prob[i] = update_mode_ct2(fc->pre_comp_inter_prob[i],
fc->comp_inter_count[i]);
for (i = 0; i < REF_CONTEXTS; i++)
fc->comp_ref_prob[i] = update_mode_ct2(fc->pre_comp_ref_prob[i],
fc->comp_ref_count[i]);
for (i = 0; i < REF_CONTEXTS; i++)
for (j = 0; j < 2; j++)
fc->single_ref_prob[i][j] = update_mode_ct2(fc->pre_single_ref_prob[i][j],
fc->single_ref_count[i][j]);
for (i = 0; i < BLOCK_SIZE_GROUPS; i++)
update_mode_probs(VP9_INTRA_MODES, vp9_intra_mode_tree,
fc->y_mode_counts[i], fc->pre_y_mode_prob[i],
......
......@@ -59,7 +59,7 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
vp9_find_mv_refs_idx(cm, xd, xd->mode_info_context,
xd->prev_mode_info_context,
ref_idx ? mbmi->second_ref_frame : mbmi->ref_frame,
mbmi->ref_frame[ref_idx],
mv_list, cm->ref_frame_sign_bias, block_idx);
dst_list[1].as_int = 0;
......
......@@ -87,7 +87,7 @@ static MB_PREDICTION_MODE left_block_mode(const MODE_INFO *cur_mb, int b) {
/* On L edge, get from MB to left of us */
--cur_mb;
if (cur_mb->mbmi.ref_frame != INTRA_FRAME) {
if (cur_mb->mbmi.ref_frame[0] != INTRA_FRAME) {
return DC_PRED;
} else if (cur_mb->mbmi.sb_type < BLOCK_SIZE_SB8X8) {
return ((cur_mb->bmi + 1 + b)->as_mode.first);
......@@ -105,7 +105,7 @@ static MB_PREDICTION_MODE above_block_mode(const MODE_INFO *cur_mb,
/* On top edge, get from MB above us */
cur_mb -= mi_stride;
if (cur_mb->mbmi.ref_frame != INTRA_FRAME) {
if (cur_mb->mbmi.ref_frame[0] != INTRA_FRAME) {
return DC_PRED;
} else if (cur_mb->mbmi.sb_type < BLOCK_SIZE_SB8X8) {
return ((cur_mb->bmi + 2 + b)->as_mode.first);
......
......@@ -140,11 +140,11 @@ void segment_via_mode_info(VP9_COMMON *oci, int how) {
break;
case SEGMENT_MV:
n = mi[mb_index].mbmi.mv[0].as_int;
if (mi[mb_index].mbmi.ref_frame == INTRA_FRAME)
if (mi[mb_index].mbmi.ref_frame[0] == INTRA_FRAME)
n = -9999999;
break;
case SEGMENT_REFFRAME:
n = mi[mb_index].mbmi.ref_frame;
n = mi[mb_index].mbmi.ref_frame[0];
break;
case SEGMENT_SKIPPED:
n = mi[mb_index].mbmi.mb_skip_coeff;
......
......@@ -177,8 +177,8 @@ static int sb_mb_lf_skip(const MODE_INFO *const mip0,
const MB_MODE_INFO *mbmi0 = &mip0->mbmi;
const MB_MODE_INFO *mbmi1 = &mip1->mbmi;
return mb_lf_skip(mbmi0) && mb_lf_skip(mbmi1) &&
mbmi0->ref_frame != INTRA_FRAME &&
mbmi1->ref_frame != INTRA_FRAME;
mbmi0->ref_frame[0] != INTRA_FRAME &&
mbmi1->ref_frame[0] != INTRA_FRAME;
}
static void lpf_mb(VP9_COMMON *cm, const MODE_INFO *mi,
......@@ -191,7 +191,7 @@ static void lpf_mb(VP9_COMMON *cm, const MODE_INFO *mi,
int mode = mi->mbmi.mode;
int mode_index = lfi_n->mode_lf_lut[mode];
int seg = mi->mbmi.segment_id;
int ref_frame = mi->mbmi.ref_frame;
MV_REFERENCE_FRAME ref_frame = mi->mbmi.ref_frame[0];
int filter_level = lfi_n->lvl[seg][ref_frame][mode_index];
if (filter_level) {
......
......@@ -47,12 +47,12 @@ static void clamp_mv_ref(const MACROBLOCKD *xd, int_mv *mv) {
static int get_matching_candidate(const MODE_INFO *candidate_mi,
MV_REFERENCE_FRAME ref_frame,
int_mv *c_mv, int block_idx) {
if (ref_frame == candidate_mi->mbmi.ref_frame) {
if (ref_frame == candidate_mi->mbmi.ref_frame[0]) {
if (block_idx >= 0 && candidate_mi->mbmi.sb_type < BLOCK_SIZE_SB8X8)
c_mv->as_int = candidate_mi->bmi[block_idx].as_mv[0].as_int;
else
c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
} else if (ref_frame == candidate_mi->mbmi.second_ref_frame) {
} else if (ref_frame == candidate_mi->mbmi.ref_frame[1]) {
if (block_idx >= 0 && candidate_mi->mbmi.sb_type < BLOCK_SIZE_SB8X8)
c_mv->as_int = candidate_mi->bmi[block_idx].as_mv[1].as_int;
else
......@@ -79,18 +79,18 @@ static void get_non_matching_candidates(const MODE_INFO *candidate_mi,
*c2_ref_frame = INTRA_FRAME;
// If first candidate not valid neither will be.
if (candidate_mi->mbmi.ref_frame > INTRA_FRAME) {
if (candidate_mi->mbmi.ref_frame[0] > INTRA_FRAME) {
// First candidate
if (candidate_mi->mbmi.ref_frame != ref_frame) {
*c_ref_frame = candidate_mi->mbmi.ref_frame;
if (candidate_mi->mbmi.ref_frame[0] != ref_frame) {
*c_ref_frame = candidate_mi->mbmi.ref_frame[0];
c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
}
// Second candidate
if ((candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) &&
(candidate_mi->mbmi.second_ref_frame != ref_frame) &&
if ((candidate_mi->mbmi.ref_frame[1] > INTRA_FRAME) &&
(candidate_mi->mbmi.ref_frame[1] != ref_frame) &&
(candidate_mi->mbmi.mv[1].as_int != candidate_mi->mbmi.mv[0].as_int)) {
*c2_ref_frame = candidate_mi->mbmi.second_ref_frame;
*c2_ref_frame = candidate_mi->mbmi.ref_frame[1];
c2_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
}
}
......@@ -226,7 +226,7 @@ void vp9_find_mv_refs_idx(VP9_COMMON *cm, MACROBLOCKD *xd, MODE_INFO *here,
&refmv_count, c_refmv, 16);
}
split_count += (candidate_mi->mbmi.sb_type < BLOCK_SIZE_SB8X8 &&
candidate_mi->mbmi.ref_frame != INTRA_FRAME);
candidate_mi->mbmi.ref_frame[0] != INTRA_FRAME);
// Count number of neihgbours coded intra and zeromv
intra_count += (candidate_mi->mbmi.mode < NEARESTMV);
......
......@@ -40,8 +40,6 @@
#define NUM_FRAME_CONTEXTS_LG2 2
#define NUM_FRAME_CONTEXTS (1 << NUM_FRAME_CONTEXTS_LG2)
#define COMP_PRED_CONTEXTS 2
#define MAX_LAG_BUFFERS 25
typedef struct frame_contexts {
......@@ -78,6 +76,19 @@ typedef struct frame_contexts {
vp9_prob inter_mode_probs[INTER_MODE_CONTEXTS][VP9_INTER_MODES - 1];
vp9_prob pre_inter_mode_probs[INTER_MODE_CONTEXTS][VP9_INTER_MODES - 1];
unsigned int inter_mode_counts[INTER_MODE_CONTEXTS][VP9_INTER_MODES - 1][2];
vp9_prob intra_inter_prob[INTRA_INTER_CONTEXTS];
vp9_prob comp_inter_prob[COMP_INTER_CONTEXTS];
vp9_prob single_ref_prob[REF_CONTEXTS][2];
vp9_prob comp_ref_prob[REF_CONTEXTS];
vp9_prob pre_intra_inter_prob[INTRA_INTER_CONTEXTS];
vp9_prob pre_comp_inter_prob[COMP_INTER_CONTEXTS];
vp9_prob pre_single_ref_prob[REF_CONTEXTS][2];
vp9_prob pre_comp_ref_prob[REF_CONTEXTS];
unsigned int intra_inter_count[INTRA_INTER_CONTEXTS][2];
unsigned int comp_inter_count[COMP_INTER_CONTEXTS][2];
unsigned int single_ref_count[REF_CONTEXTS][2][2];
unsigned int comp_ref_count[REF_CONTEXTS][2];
} FRAME_CONTEXT;
typedef enum {
......@@ -162,7 +173,6 @@ typedef struct VP9Common {
/* profile settings */
int experimental;
TXFM_MODE txfm_mode;
COMPPREDMODE_TYPE comp_pred_mode;
int no_lpf;
int use_bilinear_mc_filter;
......@@ -219,20 +229,15 @@ typedef struct VP9Common {
[VP9_INTRA_MODES - 1];
vp9_prob kf_uv_mode_prob[VP9_INTRA_MODES] [VP9_INTRA_MODES - 1];
vp9_prob prob_intra_coded;
vp9_prob prob_last_coded;
vp9_prob prob_gf_coded;
// Context probabilities when using predictive coding of segment id
vp9_prob segment_pred_probs[PREDICTION_PROBS];
unsigned char temporal_update;
// Context probabilities for reference frame prediction
unsigned char ref_scores[MAX_REF_FRAMES];
vp9_prob ref_pred_probs[PREDICTION_PROBS];
vp9_prob mod_refprobs[MAX_REF_FRAMES][PREDICTION_PROBS];
vp9_prob prob_comppred[COMP_PRED_CONTEXTS];
int allow_comp_inter_inter;
MV_REFERENCE_FRAME comp_fixed_ref;
MV_REFERENCE_FRAME comp_var_ref[2];
COMPPREDMODE_TYPE comp_pred_mode;
// FIXME contextualize
vp9_prob prob_tx[TX_SIZE_MAX_SB - 1];
......
......@@ -26,6 +26,8 @@ unsigned char vp9_get_pred_context(const VP9_COMMON *const cm,
const MODE_INFO *const mi = xd->mode_info_context;
const MODE_INFO *const above_mi = mi - cm->mode_info_stride;
const MODE_INFO *const left_mi = mi - 1;
const int left_in_image = xd->left_available && left_mi->mbmi.mb_in_image;
const int above_in_image = xd->up_available && above_mi->mbmi.mb_in_image;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
......@@ -37,19 +39,6 @@ unsigned char vp9_get_pred_context(const VP9_COMMON *const cm,
pred_context += left_mi->mbmi.seg_id_predicted;
break;
case PRED_REF:
pred_context = above_mi->mbmi.ref_predicted;
if (xd->left_available)
pred_context += left_mi->mbmi.ref_predicted;
break;
case PRED_COMP:
if (mi->mbmi.ref_frame == LAST_FRAME)
pred_context = 0;
else
pred_context = 1;
break;
case PRED_MBSKIP:
pred_context = above_mi->mbmi.mb_skip_coeff;
if (xd->left_available)
......@@ -58,14 +47,12 @@ unsigned char vp9_get_pred_context(const VP9_COMMON *const cm,
case PRED_SWITCHABLE_INTERP: {
// left
const int left_in_image = xd->left_available && left_mi->mbmi.mb_in_image;
const int left_mv_pred = is_inter_mode(left_mi->mbmi.mode);
const int left_interp = left_in_image && left_mv_pred ?
vp9_switchable_interp_map[left_mi->mbmi.interp_filter] :
VP9_SWITCHABLE_FILTERS;
// above
const int above_in_image = xd->up_available && above_mi->mbmi.mb_in_image;
const int above_mv_pred = is_inter_mode(above_mi->mbmi.mode);
const int above_interp = above_in_image && above_mv_pred ?
vp9_switchable_interp_map[above_mi->mbmi.interp_filter] :
......@@ -88,7 +75,281 @@ unsigned char vp9_get_pred_context(const VP9_COMMON *const cm,
break;
}
case PRED_INTRA_INTER: {
if (above_in_image && left_in_image) { // both edges available
if (left_mi->mbmi.ref_frame[0] == INTRA_FRAME &&
above_mi->mbmi.ref_frame[0] == INTRA_FRAME) { // intra/intra (3)
pred_context = 3;
} else { // intra/inter (1) or inter/inter (0)
pred_context = left_mi->mbmi.ref_frame[0] == INTRA_FRAME ||
above_mi->mbmi.ref_frame[0] == INTRA_FRAME;
}
} else if (above_in_image || left_in_image) { // one edge available
const MODE_INFO *edge = above_in_image ? above_mi : left_mi;
// inter: 0, intra: 2
pred_context = 2 * (edge->mbmi.ref_frame[0] == INTRA_FRAME);
} else {
pred_context = 0;
}
assert(pred_context >= 0 && pred_context < INTRA_INTER_CONTEXTS);
break;
}
case PRED_COMP_INTER_INTER: {
if (above_in_image && left_in_image) { // both edges available
if (above_mi->mbmi.ref_frame[1] <= INTRA_FRAME &&
left_mi->mbmi.ref_frame[1] <= INTRA_FRAME) {
// neither edge uses comp pred (0/1)
pred_context = ((above_mi->mbmi.ref_frame[0] == cm->comp_fixed_ref) ^
(left_mi->mbmi.ref_frame[0] == cm->comp_fixed_ref));
} else if (above_mi->mbmi.ref_frame[1] <= INTRA_FRAME) {
// one of two edges uses comp pred (2/3)
pred_context = 2 +
(above_mi->mbmi.ref_frame[0] == cm->comp_fixed_ref ||
above_mi->mbmi.ref_frame[0] == INTRA_FRAME);
} else if (left_mi->mbmi.ref_frame[1] <= INTRA_FRAME) {
// one of two edges uses comp pred (2/3)
pred_context = 2 +
(left_mi->mbmi.ref_frame[0] == cm->comp_fixed_ref ||
left_mi->mbmi.ref_frame[0] == INTRA_FRAME);
} else { // both edges use comp pred (4)
pred_context = 4;
}
} else if (above_in_image || left_in_image) { // one edge available
const MODE_INFO *edge = above_in_image ? above_mi : left_mi;
if (edge->mbmi.ref_frame[1] <= INTRA_FRAME) {
// 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);
break;
}
case PRED_COMP_REF_P: {
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_mi->mbmi.ref_frame[0] == INTRA_FRAME &&
left_mi->mbmi.ref_frame[0] == INTRA_FRAME) { // intra/intra (2)
pred_context = 2;
} else if (above_mi->mbmi.ref_frame[0] == INTRA_FRAME ||
left_mi->mbmi.ref_frame[0] == INTRA_FRAME) { // intra/inter
const MODE_INFO *edge = above_mi->mbmi.ref_frame[0] == INTRA_FRAME ?
left_mi : above_mi;
if (edge->mbmi.ref_frame[1] <= INTRA_FRAME) { // 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
int l_sg = left_mi->mbmi.ref_frame[1] <= INTRA_FRAME;
int a_sg = above_mi->mbmi.ref_frame[1] <= INTRA_FRAME;
MV_REFERENCE_FRAME vrfa = a_sg ? above_mi->mbmi.ref_frame[0] :
above_mi->mbmi.ref_frame[var_ref_idx];
MV_REFERENCE_FRAME vrfl = l_sg ? left_mi->mbmi.ref_frame[0] :
left_mi->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 MODE_INFO *edge = above_in_image ? above_mi : left_mi;
if (edge->mbmi.ref_frame[0] == INTRA_FRAME) {
pred_context = 2;
} else if (edge->mbmi.ref_frame[1] > INTRA_FRAME) {
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);
break;
}
case PRED_SINGLE_REF_P1: {
if (above_in_image && left_in_image) { // both edges available
if (above_mi->mbmi.ref_frame[0] == INTRA_FRAME &&
left_mi->mbmi.ref_frame[0] == INTRA_FRAME) {
pred_context = 2;
} else if (above_mi->mbmi.ref_frame[0] == INTRA_FRAME ||
left_mi->mbmi.ref_frame[0] == INTRA_FRAME) {
const MODE_INFO *edge = above_mi->mbmi.ref_frame[0] == INTRA_FRAME ?
left_mi : above_mi;
if (edge->mbmi.ref_frame[1] <= INTRA_FRAME) {
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 if (above_mi->mbmi.ref_frame[1] <= INTRA_FRAME &&
left_mi->mbmi.ref_frame[1] <= INTRA_FRAME) {
pred_context = 2 * (above_mi->mbmi.ref_frame[0] == LAST_FRAME) +
2 * (left_mi->mbmi.ref_frame[0] == LAST_FRAME);
} else if (above_mi->mbmi.ref_frame[1] > INTRA_FRAME &&
left_mi->mbmi.ref_frame[1] > INTRA_FRAME) {
pred_context = 1 + (above_mi->mbmi.ref_frame[0] == LAST_FRAME ||
above_mi->mbmi.ref_frame[1] == LAST_FRAME ||
left_mi->mbmi.ref_frame[0] == LAST_FRAME ||
left_mi->mbmi.ref_frame[1] == LAST_FRAME);
} else {
MV_REFERENCE_FRAME rfs = above_mi->mbmi.ref_frame[1] <= INTRA_FRAME ?
above_mi->mbmi.ref_frame[0] : left_mi->mbmi.ref_frame[0];
MV_REFERENCE_FRAME crf1 = above_mi->mbmi.ref_frame[1] > INTRA_FRAME ?
above_mi->mbmi.ref_frame[0] : left_mi->mbmi.ref_frame[0];
MV_REFERENCE_FRAME crf2 = above_mi->mbmi.ref_frame[1] > INTRA_FRAME ?
above_mi->mbmi.ref_frame[1] : left_mi->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 MODE_INFO *edge = above_in_image ? above_mi : left_mi;
if (edge->mbmi.ref_frame[0] == INTRA_FRAME) {
pred_context = 2;
} else if (edge->mbmi.ref_frame[1] <= INTRA_FRAME) {
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 (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
break;
}
case PRED_SINGLE_REF_P2: {
if (above_in_image && left_in_image) { // both edges available
if (above_mi->mbmi.ref_frame[0] == INTRA_FRAME &&
left_mi->mbmi.ref_frame[0] == INTRA_FRAME) {
pred_context = 2;
} else if (above_mi->mbmi.ref_frame[0] == INTRA_FRAME ||
left_mi->mbmi.ref_frame[0] == INTRA_FRAME) {
const MODE_INFO *edge = above_mi->mbmi.ref_frame[0] == INTRA_FRAME ?
left_mi : above_mi;
if (edge->mbmi.ref_frame[1] <= INTRA_FRAME) {
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 if (above_mi->mbmi.ref_frame[1] <= INTRA_FRAME &&
left_mi->mbmi.ref_frame[1] <= INTRA_FRAME) {
if (above_mi->mbmi.ref_frame[0] == LAST_FRAME &&
left_mi->mbmi.ref_frame[0] == LAST_FRAME) {
pred_context = 3;
} else if (above_mi->mbmi.ref_frame[0] == LAST_FRAME ||
left_mi->mbmi.ref_frame[0] == LAST_FRAME) {
const MODE_INFO *edge = above_mi->mbmi.ref_frame[0] == LAST_FRAME ?
left_mi : above_mi;
pred_context = 4 * (edge->mbmi.ref_frame[0] == GOLDEN_FRAME);
} else {
pred_context = 2 * (above_mi->mbmi.ref_frame[0] == GOLDEN_FRAME) +
2 * (left_mi->mbmi.ref_frame[0] == GOLDEN_FRAME);
}
} else if (above_mi->mbmi.ref_frame[1] > INTRA_FRAME &&
left_mi->mbmi.ref_frame[1] > INTRA_FRAME) {
if (above_mi->mbmi.ref_frame[0] == left_mi->mbmi.ref_frame[0] &&
above_mi->mbmi.ref_frame[1] == left_mi->mbmi.ref_frame[1]) {
pred_context = 3 * (above_mi->mbmi.ref_frame[0] == GOLDEN_FRAME ||
above_mi->mbmi.ref_frame[1] == GOLDEN_FRAME ||