Commit 3ec1601e authored by Zoe Liu's avatar Zoe Liu

Added 3 more reference frames for inter prediction.

Under the experiment of EXT_REFS: LAST2_FRAME, LAST3_FRAME, and
LAST4_FRAME.

Coding efficiency: derflr +1.601%; hevchr +1.895%
Speed: Encoder slowed down by ~75%

Change-Id: Ifeee5f049c2c1f7cb29bc897622ef88897082ecf
parent 0c8110ef
......@@ -65,9 +65,18 @@ typedef struct {
#define NONE -1
#define INTRA_FRAME 0
#define LAST_FRAME 1
#if CONFIG_EXT_REFS
#define LAST2_FRAME 2
#define LAST3_FRAME 3
#define LAST4_FRAME 4
#define GOLDEN_FRAME 5
#define ALTREF_FRAME 6
#define MAX_REF_FRAMES 7
#else
#define GOLDEN_FRAME 2
#define ALTREF_FRAME 3
#define MAX_REF_FRAMES 4
#endif // CONFIG_EXT_REFS
typedef int8_t MV_REFERENCE_FRAME;
typedef struct {
......
......@@ -215,16 +215,33 @@ static const vpx_prob default_comp_inter_p[COMP_INTER_CONTEXTS] = {
239, 183, 119, 96, 41
};
static const vpx_prob default_comp_ref_p[REF_CONTEXTS] = {
50, 126, 123, 221, 226
static const vpx_prob default_comp_ref_p[REF_CONTEXTS][COMP_REFS - 1] = {
#if CONFIG_EXT_REFS
// TODO(zoeliu): To adjust the initial prob values.
{ 33, 16, 16, 16 },
{ 77, 74, 74, 74 },
{ 142, 142, 142, 142 },
{ 172, 170, 170, 170 },
{ 238, 247, 247, 247 }
#else
{ 50 }, { 126 }, { 123 }, { 221 }, { 226 }
#endif // CONFIG_EXT_REFS
};
static const vpx_prob default_single_ref_p[REF_CONTEXTS][2] = {
static const vpx_prob default_single_ref_p[REF_CONTEXTS][SINGLE_REFS - 1] = {
#if CONFIG_EXT_REFS
{ 33, 16, 16, 16, 16 },
{ 77, 74, 74, 74, 74 },
{ 142, 142, 142, 142, 142 },
{ 172, 170, 170, 170, 170 },
{ 238, 247, 247, 247, 247 }
#else
{ 33, 16 },
{ 77, 74 },
{ 142, 142 },
{ 172, 170 },
{ 238, 247 }
#endif // CONFIG_EXT_REFS
};
static const struct tx_probs default_tx_probs = {
......@@ -1109,10 +1126,11 @@ void vp10_adapt_inter_frame_probs(VP10_COMMON *cm) {
fc->comp_inter_prob[i] = mode_mv_merge_probs(pre_fc->comp_inter_prob[i],
counts->comp_inter[i]);
for (i = 0; i < REF_CONTEXTS; i++)
fc->comp_ref_prob[i] = mode_mv_merge_probs(pre_fc->comp_ref_prob[i],
counts->comp_ref[i]);
for (j = 0; j < (COMP_REFS - 1); j++)
fc->comp_ref_prob[i][j] = mode_mv_merge_probs(pre_fc->comp_ref_prob[i][j],
counts->comp_ref[i][j]);
for (i = 0; i < REF_CONTEXTS; i++)
for (j = 0; j < 2; j++)
for (j = 0; j < (SINGLE_REFS - 1); j++)
fc->single_ref_prob[i][j] = mode_mv_merge_probs(
pre_fc->single_ref_prob[i][j], counts->single_ref[i][j]);
......@@ -1233,6 +1251,11 @@ static void set_default_lf_deltas(struct loopfilter *lf) {
lf->ref_deltas[INTRA_FRAME] = 1;
lf->ref_deltas[LAST_FRAME] = 0;
#if CONFIG_EXT_REFS
lf->ref_deltas[LAST2_FRAME] = lf->ref_deltas[LAST_FRAME];
lf->ref_deltas[LAST3_FRAME] = lf->ref_deltas[LAST_FRAME];
lf->ref_deltas[LAST4_FRAME] = lf->ref_deltas[LAST_FRAME];
#endif // CONFIG_EXT_REFS
lf->ref_deltas[GOLDEN_FRAME] = -1;
lf->ref_deltas[ALTREF_FRAME] = -1;
......
......@@ -63,8 +63,8 @@ typedef struct frame_contexts {
vpx_prob inter_mode_probs[INTER_MODE_CONTEXTS][INTER_MODES - 1];
vpx_prob intra_inter_prob[INTRA_INTER_CONTEXTS];
vpx_prob comp_inter_prob[COMP_INTER_CONTEXTS];
vpx_prob single_ref_prob[REF_CONTEXTS][2];
vpx_prob comp_ref_prob[REF_CONTEXTS];
vpx_prob single_ref_prob[REF_CONTEXTS][SINGLE_REFS-1];
vpx_prob comp_ref_prob[REF_CONTEXTS][COMP_REFS-1];
struct tx_probs tx_probs;
#if CONFIG_VAR_TX
vpx_prob txfm_partition_prob[TXFM_PARTITION_CONTEXTS];
......@@ -96,8 +96,8 @@ typedef struct FRAME_COUNTS {
unsigned int inter_mode[INTER_MODE_CONTEXTS][INTER_MODES];
unsigned int intra_inter[INTRA_INTER_CONTEXTS][2];
unsigned int comp_inter[COMP_INTER_CONTEXTS][2];
unsigned int single_ref[REF_CONTEXTS][2][2];
unsigned int comp_ref[REF_CONTEXTS][2];
unsigned int single_ref[REF_CONTEXTS][SINGLE_REFS-1][2];
unsigned int comp_ref[REF_CONTEXTS][COMP_REFS-1][2];
struct tx_counts tx;
#if CONFIG_VAR_TX
unsigned int txfm_partition[TXFM_PARTITION_CONTEXTS][2];
......
......@@ -123,8 +123,16 @@ typedef enum {
typedef enum {
VP9_LAST_FLAG = 1 << 0,
#if CONFIG_EXT_REFS
VP9_LAST2_FLAG = 1 << 1,
VP9_LAST3_FLAG = 1 << 2,
VP9_LAST4_FLAG = 1 << 3,
VP9_GOLD_FLAG = 1 << 4,
VP9_ALT_FLAG = 1 << 5,
#else
VP9_GOLD_FLAG = 1 << 1,
VP9_ALT_FLAG = 1 << 2,
#endif // CONFIG_EXT_REFS
} VP9_REFFRAME;
typedef enum {
......@@ -210,6 +218,14 @@ typedef uint8_t PREDICTION_MODE;
typedef TX_SIZE TXFM_CONTEXT;
#endif
#if CONFIG_EXT_REFS
#define SINGLE_REFS 6
#define COMP_REFS 5
#else
#define SINGLE_REFS 3
#define COMP_REFS 2
#endif // CONFIG_EXT_REFS
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -43,7 +43,8 @@ struct loopfilter {
uint8_t mode_ref_delta_enabled;
uint8_t mode_ref_delta_update;
// 0 = Intra, Last, GF, ARF
// 0 = Intra, Last, Last2+Last3+LAST4(CONFIG_EXT_REFS),
// GF, ARF
signed char ref_deltas[MAX_REF_FRAMES];
signed char last_ref_deltas[MAX_REF_FRAMES];
......
......@@ -174,6 +174,12 @@ typedef struct VP10Common {
#endif
FRAME_TYPE last_frame_type; /* last frame's frame type for motion search.*/
#if CONFIG_EXT_REFS
// frame type of the frame before last frame
FRAME_TYPE last2_frame_type;
// frame type of the frame two frames before last frame
FRAME_TYPE last3_frame_type;
#endif // CONFIG_EXT_REFS
FRAME_TYPE frame_type;
int show_frame;
......@@ -260,7 +266,7 @@ typedef struct VP10Common {
// Context probabilities for reference frame prediction
MV_REFERENCE_FRAME comp_fixed_ref;
MV_REFERENCE_FRAME comp_var_ref[2];
MV_REFERENCE_FRAME comp_var_ref[COMP_REFS];
REFERENCE_MODE reference_mode;
FRAME_CONTEXT *fc; /* this frame entropy */
......
......@@ -103,89 +103,970 @@ int vp10_get_reference_mode_context(const VP10_COMMON *cm,
return ctx;
}
#if CONFIG_EXT_REFS
// TODO(zoeliu): Future work will be conducted to optimize the context design
// for the coding of the reference frames.
#define CHECK_LAST_OR_LAST2(ref_frame) \
((ref_frame == LAST_FRAME) || (ref_frame == LAST2_FRAME))
#define CHECK_GOLDEN_LAST3_LAST4(ref_frame) \
((ref_frame == GOLDEN_FRAME) || (ref_frame == LAST3_FRAME) || \
(ref_frame == LAST4_FRAME))
// Returns a context number for the given MB prediction signal
// Signal the first reference frame for a compound mode is either
// GOLDEN/LAST3/LAST4, or LAST/LAST2.
//
// NOTE(zoeliu): The probability of ref_frame[0] is either
// GOLDEN_FRAME/LAST3_FRAME/LAST4_FRAME.
int vp10_get_pred_context_comp_ref_p(const VP10_COMMON *cm,
const MACROBLOCKD *xd) {
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
const int above_in_image = xd->up_available;
const int left_in_image = xd->left_available;
// 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
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
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 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[0]));
else // comp pred (1/3)
pred_context = 1 +
2 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[var_ref_idx]));
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && CHECK_GOLDEN_LAST3_LAST4(vrfa)) {
pred_context = 0;
} else if (l_sg && a_sg) { // single/single
if ((vrfa == ALTREF_FRAME && CHECK_LAST_OR_LAST2(vrfl)) ||
(vrfl == ALTREF_FRAME && CHECK_LAST_OR_LAST2(vrfa))) {
pred_context = 4;
} else if (vrfa == vrfl || (CHECK_LAST_OR_LAST2(vrfa) &&
CHECK_LAST_OR_LAST2(vrfl))) {
pred_context = 3;
} else { // Either vrfa or vrfl is GOLDEN / LAST3 / LAST4
// NOTE(zoeliu): Following assert may be removed once confirmed.
assert(CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl));
pred_context = 1;
}
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (CHECK_GOLDEN_LAST3_LAST4(vrfc) && !CHECK_GOLDEN_LAST3_LAST4(rfs))
pred_context = 1;
else if (CHECK_GOLDEN_LAST3_LAST4(rfs) &&
!CHECK_GOLDEN_LAST3_LAST4(vrfc))
pred_context = 2;
else
pred_context = 4;
} else { // comp/comp
if ((CHECK_LAST_OR_LAST2(vrfa) && CHECK_LAST_OR_LAST2(vrfl))) {
pred_context = 4;
} else {
// NOTE(zoeliu): Following assert may be removed once confirmed.
assert(CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl));
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 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[var_ref_idx]));
else
pred_context = 3 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[0]));
}
} 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
// Signal the first reference frame for a compound mode is LAST,
// conditioning on that it is known either LAST/LAST2.
//
// NOTE(zoeliu): The probability of ref_frame[0] is LAST_FRAME,
// conditioning on it is either LAST_FRAME or LAST2_FRAME.
int vp10_get_pred_context_comp_ref_p1(const VP10_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
const int above_in_image = xd->up_available;
const int left_in_image = xd->left_available;
// 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
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
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] != LAST_FRAME);
else // comp pred (1/3)
pred_context = 1 + 2 * (edge_mbmi->ref_frame[var_ref_idx]
!= LAST_FRAME);
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && vrfa == LAST_FRAME)
pred_context = 0;
else if (l_sg && a_sg) { // single/single
if (vrfa == LAST_FRAME || vrfl == LAST_FRAME)
pred_context = 1;
else if (CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl))
pred_context = 2 + (vrfa != vrfl);
else if (vrfa == vrfl)
pred_context = 3;
else
pred_context = 4;
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (vrfc == LAST_FRAME && rfs != LAST_FRAME)
pred_context = 1;
else if (rfs == LAST_FRAME && vrfc != LAST_FRAME)
pred_context = 2;
else
pred_context = 3 +
(vrfc == LAST2_FRAME || CHECK_GOLDEN_LAST3_LAST4(rfs));
} else { // comp/comp
if (vrfa == LAST_FRAME || vrfl == LAST_FRAME)
pred_context = 2;
else
pred_context = 3 + (CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl));
}
}
} 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] != LAST_FRAME);
} else {
if (edge_mbmi->ref_frame[0] == LAST_FRAME)
pred_context = 0;
else
pred_context = 2 + CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[0]);
}
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#define CHECK_LAST3_OR_LAST4(ref_frame) \
((ref_frame == LAST3_FRAME) || (ref_frame == LAST4_FRAME))
// Returns a context number for the given MB prediction signal
// Signal the first reference frame for a compound mode is GOLDEN,
// conditioning on that it is known either GOLDEN/LAST3/LAST4.
//
// NOTE(zoeliu): The probability of ref_frame[0] is GOLDEN_FRAME,
// conditioning on it is either GOLDEN / LAST3 / LAST4.
int vp10_get_pred_context_comp_ref_p2(const VP10_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
const int above_in_image = xd->up_available;
const int left_in_image = xd->left_available;
// 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
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
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] != GOLDEN_FRAME);
else // comp pred (1/3)
pred_context = 1 +
2 * (edge_mbmi->ref_frame[var_ref_idx] != GOLDEN_FRAME);
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && vrfa == GOLDEN_FRAME)
pred_context = 0;
else if (l_sg && a_sg) { // single/single
if (vrfa == GOLDEN_FRAME || vrfl == GOLDEN_FRAME)
pred_context = 1;
else if (CHECK_LAST_OR_LAST2(vrfa) || CHECK_LAST_OR_LAST2(vrfl))
pred_context = 2 + (vrfa != vrfl);
else if (vrfa == vrfl)
pred_context = 3;
else
pred_context = 4;
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (vrfc == GOLDEN_FRAME && rfs != GOLDEN_FRAME)
pred_context = 1;
else if (rfs == GOLDEN_FRAME && vrfc != GOLDEN_FRAME)
pred_context = 2;
else
pred_context = 3 +
(CHECK_LAST3_OR_LAST4(vrfc) || CHECK_LAST_OR_LAST2(rfs));
} else { // comp/comp
if (vrfa == GOLDEN_FRAME || vrfl == GOLDEN_FRAME)
pred_context = 2;
else
pred_context = 3 +
(CHECK_LAST_OR_LAST2(vrfa) || CHECK_LAST_OR_LAST2(vrfl));
}
}
} 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] != GOLDEN_FRAME);
} else {
if (edge_mbmi->ref_frame[0] == GOLDEN_FRAME)
pred_context = 0;
else
pred_context = 2 + CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]);
}
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#define CHECK_LAST_LAST2_GOLDEN(ref_frame) \
((ref_frame == LAST_FRAME) || (ref_frame == LAST2_FRAME) || \
(ref_frame == GOLDEN_FRAME))
// Returns a context number for the given MB prediction signal
// Signal the first reference frame for a compound mode is LAST3,
// conditioning on that it is known either LAST3/LAST4.
//
// NOTE(zoeliu): The probability of ref_frame[0] is LAST3_FRAME,
// conditioning on it is either LAST3 / LAST4.
int vp10_get_pred_context_comp_ref_p3(const VP10_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
const int above_in_image = xd->up_available;
const int left_in_image = xd->left_available;
// 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
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
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] != LAST3_FRAME);
else // comp pred (1/3)
pred_context = 1 +
2 * (edge_mbmi->ref_frame[var_ref_idx] != LAST3_FRAME);
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && vrfa == LAST3_FRAME)
pred_context = 0;
else if (l_sg && a_sg) { // single/single
if (vrfa == LAST3_FRAME || vrfl == LAST3_FRAME)
pred_context = 1;
else if (CHECK_LAST_LAST2_GOLDEN(vrfa) || CHECK_LAST_LAST2_GOLDEN(vrfl))
pred_context = 2 + (vrfa != vrfl);
else if (vrfa == vrfl)
pred_context = 3;
else
pred_context = 4;
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (vrfc == LAST3_FRAME && rfs != LAST3_FRAME)
pred_context = 1;
else if (rfs == LAST3_FRAME && vrfc != LAST3_FRAME)
pred_context = 2;
else
pred_context = 3 +
(vrfc == LAST4_FRAME || CHECK_LAST_LAST2_GOLDEN(rfs));
} else { // comp/comp
if (vrfa == LAST3_FRAME || vrfl == LAST3_FRAME)
pred_context = 2;
else
pred_context = 3 +
(CHECK_LAST_LAST2_GOLDEN(vrfa) || CHECK_LAST_LAST2_GOLDEN(vrfl));
}
}
} 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] != LAST3_FRAME);
} else {
if (edge_mbmi->ref_frame[0] == LAST3_FRAME)
pred_context = 0;
else
pred_context = 2 + CHECK_LAST_LAST2_GOLDEN(edge_mbmi->ref_frame[0]);
}
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#else // CONFIG_EXT_REFS
// Returns a context number for the given MB prediction signal
int vp10_get_pred_context_comp_ref_p(const VP10_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
const int above_in_image = xd->up_available;
const int left_in_image = xd->left_available;
// 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
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
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);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const 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
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const 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 {