Commit c082bbcb authored by Zoe Liu's avatar Zoe Liu

Add new coding tool of ext-comp-refs

The tool of ext-comp-refs adds the uni-directional compound reference
prediction. In details, 3 pairs of uni-direcitonal compound references
are added for the comp ref prediction:
(LAST_FRAME, LAST2_FRAME),
(LAST_FRAME, GOLDEN_FRAME), and
(BWDREF_FRAME, ALTREF_FRAME).

This new tool of ext-comp-refs will eventually overwrite
one-side-compound and have the two coding tools to merge to one.

It achieves -0.35 ~ -0.55% coding gains in BDRate, compared against
AV1 baseline with the default experiments on, but without
one-sided-compound. It achieves -0.2% ~ -0.3% coding gains when
one-sided-compound is on. It achieves larger gains on higher
resolution.

Change-Id: Icbdb16e97b96aaebaf2213f5f72d5331e2e358eb
parent 0c634c70
......@@ -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);
......
......@@ -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++)
......
......@@ -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];
......
......@@ -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)
......
......@@ -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
......
This diff is collapsed.
......@@ -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);
......
......@@ -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,
......
......@@ -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 =
......
......@@ -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++) {
......
......@@ -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;
}
......
......@@ -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) */
......
......@@ -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
......
......@@ -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