Commit 6ff3eb16 authored by Paul Wilkins's avatar Paul Wilkins
Browse files

New inter mode context.

This patch creates a new inter mode contest that avoids
a dependence on the reconstructed motion vectors from
neighboring blocks. This was a change requested by
a hardware vendor to improve decode performance.

As part of this change I have also made some modifications
to stats output code (under a flag) to allow accumulation of
inter mode context flags over multiple clips

Some further changes will be required to accommodate the
deprecation of the split mv mode over the next few days.

Performance as stands is around -0.25% on derf and
std-hd but up on the YT and YT-HD sets. With further tuning
or some adjustment to the context criteria it should be
possible to make this change broadly neutral.

Change-Id: Ia15cb4470969b9e87332a59c546ae0bd40676f6c
parent 18e07420
......@@ -12,11 +12,11 @@
#include "vp9/common/vp9_entropy.h"
const int vp9_default_mode_contexts[INTER_MODE_CONTEXTS][4] = {
{1, 223, 1, 237}, // 0,0 best: Only candidate
{87, 166, 26, 219}, // 0,0 best: non zero candidates
{89, 67, 18, 125}, // 0,0 best: non zero candidates, split
{16, 141, 69, 226}, // strong nz candidate(s), no split
{35, 122, 14, 227}, // weak nz candidate(s), no split
{14, 122, 22, 164}, // strong nz candidate(s), split
{16, 70, 9, 183}, // weak nz candidate(s), split
{2, 173, 34, 229}, // 0 = both zero mv
{7, 145, 85, 225}, // 1 = one zero mv + one a predicted mv
{7, 166, 63, 231}, // 2 = two predicted mvs
{7, 94, 66, 219}, // 3 = one predicted/zero and one new mv
{8, 64, 46, 213}, // 4 = two new mvs
{17, 81, 31, 231}, // 5 = one intra neighbour + x
{25, 29, 30, 246}, // 6 = two intra neighbours
};
......@@ -165,6 +165,10 @@ void vp9_find_mv_refs(VP9_COMMON *cm, MACROBLOCKD *xd, MODE_INFO *here,
int split_count = 0;
int (*mv_ref_search)[2];
const int mi_col = get_mi_col(xd);
int intra_count = 0;
int zero_count = 0;
int newmv_count = 0;
// Blank the reference vector lists and other local structures.
vpx_memset(mv_ref_list, 0, sizeof(int_mv) * MAX_MV_REF_CANDIDATES);
vpx_memset(candidate_scores, 0, sizeof(candidate_scores));
......@@ -196,9 +200,24 @@ void vp9_find_mv_refs(VP9_COMMON *cm, MACROBLOCKD *xd, MODE_INFO *here,
&refmv_count, c_refmv, 16);
}
split_count += (candidate_mi->mbmi.mode == SPLITMV);
// Count number of neihgbours coded intra and zeromv
intra_count += (candidate_mi->mbmi.mode < NEARESTMV);
zero_count += (candidate_mi->mbmi.mode == ZEROMV);
newmv_count += (candidate_mi->mbmi.mode >= NEWMV);
}
}
// If at this stage wwe have a 0 vector and a non zero vector from the
// correct reference frame then make sure that the non zero one is given
// precedence as we have other options for coding 0,0
/* if (refmv_count == MAX_MV_REF_CANDIDATES) {
if (mv_ref_list[1].as_int && !mv_ref_list[0].as_int) {
mv_ref_list[0].as_int = mv_ref_list[1].as_int;
mv_ref_list[1].as_int = 0;
}
} */
// More distant neigbours
for (i = 2; (i < MVREF_NEIGHBOURS) &&
(refmv_count < MAX_MV_REF_CANDIDATES); ++i) {
......@@ -278,24 +297,21 @@ void vp9_find_mv_refs(VP9_COMMON *cm, MACROBLOCKD *xd, MODE_INFO *here,
}
}
// Define inter mode coding context.
// 0,0 was best
if (mv_ref_list[0].as_int == 0) {
// 0,0 is only candidate
if (refmv_count <= 1) {
mbmi->mb_mode_context[ref_frame] = 0;
// non zero candidates candidates available
} else if (split_count == 0) {
mbmi->mb_mode_context[ref_frame] = 1;
if (!intra_count) {
if (!newmv_count) {
// 0 = both zero mv
// 1 = one zero mv + one a predicted mv
// 2 = two predicted mvs
mbmi->mb_mode_context[ref_frame] = 2 - zero_count;
} else {
mbmi->mb_mode_context[ref_frame] = 2;
// 3 = one predicted/zero and one new mv
// 4 = two new mvs
mbmi->mb_mode_context[ref_frame] = 2 + newmv_count;
}
} else if (split_count == 0) {
// Non zero best, No Split MV cases
mbmi->mb_mode_context[ref_frame] = candidate_scores[0] >= 16 ? 3 : 4;
} else {
// Non zero best, some split mv
mbmi->mb_mode_context[ref_frame] = candidate_scores[0] >= 16 ? 5 : 6;
// 5 = one intra neighbour + x
// 6 = two intra neighbours
mbmi->mb_mode_context[ref_frame] = 4 + intra_count;
}
// Clamp vectors
......
......@@ -826,9 +826,9 @@ static void write_mb_modes_kf(const VP9_COMP *cpi,
left_block_mode(m, i) : B_DC_PRED;
const int bm = m->bmi[i].as_mode.first;
#ifdef ENTROPY_STATS
/*#ifdef ENTROPY_STATS
++intra_mode_stats [A] [L] [bm];
#endif
#endif*/
write_kf_bmode(bc, bm, c->kf_bmode_prob[a][l]);
} while (++i < 4);
}
......
......@@ -2430,32 +2430,3 @@ int vp9_refining_search_8p_c(MACROBLOCK *x,
}
}
#endif // CONFIG_COMP_INTER_JOINT_SEARCH
#ifdef ENTROPY_STATS
void print_mode_context(VP9_COMMON *pc) {
FILE *f = fopen("vp9_modecont.c", "a");
int i, j;
fprintf(f, "#include \"vp9_entropy.h\"\n");
fprintf(f, "const int vp9_mode_contexts[INTER_MODE_CONTEXTS][4] =");
fprintf(f, "{\n");
for (j = 0; j < INTER_MODE_CONTEXTS; j++) {
fprintf(f, " {/* %d */ ", j);
fprintf(f, " ");
for (i = 0; i < 4; i++) {
int this_prob;
// context probs
this_prob = get_binary_prob(pc->fc.mv_ref_ct[j][i][0],
pc->fc.mv_ref_ct[j][i][1]);
fprintf(f, "%5d, ", this_prob);
}
fprintf(f, " },\n");
}
fprintf(f, "};\n");
fclose(f);
}
#endif/* END MV ref count ENTROPY_STATS stats code */
......@@ -15,10 +15,6 @@
#include "vp9/encoder/vp9_block.h"
#include "vp9/encoder/vp9_variance.h"
#ifdef ENTROPY_STATS
void print_mode_context(VP9_COMMON *pc);
#endif
// The maximum number of steps in a step search given the largest
// allowed initial step
#define MAX_MVSEARCH_STEPS 11
......
......@@ -533,6 +533,66 @@ static void configure_implicit_segmentation(VP9_COMP *cpi, int frame_qindex) {
}
#endif
#ifdef ENTROPY_STATS
void vp9_update_mode_context_stats(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
int i, j;
unsigned int (*mv_ref_ct)[4][2] = cm->fc.mv_ref_ct;
int64_t (*mv_ref_stats)[4][2] = cpi->mv_ref_stats;
FILE *f;
// Read the past stats counters
f = fopen("mode_context.bin", "rb");
if (!f) {
vpx_memset(cpi->mv_ref_stats, 0, sizeof(cpi->mv_ref_stats));
} else {
fread(cpi->mv_ref_stats, sizeof(cpi->mv_ref_stats), 1, f);
fclose(f);
}
// Add in the values for this frame
for (i = 0; i < INTER_MODE_CONTEXTS; i++) {
for (j = 0; j < 4; j++) {
mv_ref_stats[i][j][0] += (int64_t)mv_ref_ct[i][j][0];
mv_ref_stats[i][j][1] += (int64_t)mv_ref_ct[i][j][1];
}
}
// Write back the accumulated stats
f = fopen("mode_context.bin", "wb");
fwrite(cpi->mv_ref_stats, sizeof(cpi->mv_ref_stats), 1, f);
fclose(f);
}
void print_mode_context(VP9_COMP *cpi) {
FILE *f = fopen("vp9_modecont.c", "a");
int i, j;
fprintf(f, "#include \"vp9_entropy.h\"\n");
fprintf(f, "const int vp9_mode_contexts[INTER_MODE_CONTEXTS][4] =");
fprintf(f, "{\n");
for (j = 0; j < INTER_MODE_CONTEXTS; j++) {
fprintf(f, " {/* %d */ ", j);
fprintf(f, " ");
for (i = 0; i < 4; i++) {
int this_prob;
int64_t count = cpi->mv_ref_stats[j][i][0] + cpi->mv_ref_stats[j][i][1];
if (count)
this_prob = ((cpi->mv_ref_stats[j][i][0] * 256) + (count >> 1)) / count;
else
this_prob = 128;
// context probs
fprintf(f, "%5d, ", this_prob);
}
fprintf(f, " },\n");
}
fprintf(f, "};\n");
fclose(f);
}
#endif // ENTROPY_STATS
// DEBUG: Print out the segment id of each MB in the current frame.
static void print_seg_map(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
......@@ -1646,7 +1706,7 @@ void vp9_remove_compressor(VP9_PTR *ptr) {
if (cpi->pass != 1) {
print_context_counters();
print_tree_update_probs();
print_mode_context(&cpi->common);
print_mode_context(cpi);
}
#endif
#ifdef NMV_STATS
......@@ -3239,6 +3299,10 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
}
}
#ifdef ENTROPY_STATS
vp9_update_mode_context_stats(cpi);
#endif
/* Move storing frame_type out of the above loop since it is also
* needed in motion search besides loopfilter */
cm->last_frame_type = cm->frame_type;
......
......@@ -621,6 +621,10 @@ typedef struct VP9_COMP {
int this_frame_weight;
int max_arf_level;
#endif
#ifdef ENTROPY_STATS
int64_t mv_ref_stats[INTER_MODE_CONTEXTS][4][2];
#endif
} VP9_COMP;
void vp9_encode_frame(VP9_COMP *cpi);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment