shithub: libvpx

Download patch

ref: 6ff3eb1647c68c9afcd2e57f184eea5f3d369d57
parent: 18e07420a27fadd37a2d864bdec539123a8dbcec
author: Paul Wilkins <[email protected]>
date: Thu May 16 07:27:12 EDT 2013

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

--- 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
 };
--- a/vp9/common/vp9_mvref_common.c
+++ b/vp9/common/vp9_mvref_common.c
@@ -165,6 +165,10 @@
   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 @@
                          &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 @@
     }
   }
 
-  // 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
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -826,9 +826,9 @@
                                   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);
   }
--- a/vp9/encoder/vp9_mcomp.c
+++ b/vp9/encoder/vp9_mcomp.c
@@ -2430,32 +2430,3 @@
   }
 }
 #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 */
--- 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
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -533,6 +533,66 @@
 }
 #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 @@
     if (cpi->pass != 1) {
       print_context_counters();
       print_tree_update_probs();
-      print_mode_context(&cpi->common);
+      print_mode_context(cpi);
     }
 #endif
 #ifdef NMV_STATS
@@ -3238,6 +3298,10 @@
       vp9_adapt_nmv_probs(&cpi->common, cpi->mb.e_mbd.allow_high_precision_mv);
     }
   }
+
+#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 */
--- a/vp9/encoder/vp9_onyx_int.h
+++ b/vp9/encoder/vp9_onyx_int.h
@@ -621,6 +621,10 @@
   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);