diff --git a/av1/common/blockd.h b/av1/common/blockd.h index a7a6332045347e8f87d8ae88d6d4fbc41d8addfe..050b9a73bb5fd8d2f3179ba1c8ad1c547dedf02f 100644 --- a/av1/common/blockd.h +++ b/av1/common/blockd.h @@ -502,6 +502,33 @@ static INLINE int has_second_ref(const MB_MODE_INFO *mbmi) { return mbmi->ref_frame[1] > INTRA_FRAME; } +#if CONFIG_EXT_COMP_REFS +static INLINE int has_uni_comp_refs(const MB_MODE_INFO *mbmi) { + return has_second_ref(mbmi) && (!((mbmi->ref_frame[0] >= BWDREF_FRAME) ^ + (mbmi->ref_frame[1] >= BWDREF_FRAME))); +} + +static INLINE MV_REFERENCE_FRAME comp_ref0(int ref_idx) { + static const MV_REFERENCE_FRAME lut[] = { + LAST_FRAME, // LAST_LAST2_FRAMES, + LAST_FRAME, // LAST_GOLDEN_FRAMES, + BWDREF_FRAME, // BWDREF_ALTREF_FRAMES, + }; + assert(NELEMENTS(lut) == UNIDIR_COMP_REFS); + return lut[ref_idx]; +} + +static INLINE MV_REFERENCE_FRAME comp_ref1(int ref_idx) { + static const MV_REFERENCE_FRAME lut[] = { + LAST2_FRAME, // LAST_LAST2_FRAMES, + GOLDEN_FRAME, // LAST_GOLDEN_FRAMES, + ALTREF_FRAME, // BWDREF_ALTREF_FRAMES, + }; + assert(NELEMENTS(lut) == UNIDIR_COMP_REFS); + return lut[ref_idx]; +} +#endif // CONFIG_EXT_COMP_REFS + PREDICTION_MODE av1_left_block_mode(const MODE_INFO *cur_mi, const MODE_INFO *left_mi, int b); diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c index 433b0d89f2254bd039b37953da2dfd68888cd7ae..b0bf05e483b5c498cfa1199859232bbf86ffd922 100644 --- a/av1/common/entropymode.c +++ b/av1/common/entropymode.c @@ -1392,6 +1392,17 @@ static const aom_cdf_prob default_comp_inter_cdf[COMP_INTER_CONTEXTS][CDF_SIZE( { AOM_ICDF(41 * 128), AOM_ICDF(32768), 0 } }; #endif +#if CONFIG_EXT_COMP_REFS +static const aom_prob default_comp_ref_type_p[COMP_REF_TYPE_CONTEXTS] = { + 30, 75, 120, 170, 230 +}; + +static const aom_prob + default_uni_comp_ref_p[UNI_COMP_REF_CONTEXTS][UNIDIR_COMP_REFS - 1] = { + { 30, 20 }, { 75, 70 }, { 130, 130 }, { 165, 165 }, { 215, 220 } + }; +#endif // CONFIG_EXT_COMP_REFS + #if CONFIG_EXT_REFS static const aom_prob default_comp_ref_p[REF_CONTEXTS][FWD_REFS - 1] = { // TODO(zoeliu): To adjust the initial prob values. @@ -4577,6 +4588,10 @@ static void init_mode_probs(FRAME_CONTEXT *fc) { #if CONFIG_NEW_MULTISYMBOL av1_copy(fc->comp_inter_cdf, default_comp_inter_cdf); #endif +#if CONFIG_EXT_COMP_REFS + av1_copy(fc->comp_ref_type_prob, default_comp_ref_type_p); + av1_copy(fc->uni_comp_ref_prob, default_uni_comp_ref_p); +#endif // CONFIG_EXT_COMP_REFS av1_copy(fc->comp_ref_prob, default_comp_ref_p); #if CONFIG_LV_MAP av1_copy(fc->txb_skip, default_txb_skip); @@ -4804,6 +4819,17 @@ void av1_adapt_inter_frame_probs(AV1_COMMON *cm) { fc->comp_inter_prob[i] = av1_mode_mv_merge_probs(pre_fc->comp_inter_prob[i], counts->comp_inter[i]); +#if CONFIG_EXT_COMP_REFS + for (i = 0; i < COMP_REF_TYPE_CONTEXTS; i++) + fc->comp_ref_type_prob[i] = av1_mode_mv_merge_probs( + pre_fc->comp_ref_type_prob[i], counts->comp_ref_type[i]); + + for (i = 0; i < UNI_COMP_REF_CONTEXTS; i++) + for (j = 0; j < (UNIDIR_COMP_REFS - 1); j++) + fc->uni_comp_ref_prob[i][j] = av1_mode_mv_merge_probs( + pre_fc->uni_comp_ref_prob[i][j], counts->uni_comp_ref[i][j]); +#endif // CONFIG_EXT_COMP_REFS + #if CONFIG_EXT_REFS for (i = 0; i < REF_CONTEXTS; i++) for (j = 0; j < (FWD_REFS - 1); j++) diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h index b16b141db9fba189bfb32f3010cbf829a34efee3..301b3c1a5632c75a50f6d4d3fb1de0cba4750a8d 100644 --- a/av1/common/entropymode.h +++ b/av1/common/entropymode.h @@ -218,6 +218,10 @@ typedef struct frame_contexts { aom_cdf_prob comp_inter_cdf[COMP_INTER_CONTEXTS][CDF_SIZE(2)]; aom_cdf_prob single_ref_cdf[REF_CONTEXTS][SINGLE_REFS - 1][CDF_SIZE(2)]; #endif +#if CONFIG_EXT_COMP_REFS + aom_prob comp_ref_type_prob[COMP_REF_TYPE_CONTEXTS]; + aom_prob uni_comp_ref_prob[UNI_COMP_REF_CONTEXTS][UNIDIR_COMP_REFS - 1]; +#endif // CONFIG_EXT_COMP_REFS aom_prob single_ref_prob[REF_CONTEXTS][SINGLE_REFS - 1]; #if CONFIG_EXT_REFS aom_prob comp_ref_prob[REF_CONTEXTS][FWD_REFS - 1]; @@ -390,6 +394,10 @@ typedef struct FRAME_COUNTS { #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION unsigned int intra_inter[INTRA_INTER_CONTEXTS][2]; unsigned int comp_inter[COMP_INTER_CONTEXTS][2]; +#if CONFIG_EXT_COMP_REFS + unsigned int comp_ref_type[COMP_REF_TYPE_CONTEXTS][2]; + unsigned int uni_comp_ref[UNI_COMP_REF_CONTEXTS][UNIDIR_COMP_REFS - 1][2]; +#endif // CONFIG_EXT_COMP_REFS unsigned int single_ref[REF_CONTEXTS][SINGLE_REFS - 1][2]; #if CONFIG_EXT_REFS unsigned int comp_ref[REF_CONTEXTS][FWD_REFS - 1][2]; diff --git a/av1/common/enums.h b/av1/common/enums.h index 2e802deb4f24c8af4108e852963d21d079a967f5..f008f9d7d25dcaf891ca0cb76a9cc69be2b13a8e 100644 --- a/av1/common/enums.h +++ b/av1/common/enums.h @@ -286,6 +286,18 @@ typedef enum { #endif // CONFIG_EXT_REFS } AOM_REFFRAME; +#if CONFIG_EXT_COMP_REFS +#define USE_UNI_COMP_REFS 1 + +typedef enum { + UNIDIR_COMP_REFERENCE = 0, + BIDIR_COMP_REFERENCE = 1, + COMP_REFERENCE_TYPES = 2, +} COMP_REFERENCE_TYPE; +#else // !CONFIG_EXT_COMP_REFS +#define USE_UNI_COMP_REFS 0 +#endif // CONFIG_EXT_COMP_REFS + typedef enum { PLANE_TYPE_Y = 0, PLANE_TYPE_UV = 1, PLANE_TYPES } PLANE_TYPE; #if CONFIG_CFL @@ -487,6 +499,12 @@ typedef enum { #define INTRA_INTER_CONTEXTS 4 #define COMP_INTER_CONTEXTS 5 #define REF_CONTEXTS 5 + +#if CONFIG_EXT_COMP_REFS +#define COMP_REF_TYPE_CONTEXTS 5 +#define UNI_COMP_REF_CONTEXTS 5 +#endif // CONFIG_EXT_COMP_REFS + #if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #define COMP_INTER_MODE_CONTEXTS 4 #endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF @@ -526,7 +544,17 @@ typedef uint8_t TXFM_CONTEXT; #endif // CONFIG_EXT_REFS #define SINGLE_REFS (FWD_REFS + BWD_REFS) +#if CONFIG_EXT_COMP_REFS +typedef enum { + LAST_LAST2_FRAMES, // { LAST_FRAME, LAST2_FRAME } + LAST_GOLDEN_FRAMES, // { LAST_FRAME, GOLDEN_FRAME } + BWDREF_ALTREF_FRAMES, // { BWDREF_FRAME, ALTREF_FRAME } + UNIDIR_COMP_REFS +} UNIDIR_COMP_REF; +#define COMP_REFS (FWD_REFS * BWD_REFS + UNIDIR_COMP_REFS) +#else // !CONFIG_EXT_COMP_REFS #define COMP_REFS (FWD_REFS * BWD_REFS) +#endif // CONFIG_EXT_COMP_REFS #define MODE_CTX_REF_FRAMES (TOTAL_REFS_PER_FRAME + COMP_REFS) diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h index 209a63612fe3602490420860a13f903b643d6761..acba43677df5b5da4f11895c0d56d0f536c2521b 100644 --- a/av1/common/mvref_common.h +++ b/av1/common/mvref_common.h @@ -238,10 +238,41 @@ static INLINE int av1_nmv_ctx(const uint8_t ref_mv_count, return 0; } +#if CONFIG_EXT_COMP_REFS +static INLINE int8_t av1_uni_comp_ref_idx(const MV_REFERENCE_FRAME *const rf) { + // Single ref pred + if (rf[1] <= INTRA_FRAME) return -1; + + // Bi-directional comp ref pred + if ((rf[0] < BWDREF_FRAME) && (rf[1] >= BWDREF_FRAME)) return -1; + + for (int8_t ref_idx = 0; ref_idx < UNIDIR_COMP_REFS; ++ref_idx) { + if (rf[0] == comp_ref0(ref_idx) && rf[1] == comp_ref1(ref_idx)) + return ref_idx; + } + return -1; +} +#endif // CONFIG_EXT_COMP_REFS + static INLINE int8_t av1_ref_frame_type(const MV_REFERENCE_FRAME *const rf) { if (rf[1] > INTRA_FRAME) { - return TOTAL_REFS_PER_FRAME + FWD_RF_OFFSET(rf[0]) + - BWD_RF_OFFSET(rf[1]) * FWD_REFS; +#if CONFIG_EXT_COMP_REFS + int8_t uni_comp_ref_idx = av1_uni_comp_ref_idx(rf); +#if !USE_UNI_COMP_REFS + // NOTE: uni-directional comp refs disabled + assert(uni_comp_ref_idx < 0); +#endif // !USE_UNI_COMP_REFS + if (uni_comp_ref_idx >= 0) { + assert((TOTAL_REFS_PER_FRAME + FWD_REFS * BWD_REFS + uni_comp_ref_idx) < + MODE_CTX_REF_FRAMES); + return TOTAL_REFS_PER_FRAME + FWD_REFS * BWD_REFS + uni_comp_ref_idx; + } else { +#endif // CONFIG_EXT_COMP_REFS + return TOTAL_REFS_PER_FRAME + FWD_RF_OFFSET(rf[0]) + + BWD_RF_OFFSET(rf[1]) * FWD_REFS; +#if CONFIG_EXT_COMP_REFS + } +#endif // CONFIG_EXT_COMP_REFS } return rf[0]; @@ -255,9 +286,15 @@ static MV_REFERENCE_FRAME ref_frame_map[COMP_REFS][2] = { { LAST_FRAME, ALTREF_FRAME }, { LAST2_FRAME, ALTREF_FRAME }, { LAST3_FRAME, ALTREF_FRAME }, { GOLDEN_FRAME, ALTREF_FRAME } -#else + + // TODO(zoeliu): Temporarily disable uni-directional comp refs +#if CONFIG_EXT_COMP_REFS + , { LAST_FRAME, LAST2_FRAME }, { LAST_FRAME, GOLDEN_FRAME }, + { BWDREF_FRAME, ALTREF_FRAME } +#endif // CONFIG_EXT_COMP_REFS +#else // !CONFIG_EXT_REFS { LAST_FRAME, ALTREF_FRAME }, { GOLDEN_FRAME, ALTREF_FRAME } -#endif +#endif // CONFIG_EXT_REFS }; // clang-format on diff --git a/av1/common/pred_common.c b/av1/common/pred_common.c index bda1fc5412d4074442775818d474ecc89c5464c5..01e7f41f05424b2590fe05df91df9de00f695fdf 100644 --- a/av1/common/pred_common.c +++ b/av1/common/pred_common.c @@ -310,6 +310,280 @@ int av1_get_reference_mode_context(const AV1_COMMON *cm, return ctx; } +#if CONFIG_EXT_COMP_REFS +#define CHECK_BWDREF_OR_ALTREF(ref_frame) \ + ((ref_frame) == BWDREF_FRAME || (ref_frame) == ALTREF_FRAME) +int av1_get_comp_reference_type_context(const AV1_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; + + (void)cm; + + 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 + pred_context = 2; + } else if (above_intra || left_intra) { // intra/inter + const MB_MODE_INFO *inter_mbmi = above_intra ? left_mbmi : above_mbmi; + + if (!has_second_ref(inter_mbmi)) // single pred + pred_context = 2; + else // comp pred + pred_context = 1 + 2 * has_uni_comp_refs(inter_mbmi); + } else { // inter/inter + const int a_sg = !has_second_ref(above_mbmi); + const int l_sg = !has_second_ref(left_mbmi); + const MV_REFERENCE_FRAME frfa = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME frfl = left_mbmi->ref_frame[0]; + + if (a_sg && l_sg) { // single/single + pred_context = 1 + + 2 * (!(CHECK_BWDREF_OR_ALTREF(frfa) ^ + CHECK_BWDREF_OR_ALTREF(frfl))); + } else if (l_sg || a_sg) { // single/comp + const int uni_rfc = + a_sg ? has_uni_comp_refs(left_mbmi) : has_uni_comp_refs(above_mbmi); + + if (!uni_rfc) // comp bidir + pred_context = 1; + else // comp unidir + pred_context = 3 + (!(CHECK_BWDREF_OR_ALTREF(frfa) ^ + CHECK_BWDREF_OR_ALTREF(frfl))); + } else { // comp/comp + const int a_uni_rfc = has_uni_comp_refs(above_mbmi); + const int l_uni_rfc = has_uni_comp_refs(left_mbmi); + + if (!a_uni_rfc && !l_uni_rfc) // bidir/bidir + pred_context = 0; + else if (!a_uni_rfc || !l_uni_rfc) // unidir/bidir + pred_context = 2; + else // unidir/unidir + pred_context = + 3 + (!((frfa == BWDREF_FRAME) ^ (frfl == BWDREF_FRAME))); + } + } + } else if (above_in_image || left_in_image) { // one edge available + const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi; + + if (!is_inter_block(edge_mbmi)) { // intra + pred_context = 2; + } else { // inter + if (!has_second_ref(edge_mbmi)) // single pred + pred_context = 2; + else // comp pred + pred_context = 4 * has_uni_comp_refs(edge_mbmi); + } + } else { // no edges available + pred_context = 2; + } + + assert(pred_context >= 0 && pred_context < COMP_REF_TYPE_CONTEXTS); + return pred_context; +} + +// Returns a context number for the given MB prediction signal +// Signal the uni-directional compound reference frame pair as +// either (BWDREF, ALTREF), or (LAST, LAST2)/(LAST, GOLDEN), +// conditioning on the pair is known as uni-directional. +int av1_get_pred_context_uni_comp_ref_p(const AV1_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; + + (void)cm; + + 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 + pred_context = 2; + } else if (above_intra || left_intra) { // intra/inter + const MB_MODE_INFO *inter_mbmi = above_intra ? left_mbmi : above_mbmi; + + if (!has_second_ref(inter_mbmi)) { // single pred + pred_context = + 1 + 2 * (!CHECK_BWDREF_OR_ALTREF(inter_mbmi->ref_frame[0])); + } else { // comp pred + if (has_uni_comp_refs(inter_mbmi)) // comp unidir + pred_context = 4 * (inter_mbmi->ref_frame[0] != BWDREF_FRAME); + else // comp_bidir + pred_context = 2; + } + } else { // inter/inter + const int a_sg = !has_second_ref(above_mbmi); + const int l_sg = !has_second_ref(left_mbmi); + const MV_REFERENCE_FRAME frfa = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME frfl = left_mbmi->ref_frame[0]; + + if (CHECK_BWDREF_OR_ALTREF(frfa) && CHECK_BWDREF_OR_ALTREF(frfl)) { + pred_context = 0; + } else if (a_sg && l_sg) { // single/single + pred_context = 2 + (!CHECK_BWDREF_OR_ALTREF(frfa) && + !CHECK_BWDREF_OR_ALTREF(frfl)); + } else if (l_sg || a_sg) { // single/comp + const MV_REFERENCE_FRAME frfc = a_sg ? frfl : frfa; + const MV_REFERENCE_FRAME rfs = a_sg ? frfa : frfl; + const int uni_rfc = + a_sg ? has_uni_comp_refs(left_mbmi) : has_uni_comp_refs(above_mbmi); + + if (uni_rfc && (frfc == BWDREF_FRAME)) + pred_context = 1; + else if (uni_rfc && (frfc == LAST_FRAME)) + pred_context = 3 + (!CHECK_BWDREF_OR_ALTREF(rfs)); + else if (CHECK_BWDREF_OR_ALTREF(rfs)) + pred_context = 2; + else + pred_context = 3; + } else { // comp/comp + const int a_uni_rfc = has_uni_comp_refs(above_mbmi); + const int l_uni_rfc = has_uni_comp_refs(left_mbmi); + + if (a_uni_rfc && l_uni_rfc) + pred_context = 2 + 2 * (frfa != BWDREF_FRAME && frfl != BWDREF_FRAME); + else if (a_uni_rfc || l_uni_rfc) + pred_context = 1 + 2 * (frfa != BWDREF_FRAME && frfl != BWDREF_FRAME); + 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)) { // intra + pred_context = 2; + } else { // inter + if (!has_second_ref(edge_mbmi)) { // single pred + pred_context = + 1 + 2 * (!CHECK_BWDREF_OR_ALTREF(edge_mbmi->ref_frame[0])); + } else { // comp pred + if (has_uni_comp_refs(edge_mbmi)) // comp unidir + pred_context = 4 * (edge_mbmi->ref_frame[0] != BWDREF_FRAME); + else // comp bidir + pred_context = 2; + } + } + } else { // no edges available + pred_context = 2; + } + + assert(pred_context >= 0 && pred_context < UNI_COMP_REF_CONTEXTS); + return pred_context; +} + +// Returns a context number for the given MB prediction signal +// Signal the uni-directional compound reference frame pair as +// either (BWDREF, ALTREF), or (LAST, LAST2)/(LAST, GOLDEN), +// conditioning on the pair is known as uni-directional. +#define CHECK_LAST2_OR_GOLDEN(ref_frame) \ + ((ref_frame) == LAST2_FRAME || (ref_frame) == GOLDEN_FRAME) +int av1_get_pred_context_uni_comp_ref_p1(const AV1_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; + + (void)cm; + + 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 + pred_context = 2; + } else if (above_intra || left_intra) { // intra/inter + const MB_MODE_INFO *inter_mbmi = above_intra ? left_mbmi : above_mbmi; + + if (!has_second_ref(inter_mbmi)) { // single pred + if (CHECK_LAST2_OR_GOLDEN(inter_mbmi->ref_frame[0])) + pred_context = 1 + 2 * (inter_mbmi->ref_frame[0] == LAST2_FRAME); + else + pred_context = 2; + } else { // comp pred + if (CHECK_LAST2_OR_GOLDEN(inter_mbmi->ref_frame[1])) + pred_context = 4 * (inter_mbmi->ref_frame[1] == LAST2_FRAME); + else + pred_context = 2; + } + } else { // inter/inter + const int a_sg = !has_second_ref(above_mbmi); + const int l_sg = !has_second_ref(left_mbmi); + const MV_REFERENCE_FRAME frfa = above_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME frfl = left_mbmi->ref_frame[0]; + const MV_REFERENCE_FRAME brfa = above_mbmi->ref_frame[1]; + const MV_REFERENCE_FRAME brfl = left_mbmi->ref_frame[1]; + + if (a_sg && l_sg) { // single/single + if (CHECK_LAST2_OR_GOLDEN(frfa) && (frfa == frfl || frfl == LAST_FRAME)) + pred_context = 1 + 2 * (frfa == LAST2_FRAME); + else if (frfa == LAST_FRAME && CHECK_LAST2_OR_GOLDEN(frfl)) + pred_context = 1 + 2 * (frfl == LAST2_FRAME); + else + pred_context = 2; + } else if (l_sg || a_sg) { // single/comp + const MV_REFERENCE_FRAME brfc = a_sg ? brfl : brfa; + + if (CHECK_LAST2_OR_GOLDEN(brfc)) + pred_context = 4 * (brfc == LAST2_FRAME); + if (CHECK_LAST2_OR_GOLDEN(frfa) && (frfa == frfl || frfl == LAST_FRAME)) + pred_context = 1 + 2 * (frfa == LAST2_FRAME); + else if (frfa == LAST_FRAME && CHECK_LAST2_OR_GOLDEN(frfl)) + pred_context = 1 + 2 * (frfl == LAST2_FRAME); + else + pred_context = 2; + } else { // comp/comp + if (CHECK_LAST2_OR_GOLDEN(brfa) && + (brfa == brfl || !CHECK_LAST2_OR_GOLDEN(brfl))) + pred_context = 4 * (brfa == LAST2_FRAME); + else if (!CHECK_LAST2_OR_GOLDEN(brfa) && CHECK_LAST2_OR_GOLDEN(brfl)) + pred_context = 4 * (brfl == LAST2_FRAME); + else if (CHECK_LAST2_OR_GOLDEN(frfa) && + (frfa == frfl || frfl == LAST_FRAME)) + pred_context = 1 + 2 * (frfa == LAST2_FRAME); + else if (frfa == LAST_FRAME && CHECK_LAST2_OR_GOLDEN(frfl)) + pred_context = 1 + 2 * (frfl == LAST2_FRAME); + 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)) { // intra + pred_context = 2; + } else { // inter + if (!has_second_ref(edge_mbmi)) { // single pred + if (CHECK_LAST2_OR_GOLDEN(edge_mbmi->ref_frame[0])) + pred_context = 1 + 2 * (edge_mbmi->ref_frame[0] == LAST2_FRAME); + else + pred_context = 2; + } else { // comp pred + if (CHECK_LAST2_OR_GOLDEN(edge_mbmi->ref_frame[1])) + pred_context = 4 * (edge_mbmi->ref_frame[1] == LAST2_FRAME); + else + pred_context = 2; + } + } + } else { // no edges available + pred_context = 2; + } + + assert(pred_context >= 0 && pred_context < UNI_COMP_REF_CONTEXTS); + return pred_context; +} +#endif // CONFIG_EXT_COMP_REFS + #if CONFIG_EXT_REFS // TODO(zoeliu): Future work will be conducted to optimize the context design @@ -327,13 +601,8 @@ int av1_get_reference_mode_context(const AV1_COMMON *cm, // // NOTE(zoeliu): The probability of ref_frame[0] is either // GOLDEN_FRAME or LAST3_FRAME. -#if CONFIG_ONE_SIDED_COMPOUND -int av1_get_pred_context_comp_ref_p(UNUSED const AV1_COMMON *cm, - const MACROBLOCKD *xd) { -#else int av1_get_pred_context_comp_ref_p(const AV1_COMMON *cm, const MACROBLOCKD *xd) { -#endif int pred_context; const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; @@ -344,14 +613,16 @@ int av1_get_pred_context_comp_ref_p(const AV1_COMMON *cm, // 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 CONFIG_ONE_SIDED_COMPOUND // No change to bitstream +#if CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS // No change to bitstream // Code seems to assume that signbias of cm->comp_bwd_ref[0] is always 1 const int bwd_ref_sign_idx = 1; #else const int bwd_ref_sign_idx = cm->ref_frame_sign_bias[cm->comp_bwd_ref[0]]; -#endif +#endif // CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS const int fwd_ref_sign_idx = !bwd_ref_sign_idx; + (void)cm; + 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); @@ -403,8 +674,11 @@ int av1_get_pred_context_comp_ref_p(const AV1_COMMON *cm, if ((CHECK_LAST_OR_LAST2(frfa) && CHECK_LAST_OR_LAST2(frfl))) { pred_context = 4; } else { - // NOTE(zoeliu): Following assert may be removed once confirmed. +// NOTE(zoeliu): Following assert may be removed once confirmed. +#if !USE_UNI_COMP_REFS + // TODO(zoeliu): To further study the UNIDIR scenario assert(CHECK_GOLDEN_OR_LAST3(frfa) || CHECK_GOLDEN_OR_LAST3(frfl)); +#endif // !USE_UNI_COMP_REFS pred_context = 2; } } @@ -437,13 +711,8 @@ int av1_get_pred_context_comp_ref_p(const AV1_COMMON *cm, // // NOTE(zoeliu): The probability of ref_frame[0] is LAST_FRAME, // conditioning on it is either LAST_FRAME or LAST2_FRAME. -#if CONFIG_ONE_SIDED_COMPOUND -int av1_get_pred_context_comp_ref_p1(UNUSED const AV1_COMMON *cm, - const MACROBLOCKD *xd) { -#else int av1_get_pred_context_comp_ref_p1(const AV1_COMMON *cm, const MACROBLOCKD *xd) { -#endif int pred_context; const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; @@ -454,14 +723,16 @@ int av1_get_pred_context_comp_ref_p1(const AV1_COMMON *cm, // 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 CONFIG_ONE_SIDED_COMPOUND // No change to bitstream +#if CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS // No change to bitstream // Code seems to assume that signbias of cm->comp_bwd_ref[0] is always 1 const int bwd_ref_sign_idx = 1; #else const int bwd_ref_sign_idx = cm->ref_frame_sign_bias[cm->comp_bwd_ref[0]]; -#endif +#endif // CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS const int fwd_ref_sign_idx = !bwd_ref_sign_idx; + (void)cm; + 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); @@ -548,13 +819,8 @@ int av1_get_pred_context_comp_ref_p1(const AV1_COMMON *cm, // // NOTE(zoeliu): The probability of ref_frame[0] is GOLDEN_FRAME, // conditioning on it is either GOLDEN or LAST3. -#if CONFIG_ONE_SIDED_COMPOUND -int av1_get_pred_context_comp_ref_p2(UNUSED const AV1_COMMON *cm, - const MACROBLOCKD *xd) { -#else int av1_get_pred_context_comp_ref_p2(const AV1_COMMON *cm, const MACROBLOCKD *xd) { -#endif int pred_context; const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; @@ -565,14 +831,16 @@ int av1_get_pred_context_comp_ref_p2(const AV1_COMMON *cm, // 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 CONFIG_ONE_SIDED_COMPOUND // No change to bitstream +#if CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS // No change to bitstream // Code seems to assume that signbias of cm->comp_bwd_ref[0] is always 1 const int bwd_ref_sign_idx = 1; #else const int bwd_ref_sign_idx = cm->ref_frame_sign_bias[cm->comp_bwd_ref[0]]; -#endif +#endif // CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS const int fwd_ref_sign_idx = !bwd_ref_sign_idx; + (void)cm; + 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); @@ -653,13 +921,8 @@ int av1_get_pred_context_comp_ref_p2(const AV1_COMMON *cm, } // Returns a context number for the given MB prediction signal -#if CONFIG_ONE_SIDED_COMPOUND -int av1_get_pred_context_comp_bwdref_p(UNUSED const AV1_COMMON *cm, - const MACROBLOCKD *xd) { -#else int av1_get_pred_context_comp_bwdref_p(const AV1_COMMON *cm, const MACROBLOCKD *xd) { -#endif int pred_context; const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; @@ -670,14 +933,16 @@ int av1_get_pred_context_comp_bwdref_p(const AV1_COMMON *cm, // The mode info data structure has a one element border above and to the // left of the entries corresponding to real macroblocks. // The prediction flags in these dummy entries are initialized to 0. -#if CONFIG_ONE_SIDED_COMPOUND // No change to bitstream +#if CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS // No change to bitstream // Code seems to assume that signbias of cm->comp_bwd_ref[0] is always 1 const int bwd_ref_sign_idx = 1; #else const int bwd_ref_sign_idx = cm->ref_frame_sign_bias[cm->comp_bwd_ref[0]]; -#endif +#endif // CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS const int fwd_ref_sign_idx = !bwd_ref_sign_idx; + (void)cm; + 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); @@ -716,8 +981,11 @@ int av1_get_pred_context_comp_bwdref_p(const AV1_COMMON *cm, a_brf == cm->comp_bwd_ref[1]) { pred_context = 1; } else { - // NOTE: Backward ref should be either BWDREF or ALTREF. +// NOTE: Backward ref should be either BWDREF or ALTREF. +#if !USE_UNI_COMP_REFS + // TODO(zoeliu): To further study the UNIDIR scenario assert(l_brf == a_brf && l_brf != cm->comp_bwd_ref[1]); +#endif // !USE_UNI_COMP_REFS pred_context = 3; } } else if (!l_comp && !a_comp) { // single/single @@ -729,8 +997,11 @@ int av1_get_pred_context_comp_bwdref_p(const AV1_COMMON *cm, } else if (l_frf == a_frf) { pred_context = 3; } else { +#if !USE_UNI_COMP_REFS + // TODO(zoeliu): To further study the UNIDIR scenario assert(l_frf != a_frf && l_frf != cm->comp_bwd_ref[1] && a_frf != cm->comp_bwd_ref[1]); +#endif // !USE_UNI_COMP_REFS pred_context = 4; } } else { // comp/single diff --git a/av1/common/pred_common.h b/av1/common/pred_common.h index 3764576e748f8e7b2414011b7d61f99631636c69..9a32815d2380f503aed9ef9528b74d3e68391045 100644 --- a/av1/common/pred_common.h +++ b/av1/common/pred_common.h @@ -108,6 +108,35 @@ static INLINE aom_cdf_prob *av1_get_reference_mode_cdf(const AV1_COMMON *cm, } #endif +#if CONFIG_EXT_COMP_REFS +int av1_get_comp_reference_type_context(const AV1_COMMON *cm, + const MACROBLOCKD *xd); + +static INLINE aom_prob av1_get_comp_reference_type_prob(const AV1_COMMON *cm, + const MACROBLOCKD *xd) { + return cm->fc + ->comp_ref_type_prob[av1_get_comp_reference_type_context(cm, xd)]; +} + +int av1_get_pred_context_uni_comp_ref_p(const AV1_COMMON *cm, + const MACROBLOCKD *xd); + +static INLINE aom_prob av1_get_pred_prob_uni_comp_ref_p(const AV1_COMMON *cm, + const MACROBLOCKD *xd) { + const int pred_context = av1_get_pred_context_uni_comp_ref_p(cm, xd); + return cm->fc->uni_comp_ref_prob[pred_context][0]; +} + +int av1_get_pred_context_uni_comp_ref_p1(const AV1_COMMON *cm, + const MACROBLOCKD *xd); + +static INLINE aom_prob +av1_get_pred_prob_uni_comp_ref_p1(const AV1_COMMON *cm, const MACROBLOCKD *xd) { + const int pred_context = av1_get_pred_context_uni_comp_ref_p1(cm, xd); + return cm->fc->uni_comp_ref_prob[pred_context][1]; +} +#endif // CONFIG_EXT_COMP_REFS + int av1_get_pred_context_comp_ref_p(const AV1_COMMON *cm, const MACROBLOCKD *xd); diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 60847fffc8cb0a375943ee3fd9b18886539bee56..39a0dc069bf03122f7aebd83075e31a02389ecd7 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -95,7 +95,7 @@ static size_t read_uncompressed_header(AV1Decoder *pbi, struct aom_read_bit_buffer *rb); static int is_compound_reference_allowed(const AV1_COMMON *cm) { -#if CONFIG_ONE_SIDED_COMPOUND // Normative in decoder +#if CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS // Normative in decoder return !frame_is_intra_only(cm); #else int i; @@ -104,7 +104,7 @@ static int is_compound_reference_allowed(const AV1_COMMON *cm) { if (cm->ref_frame_sign_bias[i + 1] != cm->ref_frame_sign_bias[1]) return 1; return 0; -#endif +#endif // CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS } static void setup_compound_reference_mode(AV1_COMMON *cm) { @@ -290,6 +290,15 @@ static void read_frame_reference_mode_probs(AV1_COMMON *cm, aom_reader *r) { #endif if (cm->reference_mode != SINGLE_REFERENCE) { +#if CONFIG_EXT_COMP_REFS + for (i = 0; i < COMP_REF_TYPE_CONTEXTS; ++i) + av1_diff_update_prob(r, &fc->comp_ref_type_prob[i], ACCT_STR); + + for (i = 0; i < UNI_COMP_REF_CONTEXTS; ++i) + for (j = 0; j < (UNIDIR_COMP_REFS - 1); ++j) + av1_diff_update_prob(r, &fc->uni_comp_ref_prob[i][j], ACCT_STR); +#endif // CONFIG_EXT_COMP_REFS + for (i = 0; i < REF_CONTEXTS; ++i) { #if CONFIG_EXT_REFS for (j = 0; j < (FWD_REFS - 1); ++j) @@ -5213,6 +5222,12 @@ static void debug_check_frame_counts(const AV1_COMMON *const cm) { #endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF assert(!memcmp(cm->counts.comp_inter, zero_counts.comp_inter, sizeof(cm->counts.comp_inter))); +#if CONFIG_EXT_COMP_REFS + assert(!memcmp(cm->counts.comp_ref_type, zero_counts.comp_ref_type, + sizeof(cm->counts.comp_ref_type))); + assert(!memcmp(cm->counts.uni_comp_ref, zero_counts.uni_comp_ref, + sizeof(cm->counts.uni_comp_ref))); +#endif // CONFIG_EXT_COMP_REFS assert(!memcmp(cm->counts.single_ref, zero_counts.single_ref, sizeof(cm->counts.single_ref))); assert(!memcmp(cm->counts.comp_ref, zero_counts.comp_ref, diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c index 246bf4e5beb3dbd8efc0fc1aebbd2dcfcbd5ecfa..a7d6693764a64d02f9fd2c4abf6cb53c0eed483c 100644 --- a/av1/decoder/decodemv.c +++ b/av1/decoder/decodemv.c @@ -1288,6 +1288,24 @@ static REFERENCE_MODE read_block_reference_mode(AV1_COMMON *cm, aom_read(r, av1_get_pred_prob_##pname(cm, xd), ACCT_STR) #endif +#if CONFIG_EXT_COMP_REFS +static REFERENCE_MODE read_comp_reference_type(AV1_COMMON *cm, + const MACROBLOCKD *xd, + aom_reader *r) { + const int ctx = av1_get_comp_reference_type_context(cm, xd); +#if USE_UNI_COMP_REFS + const COMP_REFERENCE_TYPE comp_ref_type = (COMP_REFERENCE_TYPE)aom_read( + r, cm->fc->comp_ref_type_prob[ctx], ACCT_STR); +#else // !USE_UNI_COMP_REFS + // TODO(zoeliu): Temporarily turn off uni-directional comp refs + const COMP_REFERENCE_TYPE comp_ref_type = BIDIR_COMP_REFERENCE; +#endif // USE_UNI_COMP_REFS + FRAME_COUNTS *counts = xd->counts; + if (counts) ++counts->comp_ref_type[ctx][comp_ref_type]; + return comp_ref_type; // UNIDIR_COMP_REFERENCE or BIDIR_COMP_REFERENCE +} +#endif // CONFIG_EXT_COMP_REFS + // Read the referncence frame static void read_ref_frames(AV1_COMMON *const cm, MACROBLOCKD *const xd, aom_reader *r, int segment_id, @@ -1303,15 +1321,52 @@ static void read_ref_frames(AV1_COMMON *const cm, MACROBLOCKD *const xd, const REFERENCE_MODE mode = read_block_reference_mode(cm, xd, r); // FIXME(rbultje) I'm pretty sure this breaks segmentation ref frame coding if (mode == COMPOUND_REFERENCE) { -#if CONFIG_ONE_SIDED_COMPOUND // Normative in decoder (for low delay) +#if CONFIG_EXT_COMP_REFS + const COMP_REFERENCE_TYPE comp_ref_type = + read_comp_reference_type(cm, xd, r); + +#if !USE_UNI_COMP_REFS + // TODO(zoeliu): Temporarily turn off uni-directional comp refs + assert(comp_ref_type == BIDIR_COMP_REFERENCE); +#endif // !USE_UNI_COMP_REFS + + if (comp_ref_type == UNIDIR_COMP_REFERENCE) { + const int ctx = av1_get_pred_context_uni_comp_ref_p(cm, xd); + const int bit = aom_read(r, fc->uni_comp_ref_prob[ctx][0], ACCT_STR); + if (counts) ++counts->uni_comp_ref[ctx][0][bit]; + + if (bit) { + ref_frame[0] = BWDREF_FRAME; + ref_frame[1] = ALTREF_FRAME; + } else { + const int ctx1 = av1_get_pred_context_uni_comp_ref_p1(cm, xd); + const int bit1 = + aom_read(r, fc->uni_comp_ref_prob[ctx1][1], ACCT_STR); + if (counts) ++counts->uni_comp_ref[ctx1][1][bit1]; + + if (bit1) { + ref_frame[0] = LAST_FRAME; + ref_frame[1] = GOLDEN_FRAME; + } else { + ref_frame[0] = LAST_FRAME; + ref_frame[1] = LAST2_FRAME; + } + } + + return; + } +#endif // CONFIG_EXT_COMP_REFS + +// Normative in decoder (for low delay) +#if CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS const int idx = 1; -#else +#else // !(CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS) #if CONFIG_EXT_REFS const int idx = cm->ref_frame_sign_bias[cm->comp_bwd_ref[0]]; -#else +#else // !CONFIG_EXT_REFS const int idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref]; #endif // CONFIG_EXT_REFS -#endif +#endif // CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS const int ctx = av1_get_pred_context_comp_ref_p(cm, xd); #if CONFIG_VAR_REFS @@ -2042,6 +2097,15 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); is_compound = has_second_ref(mbmi); +#if CONFIG_EXT_COMP_REFS +#if !USE_UNI_COMP_REFS + // NOTE: uni-directional comp refs disabled + if (is_compound) + assert(mbmi->ref_frame[0] < BWDREF_FRAME && + mbmi->ref_frame[1] >= BWDREF_FRAME); +#endif // !USE_UNI_COMP_REFS +#endif // CONFIG_EXT_COMP_REFS + #if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF if (!is_compound) is_singleref_comp_mode = diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index a6154432281263a8895c7e65e8da67b28482cb15..0385221c1beda0463a4b780c7c86a78c4f1addb7 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c @@ -1259,6 +1259,30 @@ static void write_ref_frames(const AV1_COMMON *cm, const MACROBLOCKD *xd, } if (is_compound) { +#if CONFIG_EXT_COMP_REFS + const COMP_REFERENCE_TYPE comp_ref_type = has_uni_comp_refs(mbmi) + ? UNIDIR_COMP_REFERENCE + : BIDIR_COMP_REFERENCE; + +#if USE_UNI_COMP_REFS + aom_write(w, comp_ref_type, av1_get_comp_reference_type_prob(cm, xd)); +#else // !USE_UNI_COMP_REFS + // NOTE: uni-directional comp refs disabled + assert(comp_ref_type == BIDIR_COMP_REFERENCE); +#endif // USE_UNI_COMP_REFS + + if (comp_ref_type == UNIDIR_COMP_REFERENCE) { + const int bit = mbmi->ref_frame[0] == BWDREF_FRAME; + aom_write(w, bit, av1_get_pred_prob_uni_comp_ref_p(cm, xd)); + if (!bit) { + const int bit1 = mbmi->ref_frame[1] == GOLDEN_FRAME; + aom_write(w, bit1, av1_get_pred_prob_uni_comp_ref_p1(cm, xd)); + } + + return; + } +#endif // CONFIG_EXT_COMP_REFS + #if CONFIG_EXT_REFS const int bit = (mbmi->ref_frame[0] == GOLDEN_FRAME || mbmi->ref_frame[0] == LAST3_FRAME); @@ -5099,6 +5123,17 @@ static uint32_t write_compressed_header(AV1_COMP *cpi, uint8_t *data) { } #endif if (cm->reference_mode != SINGLE_REFERENCE) { +#if CONFIG_EXT_COMP_REFS + for (i = 0; i < COMP_REF_TYPE_CONTEXTS; i++) + av1_cond_prob_diff_update(header_bc, &fc->comp_ref_type_prob[i], + counts->comp_ref_type[i], probwt); + + for (i = 0; i < UNI_COMP_REF_CONTEXTS; i++) + for (j = 0; j < (UNIDIR_COMP_REFS - 1); j++) + av1_cond_prob_diff_update(header_bc, &fc->uni_comp_ref_prob[i][j], + counts->uni_comp_ref[i][j], probwt); +#endif // CONFIG_EXT_COMP_REFS + for (i = 0; i < REF_CONTEXTS; i++) { #if CONFIG_EXT_REFS for (j = 0; j < (FWD_REFS - 1); j++) { diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index ddecf49e14be00c0cbf65404d4caff0c6d9b786d..7964e0349568fae4cf71e2ac2b78313cf0c65c99 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c @@ -1589,24 +1589,49 @@ static void update_stats(const AV1_COMMON *const cm, ThreadData *td, int mi_row, } if (has_second_ref(mbmi)) { +#if CONFIG_EXT_COMP_REFS + const COMP_REFERENCE_TYPE comp_ref_type = has_uni_comp_refs(mbmi) + ? UNIDIR_COMP_REFERENCE + : BIDIR_COMP_REFERENCE; +#if !USE_UNI_COMP_REFS + // TODO(zoeliu): Temporarily turn off uni-directional comp refs + assert(comp_ref_type == BIDIR_COMP_REFERENCE); +#endif // !USE_UNI_COMP_REFS + counts->comp_ref_type[av1_get_comp_reference_type_context(cm, xd)] + [comp_ref_type]++; + + if (comp_ref_type == UNIDIR_COMP_REFERENCE) { + const int bit = (ref0 == BWDREF_FRAME); + counts->uni_comp_ref[av1_get_pred_context_uni_comp_ref_p(cm, xd)][0] + [bit]++; + if (!bit) { + const int bit1 = (ref1 == GOLDEN_FRAME); + counts->uni_comp_ref[av1_get_pred_context_uni_comp_ref_p1(cm, xd)] + [1][bit1]++; + } + } else { +#endif // CONFIG_EXT_COMP_REFS #if CONFIG_EXT_REFS - const int bit = (ref0 == GOLDEN_FRAME || ref0 == LAST3_FRAME); + const int bit = (ref0 == GOLDEN_FRAME || ref0 == LAST3_FRAME); - counts->comp_ref[av1_get_pred_context_comp_ref_p(cm, xd)][0][bit]++; - if (!bit) { - counts->comp_ref[av1_get_pred_context_comp_ref_p1(cm, xd)][1] - [ref0 == LAST_FRAME]++; - } else { - counts->comp_ref[av1_get_pred_context_comp_ref_p2(cm, xd)][2] - [ref0 == GOLDEN_FRAME]++; - } + counts->comp_ref[av1_get_pred_context_comp_ref_p(cm, xd)][0][bit]++; + if (!bit) { + counts->comp_ref[av1_get_pred_context_comp_ref_p1(cm, xd)][1] + [ref0 == LAST_FRAME]++; + } else { + counts->comp_ref[av1_get_pred_context_comp_ref_p2(cm, xd)][2] + [ref0 == GOLDEN_FRAME]++; + } - counts->comp_bwdref[av1_get_pred_context_comp_bwdref_p(cm, xd)][0] - [ref1 == ALTREF_FRAME]++; + counts->comp_bwdref[av1_get_pred_context_comp_bwdref_p(cm, xd)][0] + [ref1 == ALTREF_FRAME]++; #else // !CONFIG_EXT_REFS counts->comp_ref[av1_get_pred_context_comp_ref_p(cm, xd)][0] [ref0 == GOLDEN_FRAME]++; #endif // CONFIG_EXT_REFS +#if CONFIG_EXT_COMP_REFS + } +#endif // CONFIG_EXT_COMP_REFS } else { #if CONFIG_EXT_REFS const int bit = (ref0 == ALTREF_FRAME || ref0 == BWDREF_FRAME); @@ -5062,14 +5087,14 @@ void av1_encode_frame(AV1_COMP *cpi) { // side behavior is where the ALT ref buffer has opposite sign bias to // the other two. if (!frame_is_intra_only(cm)) { -#if !CONFIG_ONE_SIDED_COMPOUND +#if !(CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS) if ((cm->ref_frame_sign_bias[ALTREF_FRAME] == cm->ref_frame_sign_bias[GOLDEN_FRAME]) || (cm->ref_frame_sign_bias[ALTREF_FRAME] == cm->ref_frame_sign_bias[LAST_FRAME])) { cpi->allow_comp_inter_inter = 0; } else { -#endif +#endif // !(CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS) cpi->allow_comp_inter_inter = 1; #if CONFIG_EXT_REFS cm->comp_fwd_ref[0] = LAST_FRAME; @@ -5082,10 +5107,11 @@ void av1_encode_frame(AV1_COMP *cpi) { cm->comp_fixed_ref = ALTREF_FRAME; cm->comp_var_ref[0] = LAST_FRAME; cm->comp_var_ref[1] = GOLDEN_FRAME; -#endif // CONFIG_EXT_REFS -#if !CONFIG_ONE_SIDED_COMPOUND // Normative in encoder +#endif // CONFIG_EXT_REFS +#if !(CONFIG_ONE_SIDED_COMPOUND || \ + CONFIG_EXT_COMP_REFS) // Normative in encoder } -#endif +#endif // !(CONFIG_ONE_SIDED_COMPOUND || CONFIG_EXT_COMP_REFS) } else { cpi->allow_comp_inter_inter = 0; } diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 589dcd988be21b005eda75d892ad3f225d98ac6b..59894eb6aed46f31592d4a3969532b68a09c7549 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c @@ -282,6 +282,53 @@ static BLOCK_SIZE select_sb_size(const AV1_COMP *const cpi) { #endif // CONFIG_EXT_PARTITION } +#ifdef CONFIG_COLLECT_REF_FRAME_STATS +static void collect_ref_frame_stats() { + AV1_COMMON *const cm = &cpi->common; + ThreadData *td = &cpi->td; + FRAME_COUNTS *const counts = td->counts; + int i, j; + + printf(" %d,", cm->frame_context_idx); + + for (i = 0; i < COMP_INTER_CONTEXTS; ++i) { + // 0: single ref i.e. !has_second_ref(mbmi) + // 1: comp ref i.e. has_second_ref(mbmi) + printf(" %u,", counts->comp_inter[i][0]); + } + + for (i = 0; i < COMP_REF_TYPE_CONTEXTS; ++i) { + // 0: UNIDIR_COMP_REFERENCE + // 1: BIDIR_COMP_REFERENCE + printf(" %u,", counts->comp_ref_type[i][0]); + } + + // {LAST, LAST2}, {LAST, GOLDEN}, and {BWDREF, ALTREF} + for (i = 0; i < UNI_COMP_REF_CONTEXTS; ++i) { + for (j = 0; j < (UNIDIR_COMP_REFS - 1); ++j) + printf(" %u,", counts->uni_comp_ref[i][j][0]); + } + + // Single ref stats + for (i = 0; i < REF_CONTEXTS; ++i) { + for (j = 0; j < (SINGLE_REFS - 1); ++j) + printf(" %u,", counts->single_ref[i][j][0]); + } + + // Comp ref stats + for (i = 0; i < REF_CONTEXTS; ++i) { + for (j = 0; j < (FWD_REFS - 1); ++j) + printf(" %u,", counts->comp_ref[i][j][0]); + } + for (i = 0; i < REF_CONTEXTS; ++i) { + for (j = 0; j < (BWD_REFS - 1); ++j) + printf(" %u,", counts->comp_bwdref[i][j][0]); + } + + printf("\n"); +} +#endif // CONFIG_COLLECT_REF_FRAME_STATS + static void setup_frame(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; // Set up entropy context depending on frame type. The decoder mandates @@ -4395,7 +4442,12 @@ static int get_ref_frame_flags(const AV1_COMP *cpi) { if (last3_is_last || last3_is_last2 || last3_is_alt) flags &= ~AOM_LAST3_FLAG; +#if CONFIG_EXT_COMP_REFS + if (gld_is_last2) flags &= ~AOM_GOLD_FLAG; + if (gld_is_last3) flags &= ~AOM_LAST3_FLAG; +#else if (gld_is_last2 || gld_is_last3) flags &= ~AOM_GOLD_FLAG; +#endif // CONFIG_EXT_COMP_REFS #if CONFIG_ONE_SIDED_COMPOUND // Changes LL & HL bitstream /* Allow biprediction between two identical frames (e.g. bwd_is_last = 1) */ diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c index 02d5bf14534431c0f2abff01853f1be94bd9e113..eb685212cbbcc226963ef332a8efc0898f6308e1 100644 --- a/av1/encoder/rd.c +++ b/av1/encoder/rd.c @@ -1058,6 +1058,12 @@ void av1_set_rd_speed_thresholds(AV1_COMP *cpi) { rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2B] += 1000; rd->thresh_mult[THR_COMP_NEAREST_NEARESTL3B] += 1000; rd->thresh_mult[THR_COMP_NEAREST_NEARESTGB] += 1000; + +#if CONFIG_EXT_COMP_REFS + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLL2] += 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLG] += 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTBA] += 1000; +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #else // CONFIG_EXT_INTER @@ -1073,6 +1079,11 @@ void av1_set_rd_speed_thresholds(AV1_COMP *cpi) { rd->thresh_mult[THR_COMP_NEARESTL2B] += 1000; rd->thresh_mult[THR_COMP_NEARESTL3B] += 1000; rd->thresh_mult[THR_COMP_NEARESTGB] += 1000; +#if CONFIG_EXT_COMP_REFS + rd->thresh_mult[THR_COMP_NEARESTLL2] += 1000; + rd->thresh_mult[THR_COMP_NEARESTLG] += 1000; + rd->thresh_mult[THR_COMP_NEARESTBA] += 1000; +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #endif // CONFIG_EXT_INTER @@ -1145,6 +1156,38 @@ void av1_set_rd_speed_thresholds(AV1_COMP *cpi) { rd->thresh_mult[THR_COMP_NEW_NEARGB] += 1700; rd->thresh_mult[THR_COMP_NEW_NEWGB] += 2000; rd->thresh_mult[THR_COMP_ZERO_ZEROGB] += 2500; + +#if CONFIG_EXT_COMP_REFS + rd->thresh_mult[THR_COMP_NEAREST_NEARLL2] += 1200; + rd->thresh_mult[THR_COMP_NEAR_NEARESTLL2] += 1200; + rd->thresh_mult[THR_COMP_NEAR_NEARLL2] += 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWLL2] += 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTLL2] += 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWLL2] += 1700; + rd->thresh_mult[THR_COMP_NEW_NEARLL2] += 1700; + rd->thresh_mult[THR_COMP_NEW_NEWLL2] += 2000; + rd->thresh_mult[THR_COMP_ZERO_ZEROLL2] += 2500; + + rd->thresh_mult[THR_COMP_NEAREST_NEARLG] += 1200; + rd->thresh_mult[THR_COMP_NEAR_NEARESTLG] += 1200; + rd->thresh_mult[THR_COMP_NEAR_NEARLG] += 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWLG] += 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTLG] += 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWLG] += 1700; + rd->thresh_mult[THR_COMP_NEW_NEARLG] += 1700; + rd->thresh_mult[THR_COMP_NEW_NEWLG] += 2000; + rd->thresh_mult[THR_COMP_ZERO_ZEROLG] += 2500; + + rd->thresh_mult[THR_COMP_NEAREST_NEARBA] += 1200; + rd->thresh_mult[THR_COMP_NEAR_NEARESTBA] += 1200; + rd->thresh_mult[THR_COMP_NEAR_NEARBA] += 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWBA] += 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTBA] += 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWBA] += 1700; + rd->thresh_mult[THR_COMP_NEW_NEARBA] += 1700; + rd->thresh_mult[THR_COMP_NEW_NEWBA] += 2000; + rd->thresh_mult[THR_COMP_ZERO_ZEROBA] += 2500; +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #else // CONFIG_EXT_INTER @@ -1169,6 +1212,15 @@ void av1_set_rd_speed_thresholds(AV1_COMP *cpi) { rd->thresh_mult[THR_COMP_NEWL3B] += 2000; rd->thresh_mult[THR_COMP_NEARGB] += 1500; rd->thresh_mult[THR_COMP_NEWGB] += 2000; + +#if CONFIG_EXT_COMP_REFS + rd->thresh_mult[THR_COMP_NEARLL2] += 1500; + rd->thresh_mult[THR_COMP_NEWLL2] += 2000; + rd->thresh_mult[THR_COMP_NEARLG] += 1500; + rd->thresh_mult[THR_COMP_NEWLG] += 2000; + rd->thresh_mult[THR_COMP_NEARBA] += 1500; + rd->thresh_mult[THR_COMP_NEWBA] += 2000; +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS rd->thresh_mult[THR_COMP_ZEROLA] += 2500; @@ -1183,6 +1235,12 @@ void av1_set_rd_speed_thresholds(AV1_COMP *cpi) { rd->thresh_mult[THR_COMP_ZEROL2B] += 2500; rd->thresh_mult[THR_COMP_ZEROL3B] += 2500; rd->thresh_mult[THR_COMP_ZEROGB] += 2500; + +#if CONFIG_EXT_COMP_REFS + rd->thresh_mult[THR_COMP_ZEROLL2] += 2500; + rd->thresh_mult[THR_COMP_ZEROLG] += 2500; + rd->thresh_mult[THR_COMP_ZEROBA] += 2500; +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #endif // CONFIG_EXT_INTER diff --git a/av1/encoder/rd.h b/av1/encoder/rd.h index 59012862d3727679dbc2f3d73987add8a8725742..c9de1cd2555c15426340feeb1ea0a6da556405c2 100644 --- a/av1/encoder/rd.h +++ b/av1/encoder/rd.h @@ -156,6 +156,11 @@ typedef enum { THR_COMP_NEAREST_NEARESTL2B, THR_COMP_NEAREST_NEARESTL3B, THR_COMP_NEAREST_NEARESTGB, +#if CONFIG_EXT_COMP_REFS + THR_COMP_NEAREST_NEARESTLL2, + THR_COMP_NEAREST_NEARESTLG, + THR_COMP_NEAREST_NEARESTBA, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #else // CONFIG_EXT_INTER @@ -171,6 +176,11 @@ typedef enum { THR_COMP_NEARESTL2B, THR_COMP_NEARESTL3B, THR_COMP_NEARESTGB, +#if CONFIG_EXT_COMP_REFS + THR_COMP_NEARESTLL2, + THR_COMP_NEARESTLG, + THR_COMP_NEARESTBA, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #endif // CONFIG_EXT_INTER @@ -253,6 +263,38 @@ typedef enum { THR_COMP_NEAR_NEWGB, THR_COMP_NEW_NEWGB, THR_COMP_ZERO_ZEROGB, + +#if CONFIG_EXT_COMP_REFS + THR_COMP_NEAR_NEARESTLL2, + THR_COMP_NEAREST_NEARLL2, + THR_COMP_NEAR_NEARLL2, + THR_COMP_NEW_NEARESTLL2, + THR_COMP_NEAREST_NEWLL2, + THR_COMP_NEW_NEARLL2, + THR_COMP_NEAR_NEWLL2, + THR_COMP_NEW_NEWLL2, + THR_COMP_ZERO_ZEROLL2, + + THR_COMP_NEAR_NEARESTLG, + THR_COMP_NEAREST_NEARLG, + THR_COMP_NEAR_NEARLG, + THR_COMP_NEW_NEARESTLG, + THR_COMP_NEAREST_NEWLG, + THR_COMP_NEW_NEARLG, + THR_COMP_NEAR_NEWLG, + THR_COMP_NEW_NEWLG, + THR_COMP_ZERO_ZEROLG, + + THR_COMP_NEAR_NEARESTBA, + THR_COMP_NEAREST_NEARBA, + THR_COMP_NEAR_NEARBA, + THR_COMP_NEW_NEARESTBA, + THR_COMP_NEAREST_NEWBA, + THR_COMP_NEW_NEARBA, + THR_COMP_NEAR_NEWBA, + THR_COMP_NEW_NEWBA, + THR_COMP_ZERO_ZEROBA, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #else // CONFIG_EXT_INTER @@ -277,6 +319,15 @@ typedef enum { THR_COMP_NEWL3B, THR_COMP_NEARGB, THR_COMP_NEWGB, + +#if CONFIG_EXT_COMP_REFS + THR_COMP_NEARLL2, + THR_COMP_NEWLL2, + THR_COMP_NEARLG, + THR_COMP_NEWLG, + THR_COMP_NEARBA, + THR_COMP_NEWBA, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS THR_COMP_ZEROLA, @@ -291,6 +342,12 @@ typedef enum { THR_COMP_ZEROL2B, THR_COMP_ZEROL3B, THR_COMP_ZEROGB, + +#if CONFIG_EXT_COMP_REFS + THR_COMP_ZEROLL2, + THR_COMP_ZEROLG, + THR_COMP_ZEROBA, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #endif // CONFIG_EXT_INTER diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index d3a46b15532ea26355ecc70012d04d89dadc75dd..a1deed62b3fbf51a9e9cb4f9300ac340aaeb0fd6 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c @@ -113,8 +113,14 @@ static const int filter_sets[DUAL_FILTER_SET_SIZE][2] = { #endif // CONFIG_EXT_REFS #if CONFIG_EXT_REFS +#if CONFIG_EXT_COMP_REFS +#define SECOND_REF_FRAME_MASK \ + ((1 << ALTREF_FRAME) | (1 << BWDREF_FRAME) | (1 << GOLDEN_FRAME) | \ + (1 << LAST2_FRAME) | 0x01) // NOLINT +#else // !CONFIG_EXT_COMP_REFS #define SECOND_REF_FRAME_MASK ((1 << ALTREF_FRAME) | (1 << BWDREF_FRAME) | 0x01) -#else +#endif // CONFIG_EXT_COMP_REFS +#else // !CONFIG_EXT_REFS #define SECOND_REF_FRAME_MASK ((1 << ALTREF_FRAME) | 0x01) #endif // CONFIG_EXT_REFS @@ -257,6 +263,12 @@ static const MODE_DEFINITION av1_mode_order[MAX_MODES] = { { NEAREST_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } }, { NEAREST_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } }, { NEAREST_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + +#if CONFIG_EXT_COMP_REFS + { NEAREST_NEARESTMV, { LAST_FRAME, LAST2_FRAME } }, + { NEAREST_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEAREST_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } }, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #else // CONFIG_EXT_INTER @@ -272,6 +284,12 @@ static const MODE_DEFINITION av1_mode_order[MAX_MODES] = { { NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } }, { NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } }, { NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + +#if CONFIG_EXT_COMP_REFS + { NEARESTMV, { LAST_FRAME, LAST2_FRAME } }, + { NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } }, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #endif // CONFIG_EXT_INTER @@ -352,9 +370,35 @@ static const MODE_DEFINITION av1_mode_order[MAX_MODES] = { { NEAR_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, { NEW_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, { ZERO_ZEROMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + +#if CONFIG_EXT_COMP_REFS + { NEAR_NEARMV, { LAST_FRAME, LAST2_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, LAST2_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, LAST2_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, LAST2_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, LAST2_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, LAST2_FRAME } }, + { ZERO_ZEROMV, { LAST_FRAME, LAST2_FRAME } }, + + { NEAR_NEARMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, + { ZERO_ZEROMV, { LAST_FRAME, GOLDEN_FRAME } }, + + { NEAR_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEW_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEAREST_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEW_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEAR_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEW_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { ZERO_ZEROMV, { BWDREF_FRAME, ALTREF_FRAME } }, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS -#else // CONFIG_EXT_INTER +#else // !CONFIG_EXT_INTER { NEARMV, { LAST_FRAME, ALTREF_FRAME } }, { NEWMV, { LAST_FRAME, ALTREF_FRAME } }, @@ -376,6 +420,15 @@ static const MODE_DEFINITION av1_mode_order[MAX_MODES] = { { NEWMV, { LAST3_FRAME, BWDREF_FRAME } }, { NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } }, { NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + +#if CONFIG_EXT_COMP_REFS + { NEARMV, { LAST_FRAME, LAST2_FRAME } }, + { NEWMV, { LAST_FRAME, LAST2_FRAME } }, + { NEARMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEARMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS { ZEROMV, { LAST_FRAME, ALTREF_FRAME } }, @@ -390,6 +443,12 @@ static const MODE_DEFINITION av1_mode_order[MAX_MODES] = { { ZEROMV, { LAST2_FRAME, BWDREF_FRAME } }, { ZEROMV, { LAST3_FRAME, BWDREF_FRAME } }, { ZEROMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + +#if CONFIG_EXT_COMP_REFS + { ZEROMV, { LAST_FRAME, LAST2_FRAME } }, + { ZEROMV, { LAST_FRAME, GOLDEN_FRAME } }, + { ZEROMV, { BWDREF_FRAME, ALTREF_FRAME } }, +#endif // CONFIG_EXT_COMP_REFS #endif // CONFIG_EXT_REFS #endif // CONFIG_EXT_INTER @@ -5566,17 +5625,29 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, #endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF } -static void estimate_ref_frame_costs(const AV1_COMMON *cm, - const MACROBLOCKD *xd, int segment_id, - unsigned int *ref_costs_single, - unsigned int *ref_costs_comp, - aom_prob *comp_mode_p) { +static void estimate_ref_frame_costs( + const AV1_COMMON *cm, const MACROBLOCKD *xd, int segment_id, + unsigned int *ref_costs_single, +#if CONFIG_EXT_COMP_REFS + unsigned int (*ref_costs_comp)[TOTAL_REFS_PER_FRAME], +#else + unsigned int *ref_costs_comp, +#endif // CONFIG_EXT_COMP_REFS + aom_prob *comp_mode_p) { int seg_ref_active = segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME); if (seg_ref_active) { memset(ref_costs_single, 0, TOTAL_REFS_PER_FRAME * sizeof(*ref_costs_single)); +#if CONFIG_EXT_COMP_REFS + int ref_frame; + for (ref_frame = 0; ref_frame < TOTAL_REFS_PER_FRAME; ++ref_frame) + memset(ref_costs_comp[ref_frame], 0, + TOTAL_REFS_PER_FRAME * sizeof((*ref_costs_comp)[0])); +#else memset(ref_costs_comp, 0, TOTAL_REFS_PER_FRAME * sizeof(*ref_costs_comp)); +#endif // CONFIG_EXT_COMP_REFS + *comp_mode_p = 128; } else { aom_prob intra_inter_p = av1_get_intra_inter_prob(cm, xd); @@ -5696,6 +5767,57 @@ static void estimate_ref_frame_costs(const AV1_COMMON *cm, unsigned int base_cost = av1_cost_bit(intra_inter_p, 1); +#if CONFIG_EXT_COMP_REFS + aom_prob comp_ref_type_p = av1_get_comp_reference_type_prob(cm, xd); + unsigned int ref_bicomp_costs[TOTAL_REFS_PER_FRAME] = { 0 }; + + ref_bicomp_costs[LAST_FRAME] = ref_bicomp_costs[LAST2_FRAME] = + ref_bicomp_costs[LAST3_FRAME] = ref_bicomp_costs[GOLDEN_FRAME] = +#if USE_UNI_COMP_REFS + base_cost + av1_cost_bit(comp_ref_type_p, 1); +#else + base_cost; +#endif // USE_UNI_COMP_REFS + ref_bicomp_costs[BWDREF_FRAME] = ref_bicomp_costs[ALTREF_FRAME] = 0; + + ref_bicomp_costs[LAST_FRAME] += av1_cost_bit(ref_comp_p, 0); + ref_bicomp_costs[LAST2_FRAME] += av1_cost_bit(ref_comp_p, 0); + ref_bicomp_costs[LAST3_FRAME] += av1_cost_bit(ref_comp_p, 1); + ref_bicomp_costs[GOLDEN_FRAME] += av1_cost_bit(ref_comp_p, 1); + + ref_bicomp_costs[LAST_FRAME] += av1_cost_bit(ref_comp_p1, 1); + ref_bicomp_costs[LAST2_FRAME] += av1_cost_bit(ref_comp_p1, 0); + + ref_bicomp_costs[LAST3_FRAME] += av1_cost_bit(ref_comp_p2, 0); + ref_bicomp_costs[GOLDEN_FRAME] += av1_cost_bit(ref_comp_p2, 1); + + ref_bicomp_costs[BWDREF_FRAME] += av1_cost_bit(bwdref_comp_p, 0); + ref_bicomp_costs[ALTREF_FRAME] += av1_cost_bit(bwdref_comp_p, 1); + + int ref0; + for (ref0 = LAST_FRAME; ref0 <= GOLDEN_FRAME; ++ref0) { + ref_costs_comp[ref0][BWDREF_FRAME] = + ref_bicomp_costs[ref0] + ref_bicomp_costs[BWDREF_FRAME]; + ref_costs_comp[ref0][ALTREF_FRAME] = + ref_bicomp_costs[ref0] + ref_bicomp_costs[ALTREF_FRAME]; + } + + aom_prob uni_comp_ref_p = av1_get_pred_prob_uni_comp_ref_p(cm, xd); + aom_prob uni_comp_ref_p1 = av1_get_pred_prob_uni_comp_ref_p1(cm, xd); + + ref_costs_comp[LAST_FRAME][LAST2_FRAME] = + base_cost + av1_cost_bit(comp_ref_type_p, 0) + + av1_cost_bit(uni_comp_ref_p, 0) + av1_cost_bit(uni_comp_ref_p1, 0); + ref_costs_comp[LAST_FRAME][GOLDEN_FRAME] = + base_cost + av1_cost_bit(comp_ref_type_p, 0) + + av1_cost_bit(uni_comp_ref_p, 0) + av1_cost_bit(uni_comp_ref_p1, 1); + + ref_costs_comp[BWDREF_FRAME][ALTREF_FRAME] = + base_cost + av1_cost_bit(comp_ref_type_p, 0) + + av1_cost_bit(uni_comp_ref_p, 1); + +#else // !CONFIG_EXT_COMP_REFS + ref_costs_comp[LAST_FRAME] = #if CONFIG_EXT_REFS ref_costs_comp[LAST2_FRAME] = ref_costs_comp[LAST3_FRAME] = @@ -5754,7 +5876,18 @@ static void estimate_ref_frame_costs(const AV1_COMMON *cm, ref_costs_comp[LAST_FRAME] += av1_cost_bit(ref_comp_p, 0); ref_costs_comp[GOLDEN_FRAME] += av1_cost_bit(ref_comp_p, 1); #endif // CONFIG_EXT_REFS +#endif // CONFIG_EXT_COMP_REFS } else { +#if CONFIG_EXT_COMP_REFS + int ref0; + for (ref0 = LAST_FRAME; ref0 <= GOLDEN_FRAME; ++ref0) { + ref_costs_comp[ref0][BWDREF_FRAME] = 512; + ref_costs_comp[ref0][ALTREF_FRAME] = 512; + } + ref_costs_comp[LAST_FRAME][LAST2_FRAME] = 512; + ref_costs_comp[LAST_FRAME][GOLDEN_FRAME] = 512; + ref_costs_comp[BWDREF_FRAME][ALTREF_FRAME] = 512; +#else // !CONFIG_EXT_COMP_REFS ref_costs_comp[LAST_FRAME] = 512; #if CONFIG_EXT_REFS ref_costs_comp[LAST2_FRAME] = 512; @@ -5763,6 +5896,7 @@ static void estimate_ref_frame_costs(const AV1_COMMON *cm, ref_costs_comp[ALTREF_FRAME] = 512; #endif // CONFIG_EXT_REFS ref_costs_comp[GOLDEN_FRAME] = 512; +#endif // CONFIG_EXT_COMP_REFS } } } @@ -9084,7 +9218,11 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, int best_mode_skippable = 0; int midx, best_mode_index = -1; unsigned int ref_costs_single[TOTAL_REFS_PER_FRAME]; +#if CONFIG_EXT_COMP_REFS + unsigned int ref_costs_comp[TOTAL_REFS_PER_FRAME][TOTAL_REFS_PER_FRAME]; +#else unsigned int ref_costs_comp[TOTAL_REFS_PER_FRAME]; +#endif // CONFIG_EXT_COMP_REFS aom_prob comp_mode_p; int64_t best_intra_rd = INT64_MAX; unsigned int best_pred_sse = UINT_MAX; @@ -9304,6 +9442,10 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, // Skip checking missing references in both single and compound reference // modes. Note that a mode will be skipped iff both reference frames // are masked out. +#if CONFIG_EXT_COMP_REFS + ref_frame_skip_mask[0] |= (1 << ref_frame); + ref_frame_skip_mask[1] |= SECOND_REF_FRAME_MASK; +#else // !CONFIG_EXT_COMP_REFS #if CONFIG_EXT_REFS if (ref_frame == BWDREF_FRAME || ref_frame == ALTREF_FRAME) { ref_frame_skip_mask[0] |= (1 << ref_frame); @@ -9315,6 +9457,7 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, #if CONFIG_EXT_REFS } #endif // CONFIG_EXT_REFS +#endif // CONFIG_EXT_COMP_REFS } else { for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) { // Skip fixed mv modes for poor references @@ -9537,6 +9680,34 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, (ref_frame_skip_mask[1] & (1 << AOMMAX(0, second_ref_frame)))) continue; +#if CONFIG_EXT_COMP_REFS +// TODO(zoeliu): Following toggle between #if 0/1 and the bug will manifest +// itself. +#if 0 + if (!(cpi->ref_frame_flags & flag_list[ref_frame]) || + (second_ref_frame > INTRA_FRAME && + (!(cpi->ref_frame_flags & flag_list[second_ref_frame])))) + printf("Frame=%d, bsize=%d, (mi_row,mi_col)=(%d,%d), ref_frame=%d, " + "second_ref_frame=%d\n", cm->current_video_frame, bsize, mi_row, + mi_col, ref_frame, second_ref_frame); + + if (!(cpi->ref_frame_flags & flag_list[ref_frame])) continue; + if (second_ref_frame > INTRA_FRAME && + (!(cpi->ref_frame_flags & flag_list[second_ref_frame]))) + continue; +#endif // 0 + +#if !USE_UNI_COMP_REFS + // NOTE(zoeliu): Temporarily disable uni-directional comp refs + if (second_ref_frame > INTRA_FRAME) { + if (!((ref_frame < BWDREF_FRAME) ^ (second_ref_frame < BWDREF_FRAME))) + continue; + } + assert(second_ref_frame <= INTRA_FRAME || + ((ref_frame < BWDREF_FRAME) ^ (second_ref_frame < BWDREF_FRAME))); +#endif // !USE_UNI_COMP_REFS +#endif // CONFIG_EXT_COMP_REFS + if (mode_skip_mask[ref_frame] & (1 << this_mode)) continue; // Test best rd so far against threshold for trying this mode. @@ -10258,10 +10429,14 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, // Estimate the reference frame signaling cost and add it // to the rolling cost variable. if (comp_pred) { +#if CONFIG_EXT_COMP_REFS + rate2 += ref_costs_comp[ref_frame][second_ref_frame]; +#else // !CONFIG_EXT_COMP_REFS rate2 += ref_costs_comp[ref_frame]; #if CONFIG_EXT_REFS rate2 += ref_costs_comp[second_ref_frame]; #endif // CONFIG_EXT_REFS +#endif // CONFIG_EXT_COMP_REFS } else { rate2 += ref_costs_single[ref_frame]; } @@ -10981,7 +11156,11 @@ void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi, int i; int64_t best_pred_diff[REFERENCE_MODES]; unsigned int ref_costs_single[TOTAL_REFS_PER_FRAME]; +#if CONFIG_EXT_COMP_REFS + unsigned int ref_costs_comp[TOTAL_REFS_PER_FRAME][TOTAL_REFS_PER_FRAME]; +#else unsigned int ref_costs_comp[TOTAL_REFS_PER_FRAME]; +#endif // CONFIG_EXT_COMP_REFS aom_prob comp_mode_p; InterpFilter best_filter = SWITCHABLE; int64_t this_rd = INT64_MAX; diff --git a/configure b/configure index 0f511ed175a013a8eca753072dc9b15877606a0c..f59bf050ea28d61eca41a600147996318591af04 100755 --- a/configure +++ b/configure @@ -317,6 +317,7 @@ EXPERIMENT_LIST=" compound_singleref aom_qm one_sided_compound + ext_comp_refs smooth_hv var_refs rect_intra_pred