shithub: libvpx

Download patch

ref: 08f0c7cc9c1e285c33711384834e7a3baf26bd7c
parent: de52948665bf83537dd29b8697bed0dfa5390daf
author: Deb Mukherjee <debargha@google.com>
date: Tue Nov 27 10:51:06 EST 2012

New previous coef context experiment

Adds an experiment to derive the previous context of a coefficient
not just from the previous coefficient in the scan order but from a
combination of several neighboring coefficients previously encountered
in scan order.  A precomputed table of neighbors for each location
for each scan type and block size is used. Currently 5 neighbors are
used.

Results are about 0.2% positive using a strategy where the max coef
magnitude from the 5 neigbors is used to derive the context.

Change-Id: Ie708b54d8e1898af742846ce2d1e2b0d89fd4ad5

--- a/configure
+++ b/configure
@@ -250,6 +250,7 @@
     tx32x32
     dwt32x32hybrid
     cnvcontext
+    newcoefcontext
 "
 CONFIG_LIST="
     external_build
--- a/vp9/common/vp9_alloccommon.c
+++ b/vp9/common/vp9_alloccommon.c
@@ -220,4 +220,8 @@
   vp9_entropy_mode_init();
 
   vp9_entropy_mv_init();
+
+#if CONFIG_NEWCOEFCONTEXT
+  vp9_init_neighbors();
+#endif
 }
--- a/vp9/common/vp9_entropy.c
+++ b/vp9/common/vp9_entropy.c
@@ -62,6 +62,7 @@
   2, 6, 10, 14,
   3, 7, 11, 15
 };
+
 DECLARE_ALIGNED(16, const int, vp9_row_scan_4x4[16]) = {
   0,   1,  2,  3,
   4,   5,  6,  7,
@@ -69,16 +70,16 @@
   12, 13, 14, 15
 };
 
