From: Paul Wilkins Date: Thu, 16 May 2013 10:27:12 +0000 (+0100) Subject: New inter mode context. X-Git-Tag: v1.3.0~1104^2~175^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6ff3eb1647c68c9afcd2e57f184eea5f3d369d57;p=libvpx 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 --- diff --git a/vp9/common/vp9_modecont.c b/vp9/common/vp9_modecont.c index 73cb5e15e..86a8fb850 100644 --- a/vp9/common/vp9_modecont.c +++ b/vp9/common/vp9_modecont.c @@ -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 }; diff --git a/vp9/common/vp9_mvref_common.c b/vp9/common/vp9_mvref_common.c index 3f18c6961..fa84ce6bd 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -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 diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 398545136..fbdee35f9 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -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); } diff --git a/vp9/encoder/vp9_mcomp.c b/vp9/encoder/vp9_mcomp.c index aff5637e1..75e6e6757 100644 --- a/vp9/encoder/vp9_mcomp.c +++ b/vp9/encoder/vp9_mcomp.c @@ -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 */ diff --git a/vp9/encoder/vp9_mcomp.h b/vp9/encoder/vp9_mcomp.h index cdbd29aa5..33e688b97 100644 --- a/vp9/encoder/vp9_mcomp.h +++ b/vp9/encoder/vp9_mcomp.h @@ -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 diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 67d1b67fc..86d32ea2f 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -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; diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_onyx_int.h index aba4c0e64..9a94f3be5 100644 --- a/vp9/encoder/vp9_onyx_int.h +++ b/vp9/encoder/vp9_onyx_int.h @@ -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);