From: Zoe Liu Date: Thu, 12 Nov 2015 10:12:17 +0000 (-0800) Subject: Added 3 more reference frames for inter prediction. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3ec1601e37ff58fbf7b2857a375c7e194907bda8;p=libvpx 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 --- diff --git a/vp10/common/blockd.h b/vp10/common/blockd.h index bb943970e..9974da924 100644 --- a/vp10/common/blockd.h +++ b/vp10/common/blockd.h @@ -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 { diff --git a/vp10/common/entropymode.c b/vp10/common/entropymode.c index 9142d6a80..306125833 100644 --- a/vp10/common/entropymode.c +++ b/vp10/common/entropymode.c @@ -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; diff --git a/vp10/common/entropymode.h b/vp10/common/entropymode.h index 0d2ed50d5..52c3630fc 100644 --- a/vp10/common/entropymode.h +++ b/vp10/common/entropymode.h @@ -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]; diff --git a/vp10/common/enums.h b/vp10/common/enums.h index 3f9395eec..1cd6e7a60 100644 --- a/vp10/common/enums.h +++ b/vp10/common/enums.h @@ -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 diff --git a/vp10/common/loopfilter.h b/vp10/common/loopfilter.h index 513fbe3bd..3d764394e 100644 --- a/vp10/common/loopfilter.h +++ b/vp10/common/loopfilter.h @@ -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]; diff --git a/vp10/common/onyxc_int.h b/vp10/common/onyxc_int.h index e3fef907c..86ec7d8dc 100644 --- a/vp10/common/onyxc_int.h +++ b/vp10/common/onyxc_int.h @@ -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 */ diff --git a/vp10/common/pred_common.c b/vp10/common/pred_common.c index 2e79e0de3..9c42794c7 100644 --- a/vp10/common/pred_common.c +++ b/vp10/common/pred_common.c @@ -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 { + 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; +} + +#endif // CONFIG_EXT_REFS + +#if CONFIG_EXT_REFS + +#define CHECK_GOLDEN_OR_ALTREF(ref_frame) \ + ((ref_frame == GOLDEN_FRAME) || (ref_frame == ALTREF_FRAME)) + +// For the bit to signal whether the single reference is a ALTREF_FRAME +// or a GOLDEN_FRAME. +// +// NOTE(zoeliu): The probability of ref_frame[0] is ALTREF/GOLDEN. +int vp10_get_pred_context_single_ref_p1(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 has_above = xd->up_available; + const int has_left = 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. + if (has_above && has_left) { // 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 + 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 * (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0])); + else + pred_context = 1 + (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) || + !CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[1])); + } else { // inter/inter + const int above_has_second = has_second_ref(above_mbmi); + const int left_has_second = has_second_ref(left_mbmi); + + const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1]; + const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1]; + + if (above_has_second && left_has_second) { + pred_context = 1 + (!CHECK_GOLDEN_OR_ALTREF(above0) || + !CHECK_GOLDEN_OR_ALTREF(above1) || + !CHECK_GOLDEN_OR_ALTREF(left0) || + !CHECK_GOLDEN_OR_ALTREF(left1)); + } else if (above_has_second || left_has_second) { + const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1; + + if (!CHECK_GOLDEN_OR_ALTREF(rfs)) + pred_context = 3 + (!CHECK_GOLDEN_OR_ALTREF(crf1) || + !CHECK_GOLDEN_OR_ALTREF(crf2)); + else + pred_context = !CHECK_GOLDEN_OR_ALTREF(crf1) || + !CHECK_GOLDEN_OR_ALTREF(crf2); + } else { + pred_context = 2 * (!CHECK_GOLDEN_OR_ALTREF(above0)) + + 2 * (!CHECK_GOLDEN_OR_ALTREF(left0)); + } + } + } else if (has_above || has_left) { // one edge available + const MB_MODE_INFO *edge_mbmi = has_above ? 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 * (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0])); + else + pred_context = 1 + (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) || + !CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[1])); + } + } else { // no edges available + pred_context = 2; + } + + assert(pred_context >= 0 && pred_context < REF_CONTEXTS); + return pred_context; +} + +// For the bit to signal whether the single reference is ALTREF_FRAME or +// GOLDEN_FRAME, knowing that it shall be either of these 2 choices. +// +// NOTE(zoeliu): The probability of ref_frame[0] is ALTREF_FRAME, conditioning +// on it is either ALTREF_FRAME/GOLDEN_FRAME. +int vp10_get_pred_context_single_ref_p2(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 has_above = xd->up_available; + const int has_left = 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. + if (has_above && has_left) { // 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 + 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 (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0])) + 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 + const int above_has_second = has_second_ref(above_mbmi); + const int left_has_second = has_second_ref(left_mbmi); + const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1]; + const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1]; + + if (above_has_second && left_has_second) { + if (above0 == left0 && above1 == left1) + pred_context = 3 * (above0 == GOLDEN_FRAME || + above1 == GOLDEN_FRAME || + left0 == GOLDEN_FRAME || + left1 == GOLDEN_FRAME); + else + pred_context = 2; + } else if (above_has_second || left_has_second) { + const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1; + + 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 (!CHECK_GOLDEN_OR_ALTREF(above0) && !CHECK_GOLDEN_OR_ALTREF(left0)) { + pred_context = 2 + (above0 == left0); + } else if (!CHECK_GOLDEN_OR_ALTREF(above0) || + !CHECK_GOLDEN_OR_ALTREF(left0)) { + const MV_REFERENCE_FRAME edge0 = + !CHECK_GOLDEN_OR_ALTREF(above0) ? left0 : above0; + pred_context = 4 * (edge0 == GOLDEN_FRAME); + } else { + pred_context = 2 * (above0 == GOLDEN_FRAME) + + 2 * (left0 == GOLDEN_FRAME); + } + } + } + } else if (has_above || has_left) { // one edge available + const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi; + + if (!is_inter_block(edge_mbmi) || + (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) && + !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; +} + +// For the bit to signal whether the single reference is LAST3/LAST4 or +// LAST2/LAST, knowing that it shall be either of these 2 choices. +// +// NOTE(zoeliu): The probability of ref_frame[0] is LAST3/LAST4, conditioning +// on it is either LAST3/LAST4/LAST2/LAST. +int vp10_get_pred_context_single_ref_p3(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; + const int has_above = xd->up_available; + const int has_left = 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 + if (has_above && has_left) { // 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) + if (above_intra && left_intra) { // intra/intra pred_context = 2; - } else if (above_intra || left_intra) { // intra/inter + } 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)) // 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]); + if (!has_second_ref(edge_mbmi)) { + if (CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0])) + pred_context = 3; + else + pred_context = 4 * CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]); + } else { + pred_context = 1 + + 2 * (CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]) || + CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[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]; + const int above_has_second = has_second_ref(above_mbmi); + const int left_has_second = has_second_ref(left_mbmi); + const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1]; + const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1]; - 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; + if (above_has_second && left_has_second) { + if (above0 == left0 && above1 == left1) + pred_context = 3 * (CHECK_LAST_OR_LAST2(above0) || + CHECK_LAST_OR_LAST2(above1) || + CHECK_LAST_OR_LAST2(left0) || + CHECK_LAST_OR_LAST2(left1)); 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 if (above_has_second || left_has_second) { + const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1; + + if (CHECK_LAST_OR_LAST2(rfs)) + pred_context = 3 + (CHECK_LAST_OR_LAST2(crf1) || + CHECK_LAST_OR_LAST2(crf2)); + else if (rfs == LAST3_FRAME || rfs == LAST4_FRAME) + pred_context = (CHECK_LAST_OR_LAST2(crf1) || + CHECK_LAST_OR_LAST2(crf2)); else - pred_context = 4; - } else if (vrfa == vrfl) { // comp/comp - pred_context = 4; + pred_context = 1 + 2 * (CHECK_LAST_OR_LAST2(crf1) || + CHECK_LAST_OR_LAST2(crf2)); } else { - pred_context = 2; + if (CHECK_GOLDEN_OR_ALTREF(above0) && CHECK_GOLDEN_OR_ALTREF(left0)) { + pred_context = 2 + (above0 == left0); + } else if (CHECK_GOLDEN_OR_ALTREF(above0) || + CHECK_GOLDEN_OR_ALTREF(left0)) { + const MV_REFERENCE_FRAME edge0 = + CHECK_GOLDEN_OR_ALTREF(above0) ? left0 : above0; + pred_context = 4 * CHECK_LAST_OR_LAST2(edge0); + } else { + pred_context = 2 * CHECK_LAST_OR_LAST2(above0) + + 2 * CHECK_LAST_OR_LAST2(left0); + } } } - } else if (above_in_image || left_in_image) { // one edge available - const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi; + } else if (has_above || has_left) { // one edge available + const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi; - if (!is_inter_block(edge_mbmi)) { + if (!is_inter_block(edge_mbmi) || + (CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) && + !has_second_ref(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 if (!has_second_ref(edge_mbmi)) + pred_context = 4 * (CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0])); + else + pred_context = 3 * (CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]) || + CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[1])); + } else { // no edges available (2) + pred_context = 2; + } + + assert(pred_context >= 0 && pred_context < REF_CONTEXTS); + return pred_context; +} + +// For the bit to signal whether the single reference is LAST2_FRAME or +// LAST_FRAME, knowing that it shall be either of these 2 choices. +// +// NOTE(zoeliu): The probability of ref_frame[0] is LAST2_FRAME, conditioning +// on it is either LAST2_FRAME/LAST_FRAME. +int vp10_get_pred_context_single_ref_p4(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 has_above = xd->up_available; + const int has_left = 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. + if (has_above && has_left) { // 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 + 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 (!CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0])) + pred_context = 3; + else + pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST_FRAME); + } else { + pred_context = 1 + + 2 * (edge_mbmi->ref_frame[0] == LAST_FRAME || + edge_mbmi->ref_frame[1] == LAST_FRAME); + } + } else { // inter/inter + const int above_has_second = has_second_ref(above_mbmi); + const int left_has_second = has_second_ref(left_mbmi); + const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1]; + const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1]; + + if (above_has_second && left_has_second) { + if (above0 == left0 && above1 == left1) + pred_context = 3 * (above0 == LAST_FRAME || above1 == LAST_FRAME || + left0 == LAST_FRAME || left1 == LAST_FRAME); + else + pred_context = 2; + } else if (above_has_second || left_has_second) { + const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1; + + if (rfs == LAST_FRAME) + pred_context = 3 + (crf1 == LAST_FRAME || crf2 == LAST_FRAME); + else if (rfs == LAST2_FRAME) + pred_context = (crf1 == LAST_FRAME || crf2 == LAST_FRAME); + else + pred_context = 1 + 2 * (crf1 == LAST_FRAME || crf2 == LAST_FRAME); + } else { + if (!CHECK_LAST_OR_LAST2(above0) && + !CHECK_LAST_OR_LAST2(left0)) { + pred_context = 2 + (above0 == left0); + } else if (!CHECK_LAST_OR_LAST2(above0) || + !CHECK_LAST_OR_LAST2(left0)) { + const MV_REFERENCE_FRAME edge0 = + !CHECK_LAST_OR_LAST2(above0) ? left0 : above0; + pred_context = 4 * (edge0 == LAST_FRAME); + } else { + pred_context = 2 * (above0 == LAST_FRAME) + 2 * (left0 == LAST_FRAME); + } + } } + } else if (has_above || has_left) { // one edge available + const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi; + + if (!is_inter_block(edge_mbmi) || + (!CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]) && + !has_second_ref(edge_mbmi))) + pred_context = 2; + else if (!has_second_ref(edge_mbmi)) + pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST_FRAME); + else + pred_context = 3 * (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); + return pred_context; +} + +// For the bit to signal whether the single reference is LAST4_FRAME or +// LAST3_FRAME, knowing that it shall be either of these 2 choices. +// +// NOTE(zoeliu): The probability of ref_frame[0] is LAST4_FRAME, conditioning +// on it is either LAST4_FRAME/LAST3_FRAME. +int vp10_get_pred_context_single_ref_p5(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 has_above = xd->up_available; + const int has_left = 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. + if (has_above && has_left) { // 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 + 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 (!CHECK_LAST3_OR_LAST4(edge_mbmi->ref_frame[0])) + pred_context = 3; + else + pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST3_FRAME); + } else { + pred_context = 1 + + 2 * (edge_mbmi->ref_frame[0] == LAST3_FRAME || + edge_mbmi->ref_frame[1] == LAST3_FRAME); + } + } else { // inter/inter + const int above_has_second = has_second_ref(above_mbmi); + const int left_has_second = has_second_ref(left_mbmi); + const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1]; + const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1]; + + if (above_has_second && left_has_second) { + if (above0 == left0 && above1 == left1) + pred_context = 3 * (above0 == LAST3_FRAME || above1 == LAST3_FRAME || + left0 == LAST3_FRAME || left1 == LAST3_FRAME); + else + pred_context = 2; + } else if (above_has_second || left_has_second) { + const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0; + const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1; + + if (rfs == LAST3_FRAME) + pred_context = 3 + (crf1 == LAST3_FRAME || crf2 == LAST3_FRAME); + else if (rfs == LAST4_FRAME) + pred_context = (crf1 == LAST3_FRAME || crf2 == LAST3_FRAME); + else + pred_context = 1 + 2 * (crf1 == LAST3_FRAME || crf2 == LAST3_FRAME); + } else { + if (!CHECK_LAST3_OR_LAST4(above0) && + !CHECK_LAST3_OR_LAST4(left0)) { + pred_context = 2 + (above0 == left0); + } else if (!CHECK_LAST3_OR_LAST4(above0) || + !CHECK_LAST3_OR_LAST4(left0)) { + const MV_REFERENCE_FRAME edge0 = + !CHECK_LAST3_OR_LAST4(above0) ? left0 : above0; + pred_context = 4 * (edge0 == LAST3_FRAME); + } else { + pred_context = 2 * (above0 == LAST3_FRAME) + + 2 * (left0 == LAST3_FRAME); + } + } + } + } else if (has_above || has_left) { // one edge available + const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi; + + if (!is_inter_block(edge_mbmi) || + (!CHECK_LAST3_OR_LAST4(edge_mbmi->ref_frame[0]) && + !has_second_ref(edge_mbmi))) + pred_context = 2; + else if (!has_second_ref(edge_mbmi)) + pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST3_FRAME); + else + pred_context = 3 * (edge_mbmi->ref_frame[0] == LAST3_FRAME || + edge_mbmi->ref_frame[1] == LAST3_FRAME); + } else { // no edges available (2) + pred_context = 2; + } + assert(pred_context >= 0 && pred_context < REF_CONTEXTS); return pred_context; } +#else // CONFIG_EXT_REFS + int vp10_get_pred_context_single_ref_p1(const MACROBLOCKD *xd) { int pred_context; const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; @@ -337,3 +1218,5 @@ int vp10_get_pred_context_single_ref_p2(const MACROBLOCKD *xd) { assert(pred_context >= 0 && pred_context < REF_CONTEXTS); return pred_context; } + +#endif // CONFIG_EXT_REFS diff --git a/vp10/common/pred_common.h b/vp10/common/pred_common.h index ebba225df..4ebfcdb97 100644 --- a/vp10/common/pred_common.h +++ b/vp10/common/pred_common.h @@ -87,25 +87,77 @@ int vp10_get_pred_context_comp_ref_p(const VP10_COMMON *cm, const MACROBLOCKD *xd); static INLINE vpx_prob vp10_get_pred_prob_comp_ref_p(const VP10_COMMON *cm, - const MACROBLOCKD *xd) { + const MACROBLOCKD *xd) { const int pred_context = vp10_get_pred_context_comp_ref_p(cm, xd); - return cm->fc->comp_ref_prob[pred_context]; + return cm->fc->comp_ref_prob[pred_context][0]; } +#if CONFIG_EXT_REFS +int vp10_get_pred_context_comp_ref_p1(const VP10_COMMON *cm, + const MACROBLOCKD *xd); + +static INLINE vpx_prob vp10_get_pred_prob_comp_ref_p1(const VP10_COMMON *cm, + const MACROBLOCKD *xd) { + const int pred_context = vp10_get_pred_context_comp_ref_p1(cm, xd); + return cm->fc->comp_ref_prob[pred_context][1]; +} + +int vp10_get_pred_context_comp_ref_p2(const VP10_COMMON *cm, + const MACROBLOCKD *xd); + +static INLINE vpx_prob vp10_get_pred_prob_comp_ref_p2(const VP10_COMMON *cm, + const MACROBLOCKD *xd) { + const int pred_context = vp10_get_pred_context_comp_ref_p2(cm, xd); + return cm->fc->comp_ref_prob[pred_context][2]; +} + +int vp10_get_pred_context_comp_ref_p3(const VP10_COMMON *cm, + const MACROBLOCKD *xd); + +static INLINE vpx_prob vp10_get_pred_prob_comp_ref_p3(const VP10_COMMON *cm, + const MACROBLOCKD *xd) { + const int pred_context = vp10_get_pred_context_comp_ref_p3(cm, xd); + return cm->fc->comp_ref_prob[pred_context][3]; +} +#endif // CONFIG_EXT_REFS + int vp10_get_pred_context_single_ref_p1(const MACROBLOCKD *xd); static INLINE vpx_prob vp10_get_pred_prob_single_ref_p1(const VP10_COMMON *cm, - const MACROBLOCKD *xd) { + const MACROBLOCKD *xd) { return cm->fc->single_ref_prob[vp10_get_pred_context_single_ref_p1(xd)][0]; } int vp10_get_pred_context_single_ref_p2(const MACROBLOCKD *xd); static INLINE vpx_prob vp10_get_pred_prob_single_ref_p2(const VP10_COMMON *cm, - const MACROBLOCKD *xd) { + const MACROBLOCKD *xd) { return cm->fc->single_ref_prob[vp10_get_pred_context_single_ref_p2(xd)][1]; } +#if CONFIG_EXT_REFS +int vp10_get_pred_context_single_ref_p3(const MACROBLOCKD *xd); + +static INLINE vpx_prob vp10_get_pred_prob_single_ref_p3(const VP10_COMMON *cm, + const MACROBLOCKD *xd) { + return cm->fc->single_ref_prob[vp10_get_pred_context_single_ref_p3(xd)][2]; +} + +int vp10_get_pred_context_single_ref_p4(const MACROBLOCKD *xd); + +static INLINE vpx_prob vp10_get_pred_prob_single_ref_p4(const VP10_COMMON *cm, + const MACROBLOCKD *xd) { + return cm->fc->single_ref_prob[vp10_get_pred_context_single_ref_p4(xd)][3]; +} + +int vp10_get_pred_context_single_ref_p5(const MACROBLOCKD *xd); + +static INLINE vpx_prob vp10_get_pred_prob_single_ref_p5(const VP10_COMMON *cm, + const MACROBLOCKD *xd) { + return cm->fc->single_ref_prob[vp10_get_pred_context_single_ref_p5(xd)][4]; +} +#endif // CONFIG_EXT_REFS + // 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. diff --git a/vp10/common/thread_common.c b/vp10/common/thread_common.c index 55b3537e8..80d8d143c 100644 --- a/vp10/common/thread_common.c +++ b/vp10/common/thread_common.c @@ -379,13 +379,14 @@ void vp10_accumulate_frame_counts(VP10_COMMON *cm, FRAME_COUNTS *counts, cm->counts.comp_inter[i][j] += counts->comp_inter[i][j]; for (i = 0; i < REF_CONTEXTS; i++) - for (j = 0; j < 2; j++) + for (j = 0; j < (SINGLE_REFS - 1); j++) for (k = 0; k < 2; k++) - cm->counts.single_ref[i][j][k] += counts->single_ref[i][j][k]; + cm->counts.single_ref[i][j][k] += counts->single_ref[i][j][k]; for (i = 0; i < REF_CONTEXTS; i++) - for (j = 0; j < 2; j++) - cm->counts.comp_ref[i][j] += counts->comp_ref[i][j]; + for (j = 0; j < (COMP_REFS - 1); j++) + for (k = 0; k < 2; k++) + cm->counts.comp_ref[i][j][k] += counts->comp_ref[i][j][k]; for (i = 0; i < TX_SIZE_CONTEXTS; i++) { for (j = 0; j < TX_SIZES; j++) diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c index 531be1ffe..438d6df67 100644 --- a/vp10/decoder/decodeframe.c +++ b/vp10/decoder/decodeframe.c @@ -61,13 +61,26 @@ static void setup_compound_reference_mode(VP10_COMMON *cm) { cm->ref_frame_sign_bias[GOLDEN_FRAME]) { cm->comp_fixed_ref = ALTREF_FRAME; cm->comp_var_ref[0] = LAST_FRAME; +#if CONFIG_EXT_REFS + cm->comp_var_ref[1] = LAST2_FRAME; + cm->comp_var_ref[2] = LAST3_FRAME; + cm->comp_var_ref[3] = LAST4_FRAME; + cm->comp_var_ref[4] = GOLDEN_FRAME; +#else cm->comp_var_ref[1] = GOLDEN_FRAME; +#endif // CONFIG_EXT_REFS } else if (cm->ref_frame_sign_bias[LAST_FRAME] == cm->ref_frame_sign_bias[ALTREF_FRAME]) { +#if CONFIG_EXT_REFS + assert(0); +#endif // CONFIG_EXT_REFS cm->comp_fixed_ref = GOLDEN_FRAME; cm->comp_var_ref[0] = LAST_FRAME; cm->comp_var_ref[1] = ALTREF_FRAME; } else { +#if CONFIG_EXT_REFS + assert(0); +#endif // CONFIG_EXT_REFS cm->comp_fixed_ref = LAST_FRAME; cm->comp_var_ref[0] = GOLDEN_FRAME; cm->comp_var_ref[1] = ALTREF_FRAME; @@ -130,21 +143,27 @@ static REFERENCE_MODE read_frame_reference_mode(const VP10_COMMON *cm, static void read_frame_reference_mode_probs(VP10_COMMON *cm, vpx_reader *r) { FRAME_CONTEXT *const fc = cm->fc; - int i; + int i, j; if (cm->reference_mode == REFERENCE_MODE_SELECT) for (i = 0; i < COMP_INTER_CONTEXTS; ++i) vp10_diff_update_prob(r, &fc->comp_inter_prob[i]); - if (cm->reference_mode != COMPOUND_REFERENCE) + if (cm->reference_mode != COMPOUND_REFERENCE) { for (i = 0; i < REF_CONTEXTS; ++i) { - vp10_diff_update_prob(r, &fc->single_ref_prob[i][0]); - vp10_diff_update_prob(r, &fc->single_ref_prob[i][1]); + for (j = 0; j < (SINGLE_REFS - 1); ++j) { + vp10_diff_update_prob(r, &fc->single_ref_prob[i][j]); + } } + } - if (cm->reference_mode != SINGLE_REFERENCE) - for (i = 0; i < REF_CONTEXTS; ++i) - vp10_diff_update_prob(r, &fc->comp_ref_prob[i]); + if (cm->reference_mode != SINGLE_REFERENCE) { + for (i = 0; i < REF_CONTEXTS; ++i) { + for (j = 0; j < (COMP_REFS - 1); ++j) { + vp10_diff_update_prob(r, &fc->comp_ref_prob[i][j]); + } + } + } } static void update_mv_probs(vpx_prob *p, int n, vpx_reader *r) { @@ -1938,6 +1957,10 @@ static size_t read_uncompressed_header(VP10Decoder *pbi, int i, mask, ref_index = 0; size_t sz; +#if CONFIG_EXT_REFS + cm->last3_frame_type = cm->last2_frame_type; + cm->last2_frame_type = cm->last_frame_type; +#endif // CONFIG_EXT_REFS cm->last_frame_type = cm->frame_type; cm->last_intra_only = cm->intra_only; @@ -2106,20 +2129,70 @@ static size_t read_uncompressed_header(VP10Decoder *pbi, // Generate next_ref_frame_map. lock_buffer_pool(pool); for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) { +#if CONFIG_EXT_REFS +// TODO(zoeliu): To move the following #define's to a header file +#define PBI_LST_FB_IDX 0 +#define PBI_LST2_FB_IDX 1 +#define PBI_LST3_FB_IDX 2 +#define PBI_LST4_FB_IDX 3 +#define PBI_GLD_FB_IDX 4 +#define PBI_ALT_FB_IDX 5 + // NOTE(zoeliu): + // (1) When ref_index == PBI_LST2_FB_IDX and the corresponding mask bit is + // set, it indicates that LAST2_FRAME shall be refreshed, but keep in + // mind that this has already been handled when LAST_FRAME is being + // refreshed, i.e., when ref_index == PBI_LST_FB_IDX and the mask bit + // is being set correspondingly; + // (2) The only exception is that when current frame is a KEY_FRAME, where + // all the frames in the frame buffer shall get refreshed; + // (3) Similar handling for when ref_index == PBI_LST3_FB_IDX or when + // ref_indx == PBI_LST4_FB_IDX. + if ((mask & 1) && + (cm->frame_type == KEY_FRAME || (ref_index != PBI_LST2_FB_IDX && + ref_index != PBI_LST3_FB_IDX && + ref_index != PBI_LST4_FB_IDX))) { + // The reference frame map for the decoding of the next frame is updated + // and held by either current thread or possibly another decoder thread. + if (cm->frame_type != KEY_FRAME && ref_index == PBI_LST_FB_IDX && + (mask & (1 << PBI_LST2_FB_IDX))) { + if (mask & (1 << PBI_LST3_FB_IDX)) { + if (mask & (1 << PBI_LST4_FB_IDX)) { + cm->next_ref_frame_map[PBI_LST4_FB_IDX] = + cm->next_ref_frame_map[PBI_LST3_FB_IDX]; + ++frame_bufs[cm->next_ref_frame_map[PBI_LST3_FB_IDX]].ref_count; + } + cm->next_ref_frame_map[PBI_LST3_FB_IDX] = + cm->next_ref_frame_map[PBI_LST2_FB_IDX]; + ++frame_bufs[cm->next_ref_frame_map[PBI_LST2_FB_IDX]].ref_count; + } + cm->next_ref_frame_map[PBI_LST2_FB_IDX] = + cm->next_ref_frame_map[PBI_LST_FB_IDX]; + ++frame_bufs[cm->next_ref_frame_map[PBI_LST_FB_IDX]].ref_count; + } + cm->next_ref_frame_map[ref_index] = cm->new_fb_idx; + ++frame_bufs[cm->new_fb_idx].ref_count; + } else if (!(mask & 1)) { + cm->next_ref_frame_map[ref_index] = cm->ref_frame_map[ref_index]; + } +#else if (mask & 1) { cm->next_ref_frame_map[ref_index] = cm->new_fb_idx; ++frame_bufs[cm->new_fb_idx].ref_count; } else { cm->next_ref_frame_map[ref_index] = cm->ref_frame_map[ref_index]; } +#endif // CONFIG_EXT_REFS + // Current thread holds the reference frame. if (cm->ref_frame_map[ref_index] >= 0) ++frame_bufs[cm->ref_frame_map[ref_index]].ref_count; + ++ref_index; } for (; ref_index < REF_FRAMES; ++ref_index) { cm->next_ref_frame_map[ref_index] = cm->ref_frame_map[ref_index]; + // Current thread holds the reference frame. if (cm->ref_frame_map[ref_index] >= 0) ++frame_bufs[cm->ref_frame_map[ref_index]].ref_count; diff --git a/vp10/decoder/decodemv.c b/vp10/decoder/decodemv.c index d66ddd9f9..ea21c8bf5 100644 --- a/vp10/decoder/decodemv.c +++ b/vp10/decoder/decodemv.c @@ -534,12 +534,68 @@ static void read_ref_frames(VP10_COMMON *const cm, MACROBLOCKD *const xd, if (mode == COMPOUND_REFERENCE) { const int idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref]; const int ctx = vp10_get_pred_context_comp_ref_p(cm, xd); - const int bit = vpx_read(r, fc->comp_ref_prob[ctx]); + const int bit = vpx_read(r, fc->comp_ref_prob[ctx][0]); if (counts) - ++counts->comp_ref[ctx][bit]; + ++counts->comp_ref[ctx][0][bit]; ref_frame[idx] = cm->comp_fixed_ref; + +#if CONFIG_EXT_REFS + if (!bit) { + const int ctx1 = vp10_get_pred_context_comp_ref_p1(cm, xd); + const int bit1 = vpx_read(r, fc->comp_ref_prob[ctx1][1]); + if (counts) + ++counts->comp_ref[ctx1][1][bit1]; + ref_frame[!idx] = cm->comp_var_ref[bit1 ? 0 : 1]; + } else { + const int ctx2 = vp10_get_pred_context_comp_ref_p2(cm, xd); + const int bit2 = vpx_read(r, fc->comp_ref_prob[ctx2][2]); + if (counts) + ++counts->comp_ref[ctx2][2][bit2]; + if (!bit2) { + const int ctx3 = vp10_get_pred_context_comp_ref_p3(cm, xd); + const int bit3 = vpx_read(r, fc->comp_ref_prob[ctx3][3]); + if (counts) + ++counts->comp_ref[ctx3][3][bit3]; + ref_frame[!idx] = cm->comp_var_ref[bit3 ? 2 : 3]; + } else { + ref_frame[!idx] = cm->comp_var_ref[4]; + } + } +#else ref_frame[!idx] = cm->comp_var_ref[bit]; +#endif // CONFIG_EXT_REFS } else if (mode == SINGLE_REFERENCE) { +#if CONFIG_EXT_REFS + const int ctx0 = vp10_get_pred_context_single_ref_p1(xd); + const int bit0 = vpx_read(r, fc->single_ref_prob[ctx0][0]); + if (counts) + ++counts->single_ref[ctx0][0][bit0]; + if (bit0) { + const int ctx1 = vp10_get_pred_context_single_ref_p2(xd); + const int bit1 = vpx_read(r, fc->single_ref_prob[ctx1][1]); + if (counts) + ++counts->single_ref[ctx1][1][bit1]; + ref_frame[0] = bit1 ? ALTREF_FRAME : GOLDEN_FRAME; + } else { + const int ctx2 = vp10_get_pred_context_single_ref_p3(xd); + const int bit2 = vpx_read(r, fc->single_ref_prob[ctx2][2]); + if (counts) + ++counts->single_ref[ctx2][2][bit2]; + if (bit2) { + const int ctx4 = vp10_get_pred_context_single_ref_p5(xd); + const int bit4 = vpx_read(r, fc->single_ref_prob[ctx4][4]); + if (counts) + ++counts->single_ref[ctx4][4][bit4]; + ref_frame[0] = bit4 ? LAST4_FRAME : LAST3_FRAME; + } else { + const int ctx3 = vp10_get_pred_context_single_ref_p4(xd); + const int bit3 = vpx_read(r, fc->single_ref_prob[ctx3][3]); + if (counts) + ++counts->single_ref[ctx3][3][bit3]; + ref_frame[0] = bit3 ? LAST2_FRAME : LAST_FRAME; + } + } +#else const int ctx0 = vp10_get_pred_context_single_ref_p1(xd); const int bit0 = vpx_read(r, fc->single_ref_prob[ctx0][0]); if (counts) @@ -553,6 +609,7 @@ static void read_ref_frames(VP10_COMMON *const cm, MACROBLOCKD *const xd, } else { ref_frame[0] = LAST_FRAME; } +#endif // CONFIG_EXT_REFS ref_frame[1] = NONE; } else { diff --git a/vp10/decoder/decoder.c b/vp10/decoder/decoder.c index 749923072..2dbadb3b2 100644 --- a/vp10/decoder/decoder.c +++ b/vp10/decoder/decoder.c @@ -196,10 +196,23 @@ vpx_codec_err_t vp10_set_reference_dec(VP10_COMMON *cm, // later commit that adds VP9-specific controls for this functionality. if (ref_frame_flag == VP9_LAST_FLAG) { ref_buf = &cm->frame_refs[0]; +#if CONFIG_EXT_REFS + } else if (ref_frame_flag == VP9_LAST2_FLAG) { + ref_buf = &cm->frame_refs[1]; + } else if (ref_frame_flag == VP9_LAST3_FLAG) { + ref_buf = &cm->frame_refs[2]; + } else if (ref_frame_flag == VP9_LAST4_FLAG) { + ref_buf = &cm->frame_refs[3]; + } else if (ref_frame_flag == VP9_GOLD_FLAG) { + ref_buf = &cm->frame_refs[4]; + } else if (ref_frame_flag == VP9_ALT_FLAG) { + ref_buf = &cm->frame_refs[5]; +#else } else if (ref_frame_flag == VP9_GOLD_FLAG) { ref_buf = &cm->frame_refs[1]; } else if (ref_frame_flag == VP9_ALT_FLAG) { ref_buf = &cm->frame_refs[2]; +#endif // CONFIG_EXT_REFS } else { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Invalid reference frame"); @@ -243,10 +256,10 @@ static void swap_frame_buffers(VP10Decoder *pbi) { // Current thread releases the holding of reference frame. decrease_ref_count(old_idx, frame_bufs, pool); - // Release the reference frame in reference map. - if ((mask & 1) && old_idx >= 0) { + // Release the reference frame holding in the reference map for the decoding + // of the next frame. + if (mask & 1) decrease_ref_count(old_idx, frame_bufs, pool); - } cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index]; ++ref_index; } @@ -268,7 +281,7 @@ static void swap_frame_buffers(VP10Decoder *pbi) { } // Invalidate these references until the next frame starts. - for (ref_index = 0; ref_index < 3; ref_index++) + for (ref_index = 0; ref_index < REFS_PER_FRAME; ref_index++) cm->frame_refs[ref_index].idx = -1; } @@ -326,7 +339,6 @@ int vp10_receive_compressed_data(VP10Decoder *pbi, pbi->cur_buf = &frame_bufs[cm->new_fb_idx]; } - if (setjmp(cm->error.jmp)) { const VPxWorkerInterface *const winterface = vpx_get_worker_interface(); int i; @@ -350,10 +362,10 @@ int vp10_receive_compressed_data(VP10Decoder *pbi, // Current thread releases the holding of reference frame. decrease_ref_count(old_idx, frame_bufs, pool); - // Release the reference frame in reference map. - if ((mask & 1) && old_idx >= 0) { + // Release the reference frame holding in the reference map for the + // decoding of the next frame. + if (mask & 1) decrease_ref_count(old_idx, frame_bufs, pool); - } ++ref_index; } diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c index a80e5bd56..3fdad0ceb 100644 --- a/vp10/encoder/bitstream.c +++ b/vp10/encoder/bitstream.c @@ -484,15 +484,58 @@ static void write_ref_frames(const VP10_COMMON *cm, const MACROBLOCKD *xd, } if (is_compound) { - vpx_write(w, mbmi->ref_frame[0] == GOLDEN_FRAME, - vp10_get_pred_prob_comp_ref_p(cm, xd)); +#if CONFIG_EXT_REFS + const int bit = (mbmi->ref_frame[0] == GOLDEN_FRAME || + mbmi->ref_frame[0] == LAST3_FRAME || + mbmi->ref_frame[0] == LAST4_FRAME); +#else + const int bit = mbmi->ref_frame[0] == GOLDEN_FRAME; +#endif // CONFIG_EXT_REFS + vpx_write(w, bit, vp10_get_pred_prob_comp_ref_p(cm, xd)); + +#if CONFIG_EXT_REFS + if (!bit) { + const int bit1 = mbmi->ref_frame[0] == LAST_FRAME; + vpx_write(w, bit1, vp10_get_pred_prob_comp_ref_p1(cm, xd)); + } else { + const int bit2 = mbmi->ref_frame[0] == GOLDEN_FRAME; + vpx_write(w, bit2, vp10_get_pred_prob_comp_ref_p2(cm, xd)); + if (!bit2) { + const int bit3 = mbmi->ref_frame[0] == LAST3_FRAME; + vpx_write(w, bit3, vp10_get_pred_prob_comp_ref_p3(cm, xd)); + } + } +#endif // CONFIG_EXT_REFS } else { +#if CONFIG_EXT_REFS + const int bit0 = (mbmi->ref_frame[0] == GOLDEN_FRAME || + mbmi->ref_frame[0] == ALTREF_FRAME); + vpx_write(w, bit0, vp10_get_pred_prob_single_ref_p1(cm, xd)); + + if (bit0) { + const int bit1 = mbmi->ref_frame[0] != GOLDEN_FRAME; + vpx_write(w, bit1, vp10_get_pred_prob_single_ref_p2(cm, xd)); + } else { + const int bit2 = (mbmi->ref_frame[0] == LAST3_FRAME || + mbmi->ref_frame[0] == LAST4_FRAME); + vpx_write(w, bit2, vp10_get_pred_prob_single_ref_p3(cm, xd)); + + if (!bit2) { + const int bit3 = mbmi->ref_frame[0] != LAST_FRAME; + vpx_write(w, bit3, vp10_get_pred_prob_single_ref_p4(cm, xd)); + } else { + const int bit4 = mbmi->ref_frame[0] != LAST3_FRAME; + vpx_write(w, bit4, vp10_get_pred_prob_single_ref_p5(cm, xd)); + } + } +#else const int bit0 = mbmi->ref_frame[0] != LAST_FRAME; vpx_write(w, bit0, vp10_get_pred_prob_single_ref_p1(cm, xd)); if (bit0) { const int bit1 = mbmi->ref_frame[0] != GOLDEN_FRAME; vpx_write(w, bit1, vp10_get_pred_prob_single_ref_p2(cm, xd)); } +#endif // CONFIG_EXT_REFS } } } @@ -1406,6 +1449,11 @@ static int get_refresh_mask(VP10_COMP *cpi) { // and this needs to be generalized as other uses are implemented // (like RTC/temporal scalability). return (cpi->refresh_last_frame << cpi->lst_fb_idx) | +#if CONFIG_EXT_REFS + (cpi->refresh_last2_frame << cpi->lst2_fb_idx) | + (cpi->refresh_last3_frame << cpi->lst3_fb_idx) | + (cpi->refresh_last4_frame << cpi->lst4_fb_idx) | +#endif // CONFIG_EXT_REFS (cpi->refresh_golden_frame << cpi->alt_fb_idx); } else { int arf_idx = cpi->alt_fb_idx; @@ -1414,6 +1462,11 @@ static int get_refresh_mask(VP10_COMP *cpi) { arf_idx = gf_group->arf_update_idx[gf_group->index]; } return (cpi->refresh_last_frame << cpi->lst_fb_idx) | +#if CONFIG_EXT_REFS + (cpi->refresh_last2_frame << cpi->lst2_fb_idx) | + (cpi->refresh_last3_frame << cpi->lst3_fb_idx) | + (cpi->refresh_last4_frame << cpi->lst4_fb_idx) | +#endif // CONFIG_EXT_REFS (cpi->refresh_golden_frame << cpi->gld_fb_idx) | (cpi->refresh_alt_ref_frame << arf_idx); } @@ -1584,6 +1637,13 @@ static void write_uncompressed_header(VP10_COMP *cpi, vpx_wb_write_bit(wb, cm->show_frame); vpx_wb_write_bit(wb, cm->error_resilient_mode); +#if CONFIG_EXT_REFS + cpi->refresh_last2_frame = + (cm->frame_type == KEY_FRAME || cpi->refresh_last_frame) ? 1 : 0; + cpi->refresh_last3_frame = cpi->refresh_last2_frame ? 1 : 0; + cpi->refresh_last4_frame = cpi->refresh_last3_frame ? 1 : 0; +#endif // CONFIG_EXT_REFS + if (cm->frame_type == KEY_FRAME) { write_sync_code(wb); write_bitdepth_colorspace_sampling(cm, wb); @@ -1715,17 +1775,21 @@ static size_t write_compressed_header(VP10_COMP *cpi, uint8_t *data) { if (cm->reference_mode != COMPOUND_REFERENCE) { for (i = 0; i < REF_CONTEXTS; i++) { - vp10_cond_prob_diff_update(&header_bc, &fc->single_ref_prob[i][0], - counts->single_ref[i][0]); - vp10_cond_prob_diff_update(&header_bc, &fc->single_ref_prob[i][1], - counts->single_ref[i][1]); + for (j = 0; j < (SINGLE_REFS - 1); j ++) { + vp10_cond_prob_diff_update(&header_bc, &fc->single_ref_prob[i][j], + counts->single_ref[i][j]); + } } } - if (cm->reference_mode != SINGLE_REFERENCE) - for (i = 0; i < REF_CONTEXTS; i++) - vp10_cond_prob_diff_update(&header_bc, &fc->comp_ref_prob[i], - counts->comp_ref[i]); + if (cm->reference_mode != SINGLE_REFERENCE) { + for (i = 0; i < REF_CONTEXTS; i++) { + for (j = 0; j < (COMP_REFS - 1); j ++) { + vp10_cond_prob_diff_update(&header_bc, &fc->comp_ref_prob[i][j], + counts->comp_ref[i][j]); + } + } + } for (i = 0; i < BLOCK_SIZE_GROUPS; ++i) prob_diff_update(vp10_intra_mode_tree, cm->fc->y_mode_prob[i], diff --git a/vp10/encoder/denoiser.c b/vp10/encoder/denoiser.c index e5d8157a4..c4955fe9f 100644 --- a/vp10/encoder/denoiser.c +++ b/vp10/encoder/denoiser.c @@ -398,6 +398,14 @@ void vp10_denoiser_update_frame_info(VP9_DENOISER *denoiser, &denoiser->running_avg_y[INTRA_FRAME]); } if (refresh_last_frame) { +#if CONFIG_EXT_REFS + swap_frame_buffer(&denoiser->running_avg_y[LAST4_FRAME], + &denoiser->running_avg_y[LAST3_FRAME]); + swap_frame_buffer(&denoiser->running_avg_y[LAST3_FRAME], + &denoiser->running_avg_y[LAST2_FRAME]); + swap_frame_buffer(&denoiser->running_avg_y[LAST2_FRAME], + &denoiser->running_avg_y[LAST_FRAME]); +#endif // CONFIG_EXT_REFS swap_frame_buffer(&denoiser->running_avg_y[LAST_FRAME], &denoiser->running_avg_y[INTRA_FRAME]); } diff --git a/vp10/encoder/encodeframe.c b/vp10/encoder/encodeframe.c index 127cd04fe..c57b224b7 100644 --- a/vp10/encoder/encodeframe.c +++ b/vp10/encoder/encodeframe.c @@ -1282,14 +1282,51 @@ static void update_stats(VP10_COMMON *cm, ThreadData *td) { [has_second_ref(mbmi)]++; if (has_second_ref(mbmi)) { - counts->comp_ref[vp10_get_pred_context_comp_ref_p(cm, xd)] +#if CONFIG_EXT_REFS + const int bit = (ref0 == GOLDEN_FRAME || ref0 == LAST3_FRAME || + ref0 == LAST4_FRAME); + counts->comp_ref[vp10_get_pred_context_comp_ref_p(cm, xd)][0][bit]++; + if (!bit) { + counts->comp_ref[vp10_get_pred_context_comp_ref_p1(cm, xd)][1] + [ref0 == LAST_FRAME]++; + } else { + counts->comp_ref[vp10_get_pred_context_comp_ref_p2(cm, xd)][2] + [ref0 == GOLDEN_FRAME]++; + if (ref0 != GOLDEN_FRAME) { + counts->comp_ref[vp10_get_pred_context_comp_ref_p3(cm, xd)][3] + [ref0 == LAST3_FRAME]++; + } + } +#else + counts->comp_ref[vp10_get_pred_context_comp_ref_p(cm, xd)][0] [ref0 == GOLDEN_FRAME]++; +#endif // CONFIG_EXT_REFS } else { +#if CONFIG_EXT_REFS + const int bit = (ref0 == ALTREF_FRAME || ref0 == GOLDEN_FRAME); + counts->single_ref[vp10_get_pred_context_single_ref_p1(xd)][0][bit]++; + if (bit) { + counts->single_ref[vp10_get_pred_context_single_ref_p2(xd)][1] + [ref0 != GOLDEN_FRAME]++; + } else { + const int bit1 = !(ref0 == LAST2_FRAME || ref0 == LAST_FRAME); + counts->single_ref[vp10_get_pred_context_single_ref_p3(xd)][2] + [bit1]++; + if (!bit1) { + counts->single_ref[vp10_get_pred_context_single_ref_p4(xd)][3] + [ref0 != LAST_FRAME]++; + } else { + counts->single_ref[vp10_get_pred_context_single_ref_p5(xd)][4] + [ref0 != LAST3_FRAME]++; + } + } +#else counts->single_ref[vp10_get_pred_context_single_ref_p1(xd)][0] [ref0 != LAST_FRAME]++; if (ref0 != LAST_FRAME) counts->single_ref[vp10_get_pred_context_single_ref_p2(xd)][1] [ref0 != GOLDEN_FRAME]++; +#endif // CONFIG_EXT_REFS } } } @@ -2670,8 +2707,14 @@ static int check_dual_ref_flags(VP10_COMP *cpi) { if (segfeature_active(&cpi->common.seg, 1, SEG_LVL_REF_FRAME)) { return 0; } else { - return (!!(ref_flags & VP9_GOLD_FLAG) + !!(ref_flags & VP9_LAST_FLAG) - + !!(ref_flags & VP9_ALT_FLAG)) >= 2; + return (!!(ref_flags & VP9_GOLD_FLAG) + + !!(ref_flags & VP9_LAST_FLAG) + +#if CONFIG_EXT_REFS + !!(ref_flags & VP9_LAST2_FLAG) + + !!(ref_flags & VP9_LAST3_FLAG) + + !!(ref_flags & VP9_LAST4_FLAG) + +#endif // CONFIG_EXT_REFS + !!(ref_flags & VP9_ALT_FLAG)) >= 2; } } @@ -2696,6 +2739,8 @@ static MV_REFERENCE_FRAME get_frame_type(const VP10_COMP *cpi) { else if (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame) return GOLDEN_FRAME; else + // TODO(zoeliu): TO investigate whether a frame_type other than + // INTRA/ALTREF/GOLDEN/LAST needs to be specified seperately. return LAST_FRAME; } @@ -2914,7 +2959,14 @@ void vp10_encode_frame(VP10_COMP *cpi) { cpi->allow_comp_inter_inter = 1; cm->comp_fixed_ref = ALTREF_FRAME; cm->comp_var_ref[0] = LAST_FRAME; +#if CONFIG_EXT_REFS + cm->comp_var_ref[1] = LAST2_FRAME; + cm->comp_var_ref[2] = LAST3_FRAME; + cm->comp_var_ref[3] = LAST4_FRAME; + cm->comp_var_ref[4] = GOLDEN_FRAME; +#else cm->comp_var_ref[1] = GOLDEN_FRAME; +#endif // CONFIG_EXT_REFS } } else { cpi->allow_comp_inter_inter = 0; @@ -2930,9 +2982,12 @@ void vp10_encode_frame(VP10_COMP *cpi) { // either compound, single or hybrid prediction as per whatever has // worked best for that type of frame in the past. // It also predicts whether another coding mode would have worked - // better that this coding mode. If that is the case, it remembers + // better than this coding mode. If that is the case, it remembers // that for subsequent frames. // It does the same analysis for transform size selection also. + // + // TODO(zoeliu): TO investigate whether a frame_type other than + // INTRA/ALTREF/GOLDEN/LAST needs to be specified seperately. const MV_REFERENCE_FRAME frame_type = get_frame_type(cpi); int64_t *const mode_thrs = rd_opt->prediction_type_threshes[frame_type]; int64_t *const filter_thrs = rd_opt->filter_threshes[frame_type]; diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c index c9911f84d..774683959 100644 --- a/vp10/encoder/encoder.c +++ b/vp10/encoder/encoder.c @@ -718,8 +718,16 @@ static void update_frame_size(VP10_COMP *cpi) { static void init_buffer_indices(VP10_COMP *cpi) { cpi->lst_fb_idx = 0; +#if CONFIG_EXT_REFS + cpi->lst2_fb_idx = 1; + cpi->lst3_fb_idx = 2; + cpi->lst4_fb_idx = 3; + cpi->gld_fb_idx = 4; + cpi->alt_fb_idx = 5; +#else cpi->gld_fb_idx = 1; cpi->alt_fb_idx = 2; +#endif // CONFIG_EXT_REFS } static void init_config(struct VP10_COMP *cpi, VP10EncoderConfig *oxcf) { @@ -1422,6 +1430,12 @@ void vp10_change_config(struct VP10_COMP *cpi, const VP10EncoderConfig *oxcf) { cpi->refresh_golden_frame = 0; cpi->refresh_last_frame = 1; +#if CONFIG_EXT_REFS + cpi->refresh_last2_frame = 0; + cpi->refresh_last3_frame = 0; + cpi->refresh_last4_frame = 0; +#endif // CONFIG_EXT_REFS + cm->refresh_frame_context = oxcf->error_resilient_mode ? REFRESH_FRAME_CONTEXT_OFF : oxcf->frame_parallel_decoding_mode ? REFRESH_FRAME_CONTEXT_FORWARD @@ -2279,7 +2293,7 @@ static void generate_psnr_packet(VP10_COMP *cpi) { } int vp10_use_as_reference(VP10_COMP *cpi, int ref_frame_flags) { - if (ref_frame_flags > 7) + if (ref_frame_flags > ((1 << REFS_PER_FRAME) - 1)) return -1; cpi->ref_frame_flags = ref_frame_flags; @@ -2290,6 +2304,11 @@ void vp10_update_reference(VP10_COMP *cpi, int ref_frame_flags) { cpi->ext_refresh_golden_frame = (ref_frame_flags & VP9_GOLD_FLAG) != 0; cpi->ext_refresh_alt_ref_frame = (ref_frame_flags & VP9_ALT_FLAG) != 0; cpi->ext_refresh_last_frame = (ref_frame_flags & VP9_LAST_FLAG) != 0; +#if CONFIG_EXT_REFS + cpi->ext_refresh_last2_frame = (ref_frame_flags & VP9_LAST2_FLAG) != 0; + cpi->ext_refresh_last3_frame = (ref_frame_flags & VP9_LAST3_FLAG) != 0; + cpi->ext_refresh_last4_frame = (ref_frame_flags & VP9_LAST4_FLAG) != 0; +#endif // CONFIG_EXT_REFS cpi->ext_refresh_frame_flags_pending = 1; } @@ -2298,6 +2317,14 @@ static YV12_BUFFER_CONFIG *get_vp10_ref_frame_buffer(VP10_COMP *cpi, MV_REFERENCE_FRAME ref_frame = NONE; if (ref_frame_flag == VP9_LAST_FLAG) ref_frame = LAST_FRAME; +#if CONFIG_EXT_REFS + else if (ref_frame_flag == VP9_LAST2_FLAG) + ref_frame = LAST2_FRAME; + else if (ref_frame_flag == VP9_LAST3_FLAG) + ref_frame = LAST3_FRAME; + else if (ref_frame_flag == VP9_LAST4_FLAG) + ref_frame = LAST4_FRAME; +#endif // CONFIG_EXT_REFS else if (ref_frame_flag == VP9_GOLD_FLAG) ref_frame = GOLDEN_FRAME; else if (ref_frame_flag == VP9_ALT_FLAG) @@ -2634,12 +2661,82 @@ void vp10_update_reference_frames(VP10_COMP *cpi) { } if (cpi->refresh_last_frame) { +#if CONFIG_EXT_REFS + if (cpi->refresh_last2_frame) { + if (cpi->refresh_last3_frame) { + if (cpi->refresh_last4_frame) { + if (cm->frame_type == KEY_FRAME) + ref_cnt_fb(pool->frame_bufs, + &cm->ref_frame_map[cpi->lst4_fb_idx], + cm->new_fb_idx); + else + ref_cnt_fb(pool->frame_bufs, + &cm->ref_frame_map[cpi->lst4_fb_idx], + cm->ref_frame_map[cpi->lst3_fb_idx]); + } + + if (cm->frame_type == KEY_FRAME) + ref_cnt_fb(pool->frame_bufs, + &cm->ref_frame_map[cpi->lst3_fb_idx], + cm->new_fb_idx); + else + ref_cnt_fb(pool->frame_bufs, + &cm->ref_frame_map[cpi->lst3_fb_idx], + cm->ref_frame_map[cpi->lst2_fb_idx]); + } + + if (cm->frame_type == KEY_FRAME) + ref_cnt_fb(pool->frame_bufs, + &cm->ref_frame_map[cpi->lst2_fb_idx], + cm->new_fb_idx); + else + ref_cnt_fb(pool->frame_bufs, + &cm->ref_frame_map[cpi->lst2_fb_idx], + cm->ref_frame_map[cpi->lst_fb_idx]); + } +#endif // CONFIG_EXT_REFS ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[cpi->lst_fb_idx], cm->new_fb_idx); - if (!cpi->rc.is_src_frame_alt_ref) + + if (!cpi->rc.is_src_frame_alt_ref) { +#if CONFIG_EXT_REFS + if (cpi->refresh_last2_frame) { + if (cpi->refresh_last3_frame) { + if (cpi->refresh_last4_frame) { + if (cm->frame_type == KEY_FRAME) + memcpy(cpi->interp_filter_selected[LAST4_FRAME], + cpi->interp_filter_selected[0], + sizeof(cpi->interp_filter_selected[0])); + else + memcpy(cpi->interp_filter_selected[LAST4_FRAME], + cpi->interp_filter_selected[LAST3_FRAME], + sizeof(cpi->interp_filter_selected[LAST3_FRAME])); + } + + if (cm->frame_type == KEY_FRAME) + memcpy(cpi->interp_filter_selected[LAST3_FRAME], + cpi->interp_filter_selected[0], + sizeof(cpi->interp_filter_selected[0])); + else + memcpy(cpi->interp_filter_selected[LAST3_FRAME], + cpi->interp_filter_selected[LAST2_FRAME], + sizeof(cpi->interp_filter_selected[LAST2_FRAME])); + } + + if (cm->frame_type == KEY_FRAME) + memcpy(cpi->interp_filter_selected[LAST2_FRAME], + cpi->interp_filter_selected[0], + sizeof(cpi->interp_filter_selected[0])); + else + memcpy(cpi->interp_filter_selected[LAST2_FRAME], + cpi->interp_filter_selected[LAST_FRAME], + sizeof(cpi->interp_filter_selected[LAST_FRAME])); + } +#endif // CONFIG_EXT_REFS memcpy(cpi->interp_filter_selected[LAST_FRAME], cpi->interp_filter_selected[0], sizeof(cpi->interp_filter_selected[0])); + } } #if CONFIG_VP9_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity > 0) { @@ -2706,7 +2803,16 @@ static INLINE void alloc_frame_mvs(const VP10_COMMON *cm, void vp10_scale_references(VP10_COMP *cpi) { VP10_COMMON *cm = &cpi->common; MV_REFERENCE_FRAME ref_frame; - const VP9_REFFRAME ref_mask[3] = {VP9_LAST_FLAG, VP9_GOLD_FLAG, VP9_ALT_FLAG}; + const VP9_REFFRAME ref_mask[REFS_PER_FRAME] = { + VP9_LAST_FLAG, +#if CONFIG_EXT_REFS + VP9_LAST2_FLAG, + VP9_LAST3_FLAG, + VP9_LAST4_FLAG, +#endif // CONFIG_EXT_REFS + VP9_GOLD_FLAG, + VP9_ALT_FLAG + }; for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { // Need to convert from VP9_REFFRAME to index into ref_mask (subtract 1). @@ -2791,10 +2897,18 @@ static void release_scaled_references(VP10_COMP *cpi) { if (cpi->oxcf.pass == 0) { // Only release scaled references under certain conditions: // if reference will be updated, or if scaled reference has same resolution. - int refresh[3]; + int refresh[REFS_PER_FRAME]; refresh[0] = (cpi->refresh_last_frame) ? 1 : 0; +#if CONFIG_EXT_REFS + refresh[1] = (cpi->refresh_last2_frame) ? 1 : 0; + refresh[2] = (cpi->refresh_last3_frame) ? 1 : 0; + refresh[3] = (cpi->refresh_last4_frame) ? 1 : 0; + refresh[4] = (cpi->refresh_golden_frame) ? 1 : 0; + refresh[5] = (cpi->refresh_alt_ref_frame) ? 1 : 0; +#else refresh[1] = (cpi->refresh_golden_frame) ? 1 : 0; refresh[2] = (cpi->refresh_alt_ref_frame) ? 1 : 0; +#endif // CONFIG_EXT_REFS for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) { const int idx = cpi->scaled_ref_idx[i - 1]; RefCntBuffer *const buf = idx != INVALID_IDX ? @@ -3428,7 +3542,30 @@ static int get_ref_frame_flags(const VP10_COMP *cpi) { const int gold_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx]; const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx]; const int gold_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx]; + +#if CONFIG_EXT_REFS + const int last2_is_last = map[cpi->lst2_fb_idx] == map[cpi->lst_fb_idx]; + const int gld_is_last2 = map[cpi->gld_fb_idx] == map[cpi->lst2_fb_idx]; + const int alt_is_last2 = map[cpi->alt_fb_idx] == map[cpi->lst2_fb_idx]; + + const int last3_is_last = map[cpi->lst3_fb_idx] == map[cpi->lst_fb_idx]; + const int last3_is_last2 = map[cpi->lst3_fb_idx] == map[cpi->lst2_fb_idx]; + const int gld_is_last3 = map[cpi->gld_fb_idx] == map[cpi->lst3_fb_idx]; + const int alt_is_last3 = map[cpi->alt_fb_idx] == map[cpi->lst3_fb_idx]; + + const int last4_is_last = map[cpi->lst4_fb_idx] == map[cpi->lst_fb_idx]; + const int last4_is_last2 = map[cpi->lst4_fb_idx] == map[cpi->lst2_fb_idx]; + const int last4_is_last3 = map[cpi->lst4_fb_idx] == map[cpi->lst3_fb_idx]; + const int gld_is_last4 = map[cpi->gld_fb_idx] == map[cpi->lst4_fb_idx]; + const int alt_is_last4 = map[cpi->alt_fb_idx] == map[cpi->lst4_fb_idx]; +#endif // CONFIG_EXT_REFS + int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG; +#if CONFIG_EXT_REFS + flags |= VP9_LAST2_FLAG; + flags |= VP9_LAST3_FLAG; + flags |= VP9_LAST4_FLAG; +#endif // CONFIG_EXT_REFS if (gold_is_last) flags &= ~VP9_GOLD_FLAG; @@ -3442,6 +3579,35 @@ static int get_ref_frame_flags(const VP10_COMP *cpi) { if (gold_is_alt) flags &= ~VP9_ALT_FLAG; +#if CONFIG_EXT_REFS + if (last4_is_last || last4_is_last2 || last4_is_last3) + flags &= ~VP9_LAST4_FLAG; + + if (gld_is_last4) + flags &= ~VP9_GOLD_FLAG; + + if (alt_is_last4) + flags &= ~VP9_ALT_FLAG; + + if (last3_is_last || last3_is_last2) + flags &= ~VP9_LAST3_FLAG; + + if (gld_is_last3) + flags &= ~VP9_GOLD_FLAG; + + if (alt_is_last3) + flags &= ~VP9_ALT_FLAG; + + if (last2_is_last) + flags &= ~VP9_LAST2_FLAG; + + if (gld_is_last2) + flags &= ~VP9_GOLD_FLAG; + + if (alt_is_last2) + flags &= ~VP9_ALT_FLAG; +#endif // CONFIG_EXT_REFS + return flags; } @@ -3456,6 +3622,11 @@ static void set_ext_overrides(VP10_COMP *cpi) { } if (cpi->ext_refresh_frame_flags_pending) { cpi->refresh_last_frame = cpi->ext_refresh_last_frame; +#if CONFIG_EXT_REFS + cpi->refresh_last2_frame = cpi->ext_refresh_last2_frame; + cpi->refresh_last3_frame = cpi->ext_refresh_last3_frame; + cpi->refresh_last4_frame = cpi->ext_refresh_last4_frame; +#endif // CONFIG_EXT_REFS cpi->refresh_golden_frame = cpi->ext_refresh_golden_frame; cpi->refresh_alt_ref_frame = cpi->ext_refresh_alt_ref_frame; cpi->ext_refresh_frame_flags_pending = 0; @@ -3524,6 +3695,17 @@ static int setup_interp_filter_search_mask(VP10_COMP *cpi) { for (ifilter = EIGHTTAP; ifilter <= EIGHTTAP_SHARP; ++ifilter) { if ((ref_total[LAST_FRAME] && cpi->interp_filter_selected[LAST_FRAME][ifilter] == 0) && +#if CONFIG_EXT_REFS + (ref_total[LAST2_FRAME] == 0 || + cpi->interp_filter_selected[LAST2_FRAME][ifilter] * 50 + < ref_total[LAST2_FRAME]) && + (ref_total[LAST3_FRAME] == 0 || + cpi->interp_filter_selected[LAST3_FRAME][ifilter] * 50 + < ref_total[LAST3_FRAME]) && + (ref_total[LAST4_FRAME] == 0 || + cpi->interp_filter_selected[LAST4_FRAME][ifilter] * 50 + < ref_total[LAST4_FRAME]) && +#endif // CONFIG_EXT_REFS (ref_total[GOLDEN_FRAME] == 0 || cpi->interp_filter_selected[GOLDEN_FRAME][ifilter] * 50 < ref_total[GOLDEN_FRAME]) && @@ -3691,6 +3873,10 @@ static void encode_frame_to_data_rate(VP10_COMP *cpi, cpi->ref_frame_flags = get_ref_frame_flags(cpi); +#if CONFIG_EXT_REFS + cm->last3_frame_type = cm->last2_frame_type; + cm->last2_frame_type = cm->last_frame_type; +#endif // CONFIG_EXT_REFS cm->last_frame_type = cm->frame_type; vp10_rc_postencode_update(cpi, *size); @@ -3854,6 +4040,11 @@ static int frame_is_reference(const VP10_COMP *cpi) { return cm->frame_type == KEY_FRAME || cpi->refresh_last_frame || +#if CONFIG_EXT_REFS + cpi->refresh_last2_frame || + cpi->refresh_last3_frame || + cpi->refresh_last4_frame || +#endif // CONFIG_EXT_REFS cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame || cm->refresh_frame_context != REFRESH_FRAME_CONTEXT_OFF || @@ -3990,6 +4181,11 @@ int vp10_get_compressed_data(VP10_COMP *cpi, unsigned int *frame_flags, : REFRESH_FRAME_CONTEXT_BACKWARD; cpi->refresh_last_frame = 1; +#if CONFIG_EXT_REFS + cpi->refresh_last2_frame = 0; + cpi->refresh_last3_frame = 0; + cpi->refresh_last4_frame = 0; +#endif // CONFIG_EXT_REFS cpi->refresh_golden_frame = 0; cpi->refresh_alt_ref_frame = 0; @@ -4014,6 +4210,11 @@ int vp10_get_compressed_data(VP10_COMP *cpi, unsigned int *frame_flags, cpi->refresh_alt_ref_frame = 1; cpi->refresh_golden_frame = 0; cpi->refresh_last_frame = 0; +#if CONFIG_EXT_REFS + cpi->refresh_last2_frame = 0; + cpi->refresh_last3_frame = 0; + cpi->refresh_last4_frame = 0; +#endif // CONFIG_EXT_REFS rc->is_src_frame_alt_ref = 0; rc->source_alt_ref_pending = 0; } else { diff --git a/vp10/encoder/encoder.h b/vp10/encoder/encoder.h index e20b56998..7b380005f 100644 --- a/vp10/encoder/encoder.h +++ b/vp10/encoder/encoder.h @@ -304,15 +304,30 @@ typedef struct VP10_COMP { int scaled_ref_idx[MAX_REF_FRAMES]; int lst_fb_idx; +#if CONFIG_EXT_REFS + int lst2_fb_idx; + int lst3_fb_idx; + int lst4_fb_idx; +#endif // CONFIG_EXT_REFS int gld_fb_idx; int alt_fb_idx; int refresh_last_frame; +#if CONFIG_EXT_REFS + int refresh_last2_frame; + int refresh_last3_frame; + int refresh_last4_frame; +#endif // CONFIG_EXT_REFS int refresh_golden_frame; int refresh_alt_ref_frame; int ext_refresh_frame_flags_pending; int ext_refresh_last_frame; +#if CONFIG_EXT_REFS + int ext_refresh_last2_frame; + int ext_refresh_last3_frame; + int ext_refresh_last4_frame; +#endif // CONFIG_EXT_REFS int ext_refresh_golden_frame; int ext_refresh_alt_ref_frame; @@ -554,6 +569,14 @@ static INLINE int get_ref_frame_map_idx(const VP10_COMP *cpi, MV_REFERENCE_FRAME ref_frame) { if (ref_frame == LAST_FRAME) { return cpi->lst_fb_idx; +#if CONFIG_EXT_REFS + } else if (ref_frame == LAST2_FRAME) { + return cpi->lst2_fb_idx; + } else if (ref_frame == LAST3_FRAME) { + return cpi->lst3_fb_idx; + } else if (ref_frame == LAST4_FRAME) { + return cpi->lst4_fb_idx; +#endif // CONFIG_EXT_REFS } else if (ref_frame == GOLDEN_FRAME) { return cpi->gld_fb_idx; } else { diff --git a/vp10/encoder/rd.c b/vp10/encoder/rd.c index cb322524a..823e6b8a2 100644 --- a/vp10/encoder/rd.c +++ b/vp10/encoder/rd.c @@ -608,10 +608,20 @@ void vp10_set_rd_speed_thresholds(VP10_COMP *cpi) { if (sf->adaptive_rd_thresh) { rd->thresh_mult[THR_NEARESTMV] = 300; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_NEARESTL2] = 300; + rd->thresh_mult[THR_NEARESTL3] = 300; + rd->thresh_mult[THR_NEARESTL4] = 300; +#endif // CONFIG_EXT_REFS rd->thresh_mult[THR_NEARESTG] = 300; rd->thresh_mult[THR_NEARESTA] = 300; } else { rd->thresh_mult[THR_NEARESTMV] = 0; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_NEARESTL2] = 0; + rd->thresh_mult[THR_NEARESTL3] = 0; + rd->thresh_mult[THR_NEARESTL4] = 0; +#endif // CONFIG_EXT_REFS rd->thresh_mult[THR_NEARESTG] = 0; rd->thresh_mult[THR_NEARESTA] = 0; } @@ -619,26 +629,61 @@ void vp10_set_rd_speed_thresholds(VP10_COMP *cpi) { rd->thresh_mult[THR_DC] += 1000; rd->thresh_mult[THR_NEWMV] += 1000; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_NEWL2] += 1000; + rd->thresh_mult[THR_NEWL3] += 1000; + rd->thresh_mult[THR_NEWL4] += 1000; +#endif // CONFIG_EXT_REFS rd->thresh_mult[THR_NEWA] += 1000; rd->thresh_mult[THR_NEWG] += 1000; rd->thresh_mult[THR_NEARMV] += 1000; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_NEARL2] += 1000; + rd->thresh_mult[THR_NEARL3] += 1000; + rd->thresh_mult[THR_NEARL4] += 1000; +#endif // CONFIG_EXT_REFS rd->thresh_mult[THR_NEARA] += 1000; - rd->thresh_mult[THR_COMP_NEARESTLA] += 1000; - rd->thresh_mult[THR_COMP_NEARESTGA] += 1000; + rd->thresh_mult[THR_NEARG] += 1000; + + rd->thresh_mult[THR_ZEROMV] += 2000; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_ZEROL2] += 2000; + rd->thresh_mult[THR_ZEROL3] += 2000; + rd->thresh_mult[THR_ZEROL4] += 2000; +#endif // CONFIG_EXT_REFS + rd->thresh_mult[THR_ZEROG] += 2000; + rd->thresh_mult[THR_ZEROA] += 2000; rd->thresh_mult[THR_TM] += 1000; + rd->thresh_mult[THR_COMP_NEARESTLA] += 1000; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_COMP_NEARESTL2A] += 1000; + rd->thresh_mult[THR_COMP_NEARESTL3A] += 1000; + rd->thresh_mult[THR_COMP_NEARESTL4A] += 1000; +#endif // CONFIG_EXT_REFS + rd->thresh_mult[THR_COMP_NEARESTGA] += 1000; + rd->thresh_mult[THR_COMP_NEARLA] += 1500; rd->thresh_mult[THR_COMP_NEWLA] += 2000; - rd->thresh_mult[THR_NEARG] += 1000; rd->thresh_mult[THR_COMP_NEARGA] += 1500; rd->thresh_mult[THR_COMP_NEWGA] += 2000; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_COMP_NEARL2A] += 1500; + rd->thresh_mult[THR_COMP_NEWL2A] += 2000; + rd->thresh_mult[THR_COMP_NEARL3A] += 1500; + rd->thresh_mult[THR_COMP_NEWL3A] += 2000; + rd->thresh_mult[THR_COMP_NEARL4A] += 1500; + rd->thresh_mult[THR_COMP_NEWL4A] += 2000; +#endif // CONFIG_EXT_REFS - rd->thresh_mult[THR_ZEROMV] += 2000; - rd->thresh_mult[THR_ZEROG] += 2000; - rd->thresh_mult[THR_ZEROA] += 2000; rd->thresh_mult[THR_COMP_ZEROLA] += 2500; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_COMP_ZEROL2A] += 2500; + rd->thresh_mult[THR_COMP_ZEROL3A] += 2500; + rd->thresh_mult[THR_COMP_ZEROL4A] += 2500; +#endif // CONFIG_EXT_REFS rd->thresh_mult[THR_COMP_ZEROGA] += 2500; rd->thresh_mult[THR_H_PRED] += 2000; @@ -652,9 +697,15 @@ void vp10_set_rd_speed_thresholds(VP10_COMP *cpi) { } void vp10_set_rd_speed_thresholds_sub8x8(VP10_COMP *cpi) { - static const int thresh_mult[2][MAX_REFS] = - {{2500, 2500, 2500, 4500, 4500, 2500}, - {2000, 2000, 2000, 4000, 4000, 2000}}; + static const int thresh_mult[2][MAX_REFS] = { +#if CONFIG_EXT_REFS + {2500, 2500, 2500, 2500, 2500, 2500, 4500, 4500, 4500, 4500, 4500, 2500}, + {2000, 2000, 2000, 2000, 2000, 2000, 4000, 4000, 4000, 4000, 4000, 2000} +#else + {2500, 2500, 2500, 4500, 4500, 2500}, + {2000, 2000, 2000, 4000, 4000, 2000} +#endif // CONFIG_EXT_REFS + }; RD_OPT *const rd = &cpi->rd; const int idx = cpi->oxcf.mode == BEST; memcpy(rd->thresh_mult_sub8x8, thresh_mult[idx], sizeof(thresh_mult[idx])); diff --git a/vp10/encoder/rd.h b/vp10/encoder/rd.h index cd58bf84f..42261ac10 100644 --- a/vp10/encoder/rd.h +++ b/vp10/encoder/rd.h @@ -33,8 +33,17 @@ extern "C" { #define INVALID_MV 0x80008000 +#if CONFIG_EXT_REFS +#define MAX_MODES 54 +#else #define MAX_MODES 30 +#endif // CONFIG_EXT_REFS + +#if CONFIG_EXT_REFS +#define MAX_REFS 12 +#else #define MAX_REFS 6 +#endif // CONFIG_EXT_REFS #define RD_THRESH_MAX_FACT 64 #define RD_THRESH_INC 1 @@ -43,34 +52,72 @@ extern "C" { // const MODE_DEFINITION vp10_mode_order[MAX_MODES] used in the rd code. typedef enum { THR_NEARESTMV, +#if CONFIG_EXT_REFS + THR_NEARESTL2, + THR_NEARESTL3, + THR_NEARESTL4, +#endif // CONFIG_EXT_REFS THR_NEARESTA, THR_NEARESTG, THR_DC, THR_NEWMV, +#if CONFIG_EXT_REFS + THR_NEWL2, + THR_NEWL3, + THR_NEWL4, +#endif // CONFIG_EXT_REFS THR_NEWA, THR_NEWG, THR_NEARMV, +#if CONFIG_EXT_REFS + THR_NEARL2, + THR_NEARL3, + THR_NEARL4, +#endif // CONFIG_EXT_REFS THR_NEARA, THR_NEARG, THR_ZEROMV, +#if CONFIG_EXT_REFS + THR_ZEROL2, + THR_ZEROL3, + THR_ZEROL4, +#endif // CONFIG_EXT_REFS THR_ZEROG, THR_ZEROA, THR_COMP_NEARESTLA, +#if CONFIG_EXT_REFS + THR_COMP_NEARESTL2A, + THR_COMP_NEARESTL3A, + THR_COMP_NEARESTL4A, +#endif // CONFIG_EXT_REFS THR_COMP_NEARESTGA, THR_TM, THR_COMP_NEARLA, THR_COMP_NEWLA, +#if CONFIG_EXT_REFS + THR_COMP_NEARL2A, + THR_COMP_NEWL2A, + THR_COMP_NEARL3A, + THR_COMP_NEWL3A, + THR_COMP_NEARL4A, + THR_COMP_NEWL4A, +#endif // CONFIG_EXT_REFS THR_COMP_NEARGA, THR_COMP_NEWGA, THR_COMP_ZEROLA, +#if CONFIG_EXT_REFS + THR_COMP_ZEROL2A, + THR_COMP_ZEROL3A, + THR_COMP_ZEROL4A, +#endif // CONFIG_EXT_REFS THR_COMP_ZEROGA, THR_H_PRED, @@ -85,9 +132,19 @@ typedef enum { typedef enum { THR_LAST, +#if CONFIG_EXT_REFS + THR_LAST2, + THR_LAST3, + THR_LAST4, +#endif // CONFIG_EXT_REFS THR_GOLD, THR_ALTR, THR_COMP_LA, +#if CONFIG_EXT_REFS + THR_COMP_L2A, + THR_COMP_L3A, + THR_COMP_L4A, +#endif // CONFIG_EXT_REFS THR_COMP_GA, THR_INTRA, } THR_MODES_SUB8X8; diff --git a/vp10/encoder/rdopt.c b/vp10/encoder/rdopt.c index 7562b600b..ba7468e3e 100644 --- a/vp10/encoder/rdopt.c +++ b/vp10/encoder/rdopt.c @@ -43,6 +43,29 @@ #include "vp10/encoder/rdopt.h" #include "vp10/encoder/aq_variance.h" +#if CONFIG_EXT_REFS + +#define LAST_FRAME_MODE_MASK ((1 << GOLDEN_FRAME) | (1 << ALTREF_FRAME) | \ + (1 << LAST2_FRAME) | (1 << INTRA_FRAME) | \ + (1 << LAST3_FRAME) | (1 << LAST4_FRAME)) +#define LAST2_FRAME_MODE_MASK ((1 << GOLDEN_FRAME) | (1 << ALTREF_FRAME) | \ + (1 << LAST_FRAME) | (1 << INTRA_FRAME) | \ + (1 << LAST3_FRAME) | (1 << LAST4_FRAME)) +#define LAST3_FRAME_MODE_MASK ((1 << GOLDEN_FRAME) | (1 << ALTREF_FRAME) | \ + (1 << LAST_FRAME) | (1 << INTRA_FRAME) | \ + (1 << LAST2_FRAME) | (1 << LAST4_FRAME)) +#define LAST4_FRAME_MODE_MASK ((1 << GOLDEN_FRAME) | (1 << ALTREF_FRAME) | \ + (1 << LAST_FRAME) | (1 << INTRA_FRAME) | \ + (1 << LAST2_FRAME) | (1 << LAST3_FRAME)) +#define GOLDEN_FRAME_MODE_MASK ((1 << LAST_FRAME) | (1 << ALTREF_FRAME) | \ + (1 << LAST2_FRAME) | (1 << INTRA_FRAME) | \ + (1 << LAST3_FRAME) | (1 << LAST4_FRAME)) +#define ALT_REF_MODE_MASK ((1 << LAST_FRAME) | (1 << GOLDEN_FRAME) | \ + (1 << LAST2_FRAME) | (1 << INTRA_FRAME) | \ + (1 << LAST3_FRAME) | (1 << LAST4_FRAME)) + +#else + #define LAST_FRAME_MODE_MASK ((1 << GOLDEN_FRAME) | (1 << ALTREF_FRAME) | \ (1 << INTRA_FRAME)) #define GOLDEN_FRAME_MODE_MASK ((1 << LAST_FRAME) | (1 << ALTREF_FRAME) | \ @@ -50,6 +73,8 @@ #define ALT_REF_MODE_MASK ((1 << LAST_FRAME) | (1 << GOLDEN_FRAME) | \ (1 << INTRA_FRAME)) +#endif // CONFIG_EXT_REFS + #define SECOND_REF_FRAME_MASK ((1 << ALTREF_FRAME) | 0x01) #define MIN_EARLY_TERM_INDEX 3 @@ -89,34 +114,72 @@ struct rdcost_block_args { #define LAST_NEW_MV_INDEX 6 static const MODE_DEFINITION vp10_mode_order[MAX_MODES] = { {NEARESTMV, {LAST_FRAME, NONE}}, +#if CONFIG_EXT_REFS + {NEARESTMV, {LAST2_FRAME, NONE}}, + {NEARESTMV, {LAST3_FRAME, NONE}}, + {NEARESTMV, {LAST4_FRAME, NONE}}, +#endif // CONFIG_EXT_REFS {NEARESTMV, {ALTREF_FRAME, NONE}}, {NEARESTMV, {GOLDEN_FRAME, NONE}}, {DC_PRED, {INTRA_FRAME, NONE}}, {NEWMV, {LAST_FRAME, NONE}}, +#if CONFIG_EXT_REFS + {NEWMV, {LAST2_FRAME, NONE}}, + {NEWMV, {LAST3_FRAME, NONE}}, + {NEWMV, {LAST4_FRAME, NONE}}, +#endif // CONFIG_EXT_REFS {NEWMV, {ALTREF_FRAME, NONE}}, {NEWMV, {GOLDEN_FRAME, NONE}}, {NEARMV, {LAST_FRAME, NONE}}, +#if CONFIG_EXT_REFS + {NEARMV, {LAST2_FRAME, NONE}}, + {NEARMV, {LAST3_FRAME, NONE}}, + {NEARMV, {LAST4_FRAME, NONE}}, +#endif // CONFIG_EXT_REFS {NEARMV, {ALTREF_FRAME, NONE}}, {NEARMV, {GOLDEN_FRAME, NONE}}, {ZEROMV, {LAST_FRAME, NONE}}, +#if CONFIG_EXT_REFS + {ZEROMV, {LAST2_FRAME, NONE}}, + {ZEROMV, {LAST3_FRAME, NONE}}, + {ZEROMV, {LAST4_FRAME, NONE}}, +#endif // CONFIG_EXT_REFS {ZEROMV, {GOLDEN_FRAME, NONE}}, {ZEROMV, {ALTREF_FRAME, NONE}}, {NEARESTMV, {LAST_FRAME, ALTREF_FRAME}}, +#if CONFIG_EXT_REFS + {NEARESTMV, {LAST2_FRAME, ALTREF_FRAME}}, + {NEARESTMV, {LAST3_FRAME, ALTREF_FRAME}}, + {NEARESTMV, {LAST4_FRAME, ALTREF_FRAME}}, +#endif // CONFIG_EXT_REFS {NEARESTMV, {GOLDEN_FRAME, ALTREF_FRAME}}, {TM_PRED, {INTRA_FRAME, NONE}}, {NEARMV, {LAST_FRAME, ALTREF_FRAME}}, {NEWMV, {LAST_FRAME, ALTREF_FRAME}}, +#if CONFIG_EXT_REFS + {NEARMV, {LAST2_FRAME, ALTREF_FRAME}}, + {NEWMV, {LAST2_FRAME, ALTREF_FRAME}}, + {NEARMV, {LAST3_FRAME, ALTREF_FRAME}}, + {NEWMV, {LAST3_FRAME, ALTREF_FRAME}}, + {NEARMV, {LAST4_FRAME, ALTREF_FRAME}}, + {NEWMV, {LAST4_FRAME, ALTREF_FRAME}}, +#endif // CONFIG_EXT_REFS {NEARMV, {GOLDEN_FRAME, ALTREF_FRAME}}, {NEWMV, {GOLDEN_FRAME, ALTREF_FRAME}}, {ZEROMV, {LAST_FRAME, ALTREF_FRAME}}, +#if CONFIG_EXT_REFS + {ZEROMV, {LAST3_FRAME, ALTREF_FRAME}}, + {ZEROMV, {LAST2_FRAME, ALTREF_FRAME}}, + {ZEROMV, {LAST4_FRAME, ALTREF_FRAME}}, +#endif // CONFIG_EXT_REFS {ZEROMV, {GOLDEN_FRAME, ALTREF_FRAME}}, {H_PRED, {INTRA_FRAME, NONE}}, @@ -131,9 +194,19 @@ static const MODE_DEFINITION vp10_mode_order[MAX_MODES] = { static const REF_DEFINITION vp10_ref_order[MAX_REFS] = { {{LAST_FRAME, NONE}}, +#if CONFIG_EXT_REFS + {{LAST2_FRAME, NONE}}, + {{LAST3_FRAME, NONE}}, + {{LAST4_FRAME, NONE}}, +#endif // CONFIG_EXT_REFS {{GOLDEN_FRAME, NONE}}, {{ALTREF_FRAME, NONE}}, {{LAST_FRAME, ALTREF_FRAME}}, +#if CONFIG_EXT_REFS + {{LAST2_FRAME, ALTREF_FRAME}}, + {{LAST3_FRAME, ALTREF_FRAME}}, + {{LAST4_FRAME, ALTREF_FRAME}}, +#endif // CONFIG_EXT_REFS {{GOLDEN_FRAME, ALTREF_FRAME}}, {{INTRA_FRAME, NONE}}, }; @@ -3677,34 +3750,108 @@ static void estimate_ref_frame_costs(const VP10_COMMON *cm, if (cm->reference_mode != COMPOUND_REFERENCE) { vpx_prob ref_single_p1 = vp10_get_pred_prob_single_ref_p1(cm, xd); vpx_prob ref_single_p2 = vp10_get_pred_prob_single_ref_p2(cm, xd); +#if CONFIG_EXT_REFS + vpx_prob ref_single_p3 = vp10_get_pred_prob_single_ref_p3(cm, xd); + vpx_prob ref_single_p4 = vp10_get_pred_prob_single_ref_p4(cm, xd); + vpx_prob ref_single_p5 = vp10_get_pred_prob_single_ref_p5(cm, xd); +#endif // CONFIG_EXT_REFS unsigned int base_cost = vp10_cost_bit(intra_inter_p, 1); if (cm->reference_mode == REFERENCE_MODE_SELECT) base_cost += vp10_cost_bit(comp_inter_p, 0); - ref_costs_single[LAST_FRAME] = ref_costs_single[GOLDEN_FRAME] = + ref_costs_single[LAST_FRAME] = +#if CONFIG_EXT_REFS + ref_costs_single[LAST2_FRAME] = + ref_costs_single[LAST3_FRAME] = + ref_costs_single[LAST4_FRAME] = +#endif // CONFIG_EXT_REFS + ref_costs_single[GOLDEN_FRAME] = ref_costs_single[ALTREF_FRAME] = base_cost; + +#if CONFIG_EXT_REFS ref_costs_single[LAST_FRAME] += vp10_cost_bit(ref_single_p1, 0); + ref_costs_single[LAST2_FRAME] += vp10_cost_bit(ref_single_p1, 0); + ref_costs_single[LAST3_FRAME] += vp10_cost_bit(ref_single_p1, 0); + ref_costs_single[LAST4_FRAME] += vp10_cost_bit(ref_single_p1, 0); ref_costs_single[GOLDEN_FRAME] += vp10_cost_bit(ref_single_p1, 1); ref_costs_single[ALTREF_FRAME] += vp10_cost_bit(ref_single_p1, 1); + + ref_costs_single[LAST_FRAME] += vp10_cost_bit(ref_single_p3, 0); + ref_costs_single[LAST2_FRAME] += vp10_cost_bit(ref_single_p3, 0); + ref_costs_single[LAST3_FRAME] += vp10_cost_bit(ref_single_p3, 1); + ref_costs_single[LAST4_FRAME] += vp10_cost_bit(ref_single_p3, 1); ref_costs_single[GOLDEN_FRAME] += vp10_cost_bit(ref_single_p2, 0); ref_costs_single[ALTREF_FRAME] += vp10_cost_bit(ref_single_p2, 1); + + ref_costs_single[LAST_FRAME] += vp10_cost_bit(ref_single_p4, 0); + ref_costs_single[LAST2_FRAME] += vp10_cost_bit(ref_single_p4, 1); + ref_costs_single[LAST3_FRAME] += vp10_cost_bit(ref_single_p5, 0); + ref_costs_single[LAST4_FRAME] += vp10_cost_bit(ref_single_p5, 1); +#else + ref_costs_single[LAST_FRAME] += vp10_cost_bit(ref_single_p1, 0); + ref_costs_single[GOLDEN_FRAME] += vp10_cost_bit(ref_single_p1, 1); + ref_costs_single[ALTREF_FRAME] += vp10_cost_bit(ref_single_p1, 1); + ref_costs_single[GOLDEN_FRAME] += vp10_cost_bit(ref_single_p2, 0); + ref_costs_single[ALTREF_FRAME] += vp10_cost_bit(ref_single_p2, 1); +#endif // CONFIG_EXT_REFS } else { ref_costs_single[LAST_FRAME] = 512; +#if CONFIG_EXT_REFS + ref_costs_single[LAST2_FRAME] = 512; + ref_costs_single[LAST3_FRAME] = 512; + ref_costs_single[LAST4_FRAME] = 512; +#endif // CONFIG_EXT_REFS ref_costs_single[GOLDEN_FRAME] = 512; ref_costs_single[ALTREF_FRAME] = 512; } + if (cm->reference_mode != SINGLE_REFERENCE) { vpx_prob ref_comp_p = vp10_get_pred_prob_comp_ref_p(cm, xd); +#if CONFIG_EXT_REFS + vpx_prob ref_comp_p1 = vp10_get_pred_prob_comp_ref_p1(cm, xd); + vpx_prob ref_comp_p2 = vp10_get_pred_prob_comp_ref_p2(cm, xd); + vpx_prob ref_comp_p3 = vp10_get_pred_prob_comp_ref_p3(cm, xd); +#endif // CONFIG_EXT_REFS unsigned int base_cost = vp10_cost_bit(intra_inter_p, 1); if (cm->reference_mode == REFERENCE_MODE_SELECT) base_cost += vp10_cost_bit(comp_inter_p, 1); - ref_costs_comp[LAST_FRAME] = base_cost + vp10_cost_bit(ref_comp_p, 0); - ref_costs_comp[GOLDEN_FRAME] = base_cost + vp10_cost_bit(ref_comp_p, 1); + ref_costs_comp[LAST_FRAME] = +#if CONFIG_EXT_REFS + ref_costs_comp[LAST2_FRAME] = + ref_costs_comp[LAST3_FRAME] = + ref_costs_comp[LAST4_FRAME] = +#endif // CONFIG_EXT_REFS + ref_costs_comp[GOLDEN_FRAME] = base_cost; + +#if CONFIG_EXT_REFS + ref_costs_comp[LAST_FRAME] += vp10_cost_bit(ref_comp_p, 0); + ref_costs_comp[LAST2_FRAME] += vp10_cost_bit(ref_comp_p, 0); + ref_costs_comp[LAST3_FRAME] += vp10_cost_bit(ref_comp_p, 1); + ref_costs_comp[LAST4_FRAME] += vp10_cost_bit(ref_comp_p, 1); + ref_costs_comp[GOLDEN_FRAME] += vp10_cost_bit(ref_comp_p, 1); + + ref_costs_comp[LAST_FRAME] += vp10_cost_bit(ref_comp_p1, 1); + ref_costs_comp[LAST2_FRAME] += vp10_cost_bit(ref_comp_p1, 0); + ref_costs_comp[LAST3_FRAME] += vp10_cost_bit(ref_comp_p2, 0); + ref_costs_comp[LAST4_FRAME] += vp10_cost_bit(ref_comp_p2, 0); + ref_costs_comp[GOLDEN_FRAME] += vp10_cost_bit(ref_comp_p2, 1); + + ref_costs_comp[LAST3_FRAME] += vp10_cost_bit(ref_comp_p3, 1); + ref_costs_comp[LAST4_FRAME] += vp10_cost_bit(ref_comp_p3, 0); +#else + ref_costs_comp[LAST_FRAME] += vp10_cost_bit(ref_comp_p, 0); + ref_costs_comp[GOLDEN_FRAME] += vp10_cost_bit(ref_comp_p, 1); +#endif // CONFIG_EXT_REFS } else { ref_costs_comp[LAST_FRAME] = 512; +#if CONFIG_EXT_REFS + ref_costs_comp[LAST2_FRAME] = 512; + ref_costs_comp[LAST3_FRAME] = 512; + ref_costs_comp[LAST4_FRAME] = 512; +#endif // CONFIG_EXT_REFS ref_costs_comp[GOLDEN_FRAME] = 512; } } @@ -3732,13 +3879,14 @@ static void store_coding_context(MACROBLOCK *x, PICK_MODE_CONTEXT *ctx, sizeof(*best_filter_diff) * SWITCHABLE_FILTER_CONTEXTS); } -static void setup_buffer_inter(VP10_COMP *cpi, MACROBLOCK *x, - MV_REFERENCE_FRAME ref_frame, - BLOCK_SIZE block_size, - int mi_row, int mi_col, - int_mv frame_nearest_mv[MAX_REF_FRAMES], - int_mv frame_near_mv[MAX_REF_FRAMES], - struct buf_2d yv12_mb[4][MAX_MB_PLANE]) { +static void setup_buffer_inter( + VP10_COMP *cpi, MACROBLOCK *x, + MV_REFERENCE_FRAME ref_frame, + BLOCK_SIZE block_size, + int mi_row, int mi_col, + int_mv frame_nearest_mv[MAX_REF_FRAMES], + int_mv frame_near_mv[MAX_REF_FRAMES], + struct buf_2d yv12_mb[MAX_REF_FRAMES][MAX_MB_PLANE]) { const VP10_COMMON *cm = &cpi->common; const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame); MACROBLOCKD *const xd = &x->e_mbd; @@ -4551,12 +4699,21 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi, unsigned char segment_id = mbmi->segment_id; int comp_pred, i, k; int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES]; - struct buf_2d yv12_mb[4][MAX_MB_PLANE]; + struct buf_2d yv12_mb[MAX_REF_FRAMES][MAX_MB_PLANE]; int_mv single_newmv[MAX_REF_FRAMES] = { { 0 } }; INTERP_FILTER single_inter_filter[MB_MODE_COUNT][MAX_REF_FRAMES]; int single_skippable[MB_MODE_COUNT][MAX_REF_FRAMES]; - static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG, - VP9_ALT_FLAG }; + static const int flag_list[REFS_PER_FRAME + 1] = { + 0, + VP9_LAST_FLAG, +#if CONFIG_EXT_REFS + VP9_LAST2_FLAG, + VP9_LAST3_FLAG, + VP9_LAST4_FLAG, +#endif // CONFIG_EXT_REFS + VP9_GOLD_FLAG, + VP9_ALT_FLAG + }; int64_t best_rd = best_rd_so_far; int64_t best_pred_diff[REFERENCE_MODES]; int64_t best_pred_rd[REFERENCE_MODES]; @@ -4664,7 +4821,14 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi, // an unfiltered alternative. We allow near/nearest as well // because they may result in zero-zero MVs but be cheaper. if (cpi->rc.is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) { - ref_frame_skip_mask[0] = (1 << LAST_FRAME) | (1 << GOLDEN_FRAME); + ref_frame_skip_mask[0] = + (1 << LAST_FRAME) | +#if CONFIG_EXT_REFS + (1 << LAST2_FRAME) | + (1 << LAST3_FRAME) | + (1 << LAST4_FRAME) | +#endif // CONFIG_EXT_REFS + (1 << GOLDEN_FRAME); ref_frame_skip_mask[1] = SECOND_REF_FRAME_MASK; mode_skip_mask[ALTREF_FRAME] = ~INTER_NEAREST_NEAR_ZERO; if (frame_mv[NEARMV][ALTREF_FRAME].as_int != 0) @@ -4750,6 +4914,20 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi, ref_frame_skip_mask[0] |= LAST_FRAME_MODE_MASK; ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; break; +#if CONFIG_EXT_REFS + case LAST2_FRAME: + ref_frame_skip_mask[0] |= LAST2_FRAME_MODE_MASK; + ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; + break; + case LAST3_FRAME: + ref_frame_skip_mask[0] |= LAST3_FRAME_MODE_MASK; + ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; + break; + case LAST4_FRAME: + ref_frame_skip_mask[0] |= LAST4_FRAME_MODE_MASK; + ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; + break; +#endif // CONFIG_EXT_REFS case GOLDEN_FRAME: ref_frame_skip_mask[0] |= GOLDEN_FRAME_MODE_MASK; ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; @@ -4771,6 +4949,20 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi, if (mode_skip_mask[ref_frame] & (1 << this_mode)) continue; +#if CONFIG_EXT_REFS + if (cm->last_frame_type == KEY_FRAME && ref_frame == LAST2_FRAME) + continue; + + if ((cm->last2_frame_type == KEY_FRAME || + cm->last_frame_type == KEY_FRAME) && ref_frame == LAST3_FRAME) + continue; + + if ((cm->last3_frame_type == KEY_FRAME || + cm->last2_frame_type == KEY_FRAME || + cm->last_frame_type == KEY_FRAME) && ref_frame == LAST4_FRAME) + continue; +#endif // CONFIG_EXT_REFS + // Test best rd so far against threshold for trying this mode. if (best_mode_skippable && sf->schedule_mode_search) mode_threshold[mode_index] <<= 1; @@ -5373,9 +5565,18 @@ void vp10_rd_pick_inter_mode_sub8x8(VP10_COMP *cpi, unsigned char segment_id = mbmi->segment_id; int comp_pred, i; int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES]; - struct buf_2d yv12_mb[4][MAX_MB_PLANE]; - static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG, - VP9_ALT_FLAG }; + struct buf_2d yv12_mb[MAX_REF_FRAMES][MAX_MB_PLANE]; + static const int flag_list[REFS_PER_FRAME + 1] = { + 0, + VP9_LAST_FLAG, +#if CONFIG_EXT_REFS + VP9_LAST2_FLAG, + VP9_LAST3_FLAG, + VP9_LAST4_FLAG, +#endif // CONFIG_EXT_REFS + VP9_GOLD_FLAG, + VP9_ALT_FLAG + }; int64_t best_rd = best_rd_so_far; int64_t best_yrd = best_rd_so_far; // FIXME(rbultje) more precise int64_t best_pred_diff[REFERENCE_MODES]; @@ -5462,6 +5663,20 @@ void vp10_rd_pick_inter_mode_sub8x8(VP10_COMP *cpi, ref_frame = vp10_ref_order[ref_index].ref_frame[0]; second_ref_frame = vp10_ref_order[ref_index].ref_frame[1]; +#if CONFIG_EXT_REFS + if (cm->last_frame_type == KEY_FRAME && ref_frame == LAST2_FRAME) + continue; + + if ((cm->last2_frame_type == KEY_FRAME || + cm->last_frame_type == KEY_FRAME) && ref_frame == LAST3_FRAME) + continue; + + if ((cm->last3_frame_type == KEY_FRAME || + cm->last2_frame_type == KEY_FRAME || + cm->last_frame_type == KEY_FRAME) && ref_frame == LAST4_FRAME) + continue; +#endif // CONFIG_EXT_REFS + // Look at the reference frame of the best mode so far and set the // skip mask to look at a subset of the remaining modes. if (ref_index > 2 && sf->mode_skip_start < MAX_MODES) { @@ -5470,15 +5685,59 @@ void vp10_rd_pick_inter_mode_sub8x8(VP10_COMP *cpi, case INTRA_FRAME: break; case LAST_FRAME: - ref_frame_skip_mask[0] |= (1 << GOLDEN_FRAME) | (1 << ALTREF_FRAME); + ref_frame_skip_mask[0] |= (1 << GOLDEN_FRAME) | +#if CONFIG_EXT_REFS + (1 << LAST2_FRAME) | + (1 << LAST3_FRAME) | + (1 << LAST4_FRAME) | +#endif // CONFIG_EXT_REFS + (1 << ALTREF_FRAME); + ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; + break; +#if CONFIG_EXT_REFS + case LAST2_FRAME: + ref_frame_skip_mask[0] |= (1 << LAST_FRAME) | + (1 << LAST3_FRAME) | + (1 << LAST4_FRAME) | + (1 << GOLDEN_FRAME) | + (1 << ALTREF_FRAME); + ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; + break; + case LAST3_FRAME: + ref_frame_skip_mask[0] |= (1 << LAST_FRAME) | + (1 << LAST2_FRAME) | + (1 << LAST4_FRAME) | + (1 << GOLDEN_FRAME) | + (1 << ALTREF_FRAME); + ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; + break; + case LAST4_FRAME: + ref_frame_skip_mask[0] |= (1 << LAST_FRAME) | + (1 << LAST2_FRAME) | + (1 << LAST3_FRAME) | + (1 << GOLDEN_FRAME) | + (1 << ALTREF_FRAME); ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; break; +#endif // CONFIG_EXT_REFS case GOLDEN_FRAME: - ref_frame_skip_mask[0] |= (1 << LAST_FRAME) | (1 << ALTREF_FRAME); + ref_frame_skip_mask[0] |= (1 << LAST_FRAME) | +#if CONFIG_EXT_REFS + (1 << LAST2_FRAME) | + (1 << LAST3_FRAME) | + (1 << LAST4_FRAME) | +#endif // CONFIG_EXT_REFS + (1 << ALTREF_FRAME); ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; break; case ALTREF_FRAME: - ref_frame_skip_mask[0] |= (1 << GOLDEN_FRAME) | (1 << LAST_FRAME); + ref_frame_skip_mask[0] |= (1 << GOLDEN_FRAME) | +#if CONFIG_EXT_REFS + (1 << LAST2_FRAME) | + (1 << LAST3_FRAME) | + (1 << LAST4_FRAME) | +#endif // CONFIG_EXT_REFS + (1 << LAST_FRAME); break; case NONE: case MAX_REF_FRAMES: @@ -5610,8 +5869,16 @@ void vp10_rd_pick_inter_mode_sub8x8(VP10_COMP *cpi, this_rd_thresh = (ref_frame == LAST_FRAME) ? rd_opt->threshes[segment_id][bsize][THR_LAST] : rd_opt->threshes[segment_id][bsize][THR_ALTR]; +#if CONFIG_EXT_REFS + this_rd_thresh = (ref_frame == LAST2_FRAME) ? + rd_opt->threshes[segment_id][bsize][THR_LAST2] : this_rd_thresh; + this_rd_thresh = (ref_frame == LAST3_FRAME) ? + rd_opt->threshes[segment_id][bsize][THR_LAST3] : this_rd_thresh; + this_rd_thresh = (ref_frame == LAST4_FRAME) ? + rd_opt->threshes[segment_id][bsize][THR_LAST4] : this_rd_thresh; +#endif // CONFIG_EXT_REFS this_rd_thresh = (ref_frame == GOLDEN_FRAME) ? - rd_opt->threshes[segment_id][bsize][THR_GOLD] : this_rd_thresh; + rd_opt->threshes[segment_id][bsize][THR_GOLD] : this_rd_thresh; for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) filter_cache[i] = INT64_MAX; diff --git a/vp9/common/vp9_pred_common.c b/vp9/common/vp9_pred_common.c index 1f1632573..e4c349c72 100644 --- a/vp9/common/vp9_pred_common.c +++ b/vp9/common/vp9_pred_common.c @@ -192,6 +192,7 @@ int vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd) { const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; const int has_above = xd->up_available; const int has_left = 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. diff --git a/vp9/common/vp9_thread_common.c b/vp9/common/vp9_thread_common.c index db78d6be8..033326dd9 100644 --- a/vp9/common/vp9_thread_common.c +++ b/vp9/common/vp9_thread_common.c @@ -379,11 +379,11 @@ void vp9_accumulate_frame_counts(FRAME_COUNTS *accum, for (i = 0; i < REF_CONTEXTS; i++) for (j = 0; j < 2; j++) for (k = 0; k < 2; k++) - accum->single_ref[i][j][k] += counts->single_ref[i][j][k]; + accum->single_ref[i][j][k] += counts->single_ref[i][j][k]; for (i = 0; i < REF_CONTEXTS; i++) for (j = 0; j < 2; j++) - accum->comp_ref[i][j] += counts->comp_ref[i][j]; + accum->comp_ref[i][j] += counts->comp_ref[i][j]; for (i = 0; i < TX_SIZE_CONTEXTS; i++) { for (j = 0; j < TX_SIZES; j++) diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c index f5da07ea0..ed49a69f1 100644 --- a/vp9/decoder/vp9_decoder.c +++ b/vp9/decoder/vp9_decoder.c @@ -237,15 +237,16 @@ static void swap_frame_buffers(VP9Decoder *pbi) { RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; lock_buffer_pool(pool); + for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) { const int old_idx = cm->ref_frame_map[ref_index]; // Current thread releases the holding of reference frame. decrease_ref_count(old_idx, frame_bufs, pool); // Release the reference frame in reference map. - if (mask & 1) { + if (mask & 1) decrease_ref_count(old_idx, frame_bufs, pool); - } + cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index]; ++ref_index; } @@ -267,7 +268,7 @@ static void swap_frame_buffers(VP9Decoder *pbi) { } // Invalidate these references until the next frame starts. - for (ref_index = 0; ref_index < 3; ref_index++) + for (ref_index = 0; ref_index < REFS_PER_FRAME; ref_index++) cm->frame_refs[ref_index].idx = -1; } @@ -325,7 +326,6 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, pbi->cur_buf = &frame_bufs[cm->new_fb_idx]; } - if (setjmp(cm->error.jmp)) { const VPxWorkerInterface *const winterface = vpx_get_worker_interface(); int i; @@ -350,9 +350,8 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, decrease_ref_count(old_idx, frame_bufs, pool); // Release the reference frame in reference map. - if (mask & 1) { + if (mask & 1) decrease_ref_count(old_idx, frame_bufs, pool); - } ++ref_index; } diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index f9c28f6a9..2dd948dc1 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -4047,7 +4047,7 @@ void vp9_encode_frame(VP9_COMP *cpi) { // either compound, single or hybrid prediction as per whatever has // worked best for that type of frame in the past. // It also predicts whether another coding mode would have worked - // better that this coding mode. If that is the case, it remembers + // better than this coding mode. If that is the case, it remembers // that for subsequent frames. // It does the same analysis for transform size selection also. const MV_REFERENCE_FRAME frame_type = get_frame_type(cpi); diff --git a/vp9/encoder/vp9_rd.c b/vp9/encoder/vp9_rd.c index eda774376..21e57c422 100644 --- a/vp9/encoder/vp9_rd.c +++ b/vp9/encoder/vp9_rd.c @@ -590,6 +590,12 @@ void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) { rd->thresh_mult[THR_NEARMV] += 1000; rd->thresh_mult[THR_NEARA] += 1000; + rd->thresh_mult[THR_NEARG] += 1000; + + rd->thresh_mult[THR_ZEROMV] += 2000; + rd->thresh_mult[THR_ZEROG] += 2000; + rd->thresh_mult[THR_ZEROA] += 2000; + rd->thresh_mult[THR_COMP_NEARESTLA] += 1000; rd->thresh_mult[THR_COMP_NEARESTGA] += 1000; @@ -597,13 +603,9 @@ void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) { rd->thresh_mult[THR_COMP_NEARLA] += 1500; rd->thresh_mult[THR_COMP_NEWLA] += 2000; - rd->thresh_mult[THR_NEARG] += 1000; rd->thresh_mult[THR_COMP_NEARGA] += 1500; rd->thresh_mult[THR_COMP_NEWGA] += 2000; - rd->thresh_mult[THR_ZEROMV] += 2000; - rd->thresh_mult[THR_ZEROG] += 2000; - rd->thresh_mult[THR_ZEROA] += 2000; rd->thresh_mult[THR_COMP_ZEROLA] += 2500; rd->thresh_mult[THR_COMP_ZEROGA] += 2500; @@ -618,9 +620,10 @@ void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) { } void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) { - static const int thresh_mult[2][MAX_REFS] = - {{2500, 2500, 2500, 4500, 4500, 2500}, - {2000, 2000, 2000, 4000, 4000, 2000}}; + static const int thresh_mult[2][MAX_REFS] = { + {2500, 2500, 2500, 4500, 4500, 2500}, + {2000, 2000, 2000, 4000, 4000, 2000} + }; RD_OPT *const rd = &cpi->rd; const int idx = cpi->oxcf.mode == BEST; memcpy(rd->thresh_mult_sub8x8, thresh_mult[idx], sizeof(thresh_mult[idx])); diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index e32130e39..31c5b2e41 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -3966,7 +3966,7 @@ void vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, rd_opt->threshes[segment_id][bsize][THR_LAST] : rd_opt->threshes[segment_id][bsize][THR_ALTR]; this_rd_thresh = (ref_frame == GOLDEN_FRAME) ? - rd_opt->threshes[segment_id][bsize][THR_GOLD] : this_rd_thresh; + rd_opt->threshes[segment_id][bsize][THR_GOLD] : this_rd_thresh; for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) filter_cache[i] = INT64_MAX; @@ -3988,6 +3988,7 @@ void vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, int64_t rs_rd; MB_MODE_INFO_EXT *mbmi_ext = x->mbmi_ext; mbmi->interp_filter = switchable_filter_index; + tmp_rd = rd_pick_best_sub8x8_mode(cpi, x, &mbmi_ext->ref_mvs[ref_frame][0], second_ref, best_yrd, &rate,