-
 DECLARE_ALIGNED(64, const int, vp9_coef_bands_8x8[64]) = { 0, 1, 2, 3, 5, 4, 4, 5,
-                                                           5, 3, 6, 3, 5, 4, 6, 6,
-                                                           6, 5, 5, 6, 6, 6, 6, 6,
-                                                           6, 6, 6, 6, 6, 6, 6, 6,
-                                                           6, 6, 6, 6, 7, 7, 7, 7,
-                                                           7, 7, 7, 7, 7, 7, 7, 7,
-                                                           7, 7, 7, 7, 7, 7, 7, 7,
-                                                           7, 7, 7, 7, 7, 7, 7, 7
-                                                         };
+  5, 3, 6, 3, 5, 4, 6, 6,
+  6, 5, 5, 6, 6, 6, 6, 6,
+  6, 6, 6, 6, 6, 6, 6, 6,
+  6, 6, 6, 6, 7, 7, 7, 7,
+  7, 7, 7, 7, 7, 7, 7, 7,
+  7, 7, 7, 7, 7, 7, 7, 7,
+  7, 7, 7, 7, 7, 7, 7, 7
+};
+
 DECLARE_ALIGNED(64, const int, vp9_default_zig_zag1d_8x8[64]) = {
   0,  1,  8, 16,  9,  2,  3, 10, 17, 24, 32, 25, 18, 11,  4,  5,
   12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13,  6,  7, 14, 21, 28,
@@ -118,17 +119,17 @@
   25,  10,  11,  26,  41,  56,  71,  86,
   101, 116, 131, 146, 161, 176, 192, 177,
   162, 147, 132, 117, 102,  87,  72,  57,
-  42,  27,  12,  13,  28,  43,  58,  73,
+  42,  27,  12,  13,  28,  43,  58, 73,
   88, 103, 118, 133, 148, 163, 178, 193,
   208, 224, 209, 194, 179, 164, 149, 134,
   119, 104,  89,  74,  59,  44,  29,  14,
-  15,  30,  45,  60,  75,  90, 105, 120,
+  15,  30, 45,  60,  75,  90, 105, 120,
   135, 150, 165, 180, 195, 210, 225, 240,
   241, 226, 211, 196, 181, 166, 151, 136,
   121, 106,  91,  76,  61,  46,  31,  47,
-  62,  77,  92, 107, 122, 137, 152, 167,
+  62,  77, 92, 107, 122, 137, 152, 167,
   182, 197, 212, 227, 242, 243, 228, 213,
-  198, 183, 168, 153, 138, 123, 108,  93,
+  198, 183, 168, 153, 138, 123, 108, 93,
   78,  63,  79,  94, 109, 124, 139, 154,
   169, 184, 199, 214, 229, 244, 245, 230,
   215, 200, 185, 170, 155, 140, 125, 110,
@@ -530,6 +531,152 @@
 
 #include "vp9/common/vp9_default_coef_probs.h"
 
+#if CONFIG_NEWCOEFCONTEXT
+
+// Neighborhood 5-tuples for various scans and blocksizes,
+// in {top, left, topleft, topright, bottomleft} order
+// for each position in raster scan order.
+// -1 indicates the neighbor does not exist.
+DECLARE_ALIGNED(16, int,
+                vp9_default_zig_zag1d_4x4_neighbors[16 * MAX_NEIGHBORS]);
+DECLARE_ALIGNED(16, int,
+                vp9_col_scan_4x4_neighbors[16 * MAX_NEIGHBORS]);
+DECLARE_ALIGNED(16, int,
+                vp9_row_scan_4x4_neighbors[16 * MAX_NEIGHBORS]);
+DECLARE_ALIGNED(16, int,
+                vp9_default_zig_zag1d_8x8_neighbors[64 * MAX_NEIGHBORS]);
+DECLARE_ALIGNED(16, int,
+                vp9_default_zig_zag1d_16x16_neighbors[256 * MAX_NEIGHBORS]);
+#if CONFIG_TX32X32 && CONFIG_SUPERBLOCKS
+DECLARE_ALIGNED(16, int,
+                vp9_default_zig_zag1d_32x32_neighbors[1024 * MAX_NEIGHBORS]);
+#endif
+
+static int find_in_scan(const int *scan, int l, int m) {
+  int i, l2 = l * l;
+  for (i = 0; i < l2; ++i) {
+    if (scan[i] == m)
+      return i;
+  }
+  return -1;
+}
+
+static void init_scan_neighbors(const int *scan, int l, int *neighbors) {
+  int l2 = l * l;
+  int m, n, i, j, k;
+  for (n = 0; n < l2; ++n) {
+    int locn = find_in_scan(scan, l, n);
+    int z = -1;
+    i = n / l;
+    j = n % l;
+    for (k = 0; k < MAX_NEIGHBORS; ++k)
+      neighbors[MAX_NEIGHBORS * n + k] = -1;
+    if (i - 1 >= 0) {
+      m = (i - 1) * l + j;
+      if (find_in_scan(scan, l, m) < locn) {
+        neighbors[MAX_NEIGHBORS * n] = m;
+        if (m == 0) z = 0;
+      }
+    }
+    if (j - 1 >= 0) {
+      m = i * l + j - 1;
+      if (find_in_scan(scan, l, m) < locn) {
+        neighbors[MAX_NEIGHBORS * n + 1] = m;
+        if (m == 0) z = 1;
+      }
+    }
+    if (i - 1 >= 0 && j - 1 >= 0) {
+      m = (i - 1) * l + j - 1;
+      if (find_in_scan(scan, l, m) < locn) {
+        neighbors[MAX_NEIGHBORS * n + 2] = m;
+        if (m == 0) z = 2;
+      }
+    }
+    if (i - 1 >= 0 && j + 1 < l) {
+      m = (i - 1) * l + j + 1;
+      if (find_in_scan(scan, l, m) < locn) {
+        neighbors[MAX_NEIGHBORS * n + 3] = m;
+        if (m == 0) z = 3;
+      }
+    }
+    if (i + 1 < l && j - 1 >= 0) {
+       m = (i + 1) * l + j - 1;
+      if (find_in_scan(scan, l, m) < locn) {
+        neighbors[MAX_NEIGHBORS * n + 4] = m;
+        if (m == 0) z = 4;
+      }
+    }
+    if (z != -1) {  // zero exists
+      int v = 0;
+      for (k = 0; k < MAX_NEIGHBORS; ++k)
+        v += (neighbors[MAX_NEIGHBORS * n + k] > 0);
+      if (v) {
+        neighbors[MAX_NEIGHBORS * n + z] = -1;
+      }
+    }
+  }
+}
+
+void vp9_init_neighbors() {
+  init_scan_neighbors(vp9_default_zig_zag1d_4x4, 4,
+                      vp9_default_zig_zag1d_4x4_neighbors);
+  init_scan_neighbors(vp9_row_scan_4x4, 4,
+                      vp9_row_scan_4x4_neighbors);
+  init_scan_neighbors(vp9_col_scan_4x4, 4,
+                      vp9_col_scan_4x4_neighbors);
+  init_scan_neighbors(vp9_default_zig_zag1d_8x8, 8,
+                      vp9_default_zig_zag1d_8x8_neighbors);
+  init_scan_neighbors(vp9_default_zig_zag1d_16x16, 16,
+                      vp9_default_zig_zag1d_16x16_neighbors);
+#if CONFIG_TX32X32 && CONFIG_SUPERBLOCKS
+  init_scan_neighbors(vp9_default_zig_zag1d_32x32, 32,
+                      vp9_default_zig_zag1d_32x32_neighbors);
+#endif
+}
+
+const int *vp9_get_coef_neighbors_handle(const int *scan) {
+  if (scan == vp9_default_zig_zag1d_4x4) {
+    return vp9_default_zig_zag1d_4x4_neighbors;
+  } else if (scan == vp9_row_scan_4x4) {
+    return vp9_row_scan_4x4_neighbors;
+  } else if (scan == vp9_col_scan_4x4) {
+    return vp9_col_scan_4x4_neighbors;
+  } else if (scan == vp9_default_zig_zag1d_8x8) {
+    return vp9_default_zig_zag1d_8x8_neighbors;
+  } else if (scan == vp9_default_zig_zag1d_16x16) {
+    return vp9_default_zig_zag1d_16x16_neighbors;
+#if CONFIG_TX32X32 && CONFIG_SUPERBLOCKS
+  } else if (scan == vp9_default_zig_zag1d_32x32) {
+    return vp9_default_zig_zag1d_32x32_neighbors;
+#endif
+  }
+  return vp9_default_zig_zag1d_4x4_neighbors;
+}
+
+int vp9_get_coef_neighbor_context(const short int *qcoeff_ptr, int nodc,
+                                  const int *neigbor_handle, int rc) {
+  static int neighbors_used = MAX_NEIGHBORS;   // maximum is MAX_NEIGHBORS
+  const int *nb = neigbor_handle + rc * MAX_NEIGHBORS;
+  int i, v, val = 0, n = 0;
+  for (i = 0; i < neighbors_used; ++i) {
+    if (nb[i] == -1 || (nb[i] == 0 && nodc)) {
+      continue;
+    }
+    v = abs(qcoeff_ptr[nb[i]]);
+    val = (v > val ? v : val);
+    n++;
+  }
+  if (n == 0)
+    return 0;
+  else if (val <= 1)
+    return val;
+  else if (val < 4)
+    return 2;
+  else
+    return 3;
+}
+#endif  /* CONFIG_NEWCOEFCONTEXT */
+
 void vp9_default_coef_probs(VP9_COMMON *pc) {
   vpx_memcpy(pc->fc.coef_probs_4x4, default_coef_probs_4x4,
              sizeof(pc->fc.coef_probs_4x4));
@@ -546,7 +693,6 @@
   vpx_memcpy(pc->fc.hybrid_coef_probs_16x16,
              default_hybrid_coef_probs_16x16,
              sizeof(pc->fc.hybrid_coef_probs_16x16));
-
 #if CONFIG_TX32X32 && CONFIG_SUPERBLOCKS
   vpx_memcpy(pc->fc.coef_probs_32x32, default_coef_probs_32x32,
              sizeof(pc->fc.coef_probs_32x32));
--- a/vp9/common/vp9_entropy.h
+++ b/vp9/common/vp9_entropy.h
@@ -98,7 +98,7 @@
    distinct bands). */
 
 /*# define DC_TOKEN_CONTEXTS        3*/ /* 00, 0!0, !0!0 */
-#define PREV_COEF_CONTEXTS       4
+#define PREV_COEF_CONTEXTS          4
 
 typedef unsigned int vp9_coeff_count[COEF_BANDS][PREV_COEF_CONTEXTS]
                                     [MAX_ENTROPY_TOKENS];
@@ -127,13 +127,36 @@
 #endif
 
 void vp9_coef_tree_initialize(void);
-
 void vp9_adapt_coef_probs(struct VP9Common *);
 
 static void vp9_reset_mb_tokens_context(MACROBLOCKD* const xd) {
   /* Clear entropy contexts */
-    vpx_memset(xd->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES));
-    vpx_memset(xd->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES));
+  vpx_memset(xd->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES));
+  vpx_memset(xd->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES));
 }
 
+#if CONFIG_NEWCOEFCONTEXT
+
+#define MAX_NEIGHBORS 5
+#define NEWCOEFCONTEXT_BAND_COND(b)   ((b) >= 1)
+void vp9_init_neighbors(void);
+
+const int *vp9_get_coef_neighbors_handle(const int *scan);
+int vp9_get_coef_neighbor_context(const short int *qcoeff_ptr, int nodc,
+                                  const int *neigbor_handle, int rc);
+extern DECLARE_ALIGNED(16, int, vp9_default_zig_zag1d_4x4_neighbors[
+                       16 * MAX_NEIGHBORS]);
+extern DECLARE_ALIGNED(16, int, vp9_row_scan_4x4_neighbors[
+                       16 * MAX_NEIGHBORS]);
+extern DECLARE_ALIGNED(16, int, vp9_col_scan_4x4_neighbors[
+                       16 * MAX_NEIGHBORS]);
+extern DECLARE_ALIGNED(16, int, vp9_default_zig_zag1d_8x8_neighbors[
+                       64 * MAX_NEIGHBORS]);
+extern DECLARE_ALIGNED(16, int, vp9_default_zig_zag1d_16x16_neighbors[
+                       256 * MAX_NEIGHBORS]);
+#if CONFIG_SUPERBLOCKS && CONFIG_TX32X32
+extern DECLARE_ALIGNED(16, int, vp9_default_zig_zag1d_32x32_neighbors[
+                       1024 * MAX_NEIGHBORS]);
+#endif
+#endif  // CONFIG_NEWCOEFCONTEXT
 #endif  // VP9_COMMON_VP9_ENTROPY_H_
--- a/vp9/decoder/vp9_detokenize.c
+++ b/vp9/decoder/vp9_detokenize.c
@@ -63,11 +63,24 @@
   return decode_bool(br, 128) ? -value_to_sign : value_to_sign;
 }
 
-#define INCREMENT_COUNT(token)                     \
-  do {                                             \
+#if CONFIG_NEWCOEFCONTEXT
+#define PT pn
+#define INCREMENT_COUNT(token)                       \
+  do {                                               \
+    coef_counts[type][coef_bands[c]][pn][token]++;   \
+    pn = pt = vp9_prev_token_class[token];           \
+    if (c < seg_eob - 1 && NEWCOEFCONTEXT_BAND_COND(coef_bands[c + 1]))  \
+      pn = vp9_get_coef_neighbor_context(            \
+          qcoeff_ptr, nodc, neighbors, scan[c + 1]); \
+  } while (0)
+#else
+#define PT pt
+#define INCREMENT_COUNT(token)               \
+  do {                                       \
     coef_counts[type][coef_bands[c]][pt][token]++; \
     pt = vp9_prev_token_class[token];              \
   } while (0)
+#endif  /* CONFIG_NEWCOEFCONTEXT */
 
 #define WRITE_COEF_CONTINUE(val, token)                       \
   {                                                           \
@@ -92,7 +105,12 @@
                         const int *const scan, TX_SIZE txfm_size,
                         const int *coef_bands) {
   FRAME_CONTEXT *const fc = &dx->common.fc;
-  int pt, c = (type == PLANE_TYPE_Y_NO_DC);
+#if CONFIG_NEWCOEFCONTEXT
+  const int *neighbors;
+  int pn;
+#endif
+  int nodc = (type == PLANE_TYPE_Y_NO_DC);
+  int pt, c = nodc;
   vp9_coeff_probs *coef_probs;
   vp9_prob *prob;
   vp9_coeff_count *coef_counts;
@@ -135,11 +153,15 @@
   }
 
   VP9_COMBINEENTROPYCONTEXTS(pt, *a, *l);
+#if CONFIG_NEWCOEFCONTEXT
+  pn = pt;
+  neighbors = vp9_get_coef_neighbors_handle(scan);
+#endif
   while (1) {
     int val;
     const uint8_t *cat6 = cat6_prob;
     if (c >= seg_eob) break;
-    prob = coef_probs[type][coef_bands[c]][pt];
+    prob = coef_probs[type][coef_bands[c]][PT];
     if (!vp9_read(br, prob[EOB_CONTEXT_NODE]))
       break;
 SKIP_START:
@@ -147,7 +169,7 @@
     if (!vp9_read(br, prob[ZERO_CONTEXT_NODE])) {
       INCREMENT_COUNT(ZERO_TOKEN);
       ++c;
-      prob = coef_probs[type][coef_bands[c]][pt];
+      prob = coef_probs[type][coef_bands[c]][PT];
       goto SKIP_START;
     }
     // ONE_CONTEXT_NODE_0_
@@ -211,7 +233,7 @@
   }
 
   if (c < seg_eob)
-    coef_counts[type][coef_bands[c]][pt][DCT_EOB_TOKEN]++;
+    coef_counts[type][coef_bands[c]][PT][DCT_EOB_TOKEN]++;
 
   a[0] = l[0] = (c > !type);
 
--- a/vp9/encoder/vp9_encodemb.c
+++ b/vp9/encoder/vp9_encodemb.c
@@ -380,6 +380,9 @@
   int err_mult = plane_rd_mult[type];
   int default_eob;
   int const *scan, *bands;
+#if CONFIG_NEWCOEFCONTEXT
+  const int *neighbors;
+#endif
 
   switch (tx_size) {
     default:
@@ -421,6 +424,9 @@
       default_eob = 256;
       break;
   }
+#if CONFIG_NEWCOEFCONTEXT
+  neighbors = vp9_get_coef_neighbors_handle(scan);
+#endif
 
   /* Now set up a Viterbi trellis to evaluate alternative roundings. */
   rdmult = mb->rdmult * err_mult;
@@ -454,6 +460,11 @@
       if (next < default_eob) {
         band = bands[i + 1];
         pt = vp9_prev_token_class[t0];
+#if CONFIG_NEWCOEFCONTEXT
+        if (NEWCOEFCONTEXT_BAND_COND(band))
+          pt = vp9_get_coef_neighbor_context(
+              qcoeff_ptr, i0, neighbors, scan[i + 1]);
+#endif
         rate0 +=
           mb->token_costs[tx_size][type][band][pt][tokens[next][0].token];
         rate1 +=
@@ -501,12 +512,34 @@
       if (next < default_eob) {
         band = bands[i + 1];
         if (t0 != DCT_EOB_TOKEN) {
+#if CONFIG_NEWCOEFCONTEXT
+          int tmp = qcoeff_ptr[scan[i]];
+          qcoeff_ptr[scan[i]] = x;
+          if (NEWCOEFCONTEXT_BAND_COND(band))
+            pt = vp9_get_coef_neighbor_context(
+                qcoeff_ptr, i0, neighbors, scan[i + 1]);
+          else
+            pt = vp9_prev_token_class[t0];
+          qcoeff_ptr[scan[i]] = tmp;
+#else
           pt = vp9_prev_token_class[t0];
+#endif
           rate0 += mb->token_costs[tx_size][type][band][pt][
               tokens[next][0].token];
         }
         if (t1 != DCT_EOB_TOKEN) {
+#if CONFIG_NEWCOEFCONTEXT
+          int tmp = qcoeff_ptr[scan[i]];
+          qcoeff_ptr[scan[i]] = x;
+          if (NEWCOEFCONTEXT_BAND_COND(band))
+            pt = vp9_get_coef_neighbor_context(
+                qcoeff_ptr, i0, neighbors, scan[i + 1]);
+          else
+            pt = vp9_prev_token_class[t1];
+          qcoeff_ptr[scan[i]] = tmp;
+#else
           pt = vp9_prev_token_class[t1];
+#endif
           rate1 += mb->token_costs[tx_size][type][band][pt][
               tokens[next][1].token];
         }
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -513,18 +513,32 @@
 
 }
 
+#if CONFIG_NEWCOEFCONTEXT
+#define PT pn
+#else
+#define PT pt
+#endif
+
 static int cost_coeffs_2x2(MACROBLOCK *mb,
                            BLOCKD *b, PLANE_TYPE type,
                            ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) {
-  int c = (type == PLANE_TYPE_Y_NO_DC); /* start at coef 0, unless Y with Y2 */
+  int nodc = (type == PLANE_TYPE_Y_NO_DC);
+  int c = nodc; /* start at coef 0, unless Y with Y2 */
   int eob = b->eob;
   int pt;    /* surrounding block/prev coef predictor */
   int cost = 0;
   int16_t *qcoeff_ptr = b->qcoeff;
+#if CONFIG_NEWCOEFCONTEXT
+  const int *neighbors = vp9_default_zig_zag1d_4x4_neighbors;
+  int pn;
+#endif
 
   VP9_COMBINEENTROPYCONTEXTS(pt, *a, *l);
   assert(eob <= 4);
 
+#if CONFIG_NEWCOEFCONTEXT
+  pn = pt;
+#endif
   for (; c < eob; c++) {
     int v = qcoeff_ptr[vp9_default_zig_zag1d_4x4[c]];
     int t = vp9_dct_value_tokens_ptr[v].Token;
@@ -531,11 +545,16 @@
     cost += mb->token_costs[TX_8X8][type][vp9_coef_bands_4x4[c]][pt][t];
     cost += vp9_dct_value_cost_ptr[v];
     pt = vp9_prev_token_class[t];
+#if CONFIG_NEWCOEFCONTEXT
+    if (c < 4 - 1)
+      pn = vp9_get_coef_neighbor_context(
+           qcoeff_ptr, nodc, neighbors, vp9_default_zig_zag1d_4x4[c + 1]);
+#endif
   }
 
   if (c < 4)
     cost += mb->token_costs[TX_8X8][type][vp9_coef_bands_4x4[c]]
-            [pt] [DCT_EOB_TOKEN];
+        [PT][DCT_EOB_TOKEN];
   // is eob first coefficient;
   pt = (c > !type);
   *a = *l = pt;
@@ -546,7 +565,8 @@
                        ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l,
                        TX_SIZE tx_size) {
   const int eob = b->eob;
-  int c = (type == PLANE_TYPE_Y_NO_DC); /* start at coef 0, unless Y with Y2 */
+  int nodc = (type == PLANE_TYPE_Y_NO_DC);
+  int c = nodc; /* start at coef 0, unless Y with Y2 */
   int cost = 0, default_eob, seg_eob;
   int pt;                     /* surrounding block/prev coef predictor */
   int const *scan, *band;
@@ -555,6 +575,10 @@
   MB_MODE_INFO *mbmi = &mb->e_mbd.mode_info_context->mbmi;
   TX_TYPE tx_type = DCT_DCT;
   int segment_id = mbmi->segment_id;
+#if CONFIG_NEWCOEFCONTEXT
+  const int *neighbors;
+  int pn;
+#endif
   scan = vp9_default_zig_zag1d_4x4;
   band = vp9_coef_bands_4x4;
   default_eob = 16;
@@ -628,17 +652,28 @@
 
   VP9_COMBINEENTROPYCONTEXTS(pt, *a, *l);
 
+#if CONFIG_NEWCOEFCONTEXT
+  neighbors = vp9_get_coef_neighbors_handle(scan);
+  pn = pt;
+#endif
   if (tx_type != DCT_DCT) {
     for (; c < eob; c++) {
       int v = qcoeff_ptr[scan[c]];
       int t = vp9_dct_value_tokens_ptr[v].Token;
-      cost += mb->hybrid_token_costs[tx_size][type][band[c]][pt][t];
+      cost += mb->hybrid_token_costs[tx_size][type][band[c]][PT][t];
       cost += vp9_dct_value_cost_ptr[v];
       pt = vp9_prev_token_class[t];
+#if CONFIG_NEWCOEFCONTEXT
+      if (c < seg_eob - 1 && NEWCOEFCONTEXT_BAND_COND(band[c + 1]))
+        pn = vp9_get_coef_neighbor_context(
+            qcoeff_ptr, nodc, neighbors, scan[c + 1]);
+      else
+        pn = pt;
+#endif
     }
     if (c < seg_eob)
       cost += mb->hybrid_token_costs[tx_size][type][band[c]]
-          [pt][DCT_EOB_TOKEN];
+          [PT][DCT_EOB_TOKEN];
   } else {
     for (; c < eob; c++) {
       int v = qcoeff_ptr[scan[c]];
@@ -646,10 +681,17 @@
       cost += mb->token_costs[tx_size][type][band[c]][pt][t];
       cost += vp9_dct_value_cost_ptr[v];
       pt = vp9_prev_token_class[t];
+#if CONFIG_NEWCOEFCONTEXT
+      if (c < seg_eob - 1 && NEWCOEFCONTEXT_BAND_COND(band[c + 1]))
+        pn = vp9_get_coef_neighbor_context(
+            qcoeff_ptr, nodc, neighbors, scan[c + 1]);
+      else
+        pn = pt;
+#endif
     }
     if (c < seg_eob)
       cost += mb->token_costs[tx_size][type][band[c]]
-          [pt][DCT_EOB_TOKEN];
+          [PT][DCT_EOB_TOKEN];
   }
 
   // is eob first coefficient;
--- a/vp9/encoder/vp9_tokenize.c
+++ b/vp9/encoder/vp9_tokenize.c
@@ -103,6 +103,13 @@
   vp9_dct_value_tokens_ptr = dct_value_tokens + DCT_MAX_VALUE;
   vp9_dct_value_cost_ptr   = dct_value_cost + DCT_MAX_VALUE;
 }
+
+#if CONFIG_NEWCOEFCONTEXT
+#define PT pn
+#else
+#define PT pt
+#endif
+
 static void tokenize_b(VP9_COMP *cpi,
                        MACROBLOCKD *xd,
                        const int ib,
@@ -123,6 +130,10 @@
   vp9_coeff_probs *probs;
   const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ?
                           get_tx_type(xd, b) : DCT_DCT;
+#if CONFIG_NEWCOEFCONTEXT
+  const int *neighbors;
+  int pn;
+#endif
 
   ENTROPY_CONTEXT *const a = (ENTROPY_CONTEXT *)xd->above_context +
       vp9_block2above[tx_size][ib];
@@ -229,6 +240,10 @@
   }
 
   VP9_COMBINEENTROPYCONTEXTS(pt, a_ec, l_ec);
+#if CONFIG_NEWCOEFCONTEXT
+  neighbors = vp9_get_coef_neighbors_handle(scan);
+  pn = pt;
+#endif
 
   if (vp9_segfeature_active(xd, segment_id, SEG_LVL_EOB))
     seg_eob = vp9_get_segdata(xd, segment_id, SEG_LVL_EOB);
@@ -249,14 +264,21 @@
     }
 
     t->Token = token;
-    t->context_tree = probs[type][band][pt];
+    t->context_tree = probs[type][band][PT];
     t->skip_eob_node = (pt == 0) && ((band > 0 && type != PLANE_TYPE_Y_NO_DC) ||
                                      (band > 1 && type == PLANE_TYPE_Y_NO_DC));
     assert(vp9_coef_encodings[t->Token].Len - t->skip_eob_node > 0);
     if (!dry_run) {
-      ++counts[type][band][pt][token];
+      ++counts[type][band][PT][token];
     }
     pt = vp9_prev_token_class[token];
+#if CONFIG_NEWCOEFCONTEXT
+    if (c < seg_eob - 1 && NEWCOEFCONTEXT_BAND_COND(bands[c + 1]))
+      pn = vp9_get_coef_neighbor_context(
+          qcoeff_ptr, (type == PLANE_TYPE_Y_NO_DC), neighbors, scan[c + 1]);
+    else
+      pn = pt;
+#endif
     ++t;
   } while (c < eob && ++c < seg_eob);