shithub: libvpx

Download patch

ref: a28139c849b6c305ff293332c33e7c30a83a7b7b
parent: 0643c3f133a852d12423c1fc13d329a03a1a18e4
author: Deb Mukherjee <debargha@google.com>
date: Thu Mar 7 15:56:34 EST 2013

Continued experiment with nonzero count

Adds probability updates for extra bits for the nzcs, code for
getting nzc stats, plus some minor cleanups and fixes.

Change-Id: If2814e7f04fb52f5025ad9f400f3e6c50a00b543

--- a/vp9/common/vp9_coefupdateprobs.h
+++ b/vp9/common/vp9_coefupdateprobs.h
@@ -22,6 +22,7 @@
 #define NZC_UPDATE_PROB_8X8     252
 #define NZC_UPDATE_PROB_16X16   252
 #define NZC_UPDATE_PROB_32X32   252
+#define NZC_UPDATE_PROB_PCAT    252
 #endif
 
 #endif  // VP9_COMMON_VP9_COEFUPDATEPROBS_H__
--- a/vp9/common/vp9_default_coef_probs.h
+++ b/vp9/common/vp9_default_coef_probs.h
@@ -697,18 +697,22 @@
 };
 
 #if CONFIG_CODE_NONZEROCOUNT
-// TODO(debargha): Replace with probabilities once the stats stabilize
-static const unsigned int default_nzc4x4_counts[MAX_NZC_CONTEXTS]
-                                               [REF_TYPES]
-                                               [BLOCK_TYPES]
-                                               [NZC4X4_TOKENS] = {
+
+// TODO(debargha): Remove the macro and count tables after experimentation
+#define NZC_DEFAULT_COUNTS  /* Uncomment to use counts as defaults */
+
+#ifdef NZC_DEFAULT_COUNTS
+static const unsigned int default_nzc_counts_4x4[MAX_NZC_CONTEXTS]
+                                                [REF_TYPES]
+                                                [BLOCK_TYPES]
+                                                [NZC4X4_TOKENS] = {
   {
     {
       { 967652, 29023, 15039, 6952, 1568, 116 },
-      { 789116, 22938, 4522, 1935, 520, 47 }
+      { 289116, 22938, 4522, 1935, 520, 47 }
     }, {
       { 967652, 29023, 15039, 6952, 1568, 116 },
-      { 789116, 22938, 4522, 1935, 520, 47 }
+      { 689116, 22938, 4522, 1935, 520, 47 }
     },
   }, {
     {
@@ -716,23 +720,23 @@
       { 10405, 12395, 3401, 3574, 2461, 771 }
     }, {
       { 124684, 37167, 15270, 8483, 1777, 102 },
-      { 10405, 12395, 3401, 3574, 2461, 771 }
+      { 20405, 12395, 3401, 3574, 2461, 771 }
     }
   }, {
     {
-      { 41100, 22976, 15627, 16137, 7982, 793 },
+      { 4100, 22976, 15627, 16137, 7982, 1793 },
       { 4249, 3084, 2131, 4081, 6439, 1653 }
     }, {
-      { 41100, 22976, 15627, 16137, 7982, 793 },
-      { 4249, 3084, 2131, 4081, 6439, 1653 }
+      { 21100, 22976, 15627, 16137, 7982, 1793 },
+      { 4249, 3084, 2131, 4081, 2439, 1653 }
     }
   }
 };
 
-static const unsigned int default_nzc8x8_counts[MAX_NZC_CONTEXTS]
-                                               [REF_TYPES]
-                                               [BLOCK_TYPES]
-                                               [NZC8X8_TOKENS] = {
+static const unsigned int default_nzc_counts_8x8[MAX_NZC_CONTEXTS]
+                                                [REF_TYPES]
+                                                [BLOCK_TYPES]
+                                                [NZC8X8_TOKENS] = {
   {
     {
       { 372988, 62777, 19440, 11812, 5145, 1917, 439, 10 },
@@ -739,86 +743,251 @@
       { 72052, 30468, 6973, 3250, 1500, 750, 375, 5 },
     }, {
       { 372988, 62777, 19440, 11812, 5145, 1917, 439, 10 },
-      { 72052, 30468, 6973, 3250, 1500, 750, 375, 5 },
+      { 192052, 30468, 6973, 3250, 1500, 750, 375, 5 },
     }
   }, {
     {
       { 121533, 33527, 15655, 11920, 5723, 2009, 315, 7 },
-      { 17772, 23120, 13127, 8115, 4000, 2000, 200, 6 },
+      { 23772, 23120, 13127, 8115, 4000, 2000, 200, 6 },
     }, {
       { 121533, 33527, 15655, 11920, 5723, 2009, 315, 7 },
-      { 17772, 23120, 13127, 8115, 4000, 2000, 200, 6 },
+      { 23772, 23120, 13127, 8115, 4000, 2000, 200, 6 },
     }
   }, {
     {
       { 29408, 11758, 8023, 10123, 6705, 2468, 369, 17 },
-      { 6612, 13874, 13329, 13022, 6500, 3250, 300, 12 },
+      { 11612, 13874, 13329, 13022, 6500, 3250, 300, 12 },
     }, {
       { 29408, 11758, 8023, 10123, 6705, 2468, 369, 17 },
-      { 6612, 13874, 13329, 13022, 6500, 3250, 300, 12 },
+      { 11612, 13874, 13329, 13022, 6500, 3250, 300, 12 },
     }
   }
 };
 
-static const unsigned int default_nzc16x16_counts[MAX_NZC_CONTEXTS]
-                                                 [REF_TYPES]
-                                                 [BLOCK_TYPES]
-                                                 [NZC16X16_TOKENS] = {
+static const unsigned int default_nzc_counts_16x16[MAX_NZC_CONTEXTS]
+                                                  [REF_TYPES]
+                                                  [BLOCK_TYPES]
+                                                  [NZC16X16_TOKENS] = {
   {
     {
       { 372988, 62777, 19440, 11812, 5145, 1917, 439, 10, 5, 2 },
       { 72052, 30468, 6973, 3250, 1500, 750, 375, 50, 8, 1 },
     }, {
-      { 372988, 62777, 19440, 11812, 5145, 1917, 439, 10, 5, 2 },
-      { 72052, 30468, 6973, 3250, 1500, 750, 375, 50, 8, 1 },
+      { 32988, 62777, 19440, 11812, 5145, 1917, 439, 10, 5, 2 },
+      { 92052, 30468, 6973, 3250, 1500, 750, 375, 50, 8, 1 },
     }
   }, {
     {
-      { 121533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2 },
-      { 17772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2 },
+      { 21533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2 },
+      { 47772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2 },
     }, {
-      { 121533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2 },
-      { 17772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2 },
+      { 21533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2 },
+      { 27772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2 },
     }
   }, {
     {
       { 29408, 11758, 8023, 10123, 6705, 2468, 369, 17, 10, 5 },
-      { 6612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3 },
+      { 9612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3 },
     }, {
       { 29408, 11758, 8023, 10123, 6705, 2468, 369, 17, 10, 5 },
-      { 6612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3 },
+      { 9612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3 },
     }
   }
 };
 
-static const unsigned int default_nzc32x32_counts[MAX_NZC_CONTEXTS]
-                                                 [REF_TYPES]
-                                                 [BLOCK_TYPES]
-                                                 [NZC32X32_TOKENS] = {
+static const unsigned int default_nzc_counts_32x32[MAX_NZC_CONTEXTS]
+                                                  [REF_TYPES]
+                                                  [BLOCK_TYPES]
+                                                  [NZC32X32_TOKENS] = {
   {
     {
-      { 372988, 62777, 19440, 11812, 5145, 1917, 439, 10, 5, 2, 1, 0 },
-      { 72052, 30468, 6973, 3250, 1500, 750, 375, 50, 8, 1 },
+      { 72988, 62777, 19440, 11812, 5145, 1917, 439, 10, 5, 2, 1, 0 },
+      { 52052, 30468, 6973, 3250, 1500, 750, 375, 50, 8, 1, 0, 0 },
     }, {
-      { 372988, 62777, 19440, 11812, 5145, 1917, 439, 10, 5, 2, 1, 0 },
-      { 72052, 30468, 6973, 3250, 1500, 750, 375, 50, 8, 1 },
+      { 72988, 62777, 19440, 11812, 5145, 1917, 439, 10, 5, 2, 1, 0 },
+      { 72052, 30468, 6973, 3250, 1500, 750, 375, 50, 8, 1, 0, 0 },
     }
   }, {
     {
-      { 121533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2, 1, 0 },
-      { 17772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2 },
+      { 21533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2, 1, 0 },
+      { 27772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2, 1, 0 },
     }, {
-      { 121533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2, 1, 0 },
-      { 17772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2 },
+      { 21533, 33527, 15655, 11920, 5723, 2009, 315, 7, 4, 2, 1, 0 },
+      { 27772, 23120, 13127, 8115, 4000, 2000, 200, 6, 4, 2, 1, 0 },
     }
   }, {
     {
       { 29408, 11758, 8023, 10123, 6705, 2468, 369, 17, 10, 5, 2, 1 },
-      { 6612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3 },
+      { 9612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3, 2, 1 },
     }, {
       { 29408, 11758, 8023, 10123, 6705, 2468, 369, 17, 10, 5, 2, 1 },
-      { 6612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3 },
+      { 9612, 13874, 13329, 13022, 6500, 3250, 300, 12, 6, 3, 2, 1 },
     }
   }
 };
+
+#else
+
+static const vp9_prob default_nzc_probs_4x4[MAX_NZC_CONTEXTS]
+                                           [REF_TYPES]
+                                           [BLOCK_TYPES]
+                                           [NZC4X4_TOKENS] = {
+  {
+    {
+      { 219, 162, 179, 142, 242, },
+      { 214, 253, 228, 246, 255, },
+    }, {
+      { 225, 236, 190, 229, 253, },
+      { 251, 253, 240, 248, 255, },
+    },
+  }, {
+    {
+      { 106, 126, 158, 126, 244, },
+      { 118, 241, 201, 240, 255, },
+    }, {
+      { 165, 179, 143, 189, 242, },
+      { 173, 239, 192, 255, 128, },
+    },
+  }, {
+    {
+      { 42 , 78 , 153, 92 , 223, },
+      { 128, 128, 128, 128, 128, },
+    }, {
+      { 76 , 68 , 126, 110, 216, },
+      { 128, 128, 128, 128, 128, },
+    },
+  },
+};
+
+static const vp9_prob default_nzc_probs_8x8[MAX_NZC_CONTEXTS]
+                                           [REF_TYPES]
+                                           [BLOCK_TYPES]
+                                           [NZC8X8_TOKENS] = {
+  {
+    {
+      { 134, 139, 170, 178, 142, 197, 255, },
+      { 167, 224, 199, 252, 205, 255, 128, },
+    }, {
+      { 181, 210, 180, 241, 190, 235, 255, },
+      { 234, 251, 235, 252, 219, 255, 128, },
+    },
+  }, {
+    {
+      { 33 , 64 , 155, 143, 86 , 216, 255, },
+      { 73 , 160, 167, 251, 153, 255, 128, },
+    }, {
+      { 79 , 104, 153, 195, 119, 246, 255, },
+      { 149, 183, 186, 249, 203, 255, 128, },
+    },
+  }, {
+    {
+      { 10 , 25 , 156, 61 , 69 , 156, 254, },
+      { 32 , 1  , 128, 146, 64 , 255, 128, },
+    }, {
+      { 37 , 48 , 143, 113, 81 , 202, 255, },
+      { 1  , 255, 128, 128, 128, 128, 128, },
+    },
+  },
+};
+
+static const vp9_prob default_nzc_probs_16x16[MAX_NZC_CONTEXTS]
+                                             [REF_TYPES]
+                                             [BLOCK_TYPES]
+                                             [NZC16X16_TOKENS] = {
+  {
+    {
+      { 11 , 188, 210, 167, 141, 143, 152, 255, 128, },
+      { 171, 201, 203, 244, 207, 255, 255, 128, 128, },
+    }, {
+      { 23 , 217, 207, 251, 198, 255, 219, 128, 128, },
+      { 235, 249, 229, 255, 199, 128, 128, 128, 128, },
+    },
+  }, {
+    {
+      { 9  , 45 , 168, 85 , 66 , 221, 139, 246, 255, },
+      { 51 , 110, 163, 238, 94 , 255, 255, 128, 128, },
+    }, {
+      { 4  , 149, 175, 240, 149, 255, 205, 128, 128, },
+      { 141, 217, 186, 255, 128, 128, 128, 128, 128, },
+    },
+  }, {
+    {
+      { 1  , 12 , 173, 6  , 68 , 145, 41 , 204, 255, },
+      { 39 , 47 , 128, 199, 110, 255, 128, 128, 128, },
+    }, {
+      { 1  , 121, 171, 149, 115, 242, 159, 255, 128, },
+      { 1  , 255, 255, 128, 128, 128, 128, 128, 128, },
+    },
+  },
+};
+
+static const vp9_prob default_nzc_probs_32x32[MAX_NZC_CONTEXTS]
+                                             [REF_TYPES]
+                                             [BLOCK_TYPES]
+                                             [NZC32X32_TOKENS] = {
+  {
+    {
+      { 11 , 216, 195, 201, 160, 247, 217, 255, 255, 128, 128, },
+      { 177, 240, 239, 255, 192, 128, 128, 128, 128, 128, 128, },
+    }, {
+      { 48 , 235, 213, 235, 199, 255, 255, 128, 128, 128, 128, },
+      { 205, 255, 248, 128, 128, 128, 128, 128, 128, 128, 128, },
+    },
+  }, {
+    {
+      { 6  , 96 , 138, 99 , 125, 248, 188, 255, 128, 128, 128, },
+      { 17 , 53 , 43 , 189, 1  , 255, 171, 128, 128, 128, 128, },
+    }, {
+      { 5  , 187, 235, 232, 117, 255, 219, 128, 128, 128, 128, },
+      { 146, 255, 255, 128, 128, 128, 128, 128, 128, 128, 128, },
+    },
+  }, {
+    {
+      { 1  , 7  , 93 , 14 , 100, 30 , 85 , 65 , 81 , 210, 255, },
+      { 1  , 1  , 128, 26 , 1  , 218, 78 , 255, 255, 128, 128, },
+    }, {
+      { 4  , 148, 206, 137, 160, 255, 255, 128, 128, 128, 128, },
+      { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, },
+    },
+  },
+};
 #endif
+
+static const vp9_prob default_nzc_pcat_probs[MAX_NZC_CONTEXTS]
+                                            [NZC_TOKENS_EXTRA]
+                                            [NZC_BITS_EXTRA] = {
+  // Bit probabilities are in least to most significance order
+  {
+    {176, 128, 128, 128, 128, 128, 128, 128, 128},   // 3 - 4
+    {164, 192, 128, 128, 128, 128, 128, 128, 128},   // 5 - 8
+    {154, 184, 208, 128, 128, 128, 128, 128, 128},   // 9 - 16
+    {144, 176, 200, 216, 128, 128, 128, 128, 128},   // 17 - 32
+    {140, 172, 192, 208, 224, 128, 128, 128, 128},   // 33 - 64
+    {136, 168, 188, 200, 220, 232, 128, 128, 128},   // 65 - 128
+    {132, 164, 184, 196, 216, 228, 240, 128, 128},   // 129 - 256
+    {130, 162, 178, 194, 212, 226, 240, 248, 128},   // 257 - 512
+    {128, 160, 176, 192, 208, 224, 240, 248, 254},   // 513 - 1024
+  }, {
+    {168, 128, 128, 128, 128, 128, 128, 128, 128},   // 3 - 4
+    {152, 184, 128, 128, 128, 128, 128, 128, 128},   // 5 - 8
+    {152, 184, 208, 128, 128, 128, 128, 128, 128},   // 9 - 16
+    {144, 176, 200, 216, 128, 128, 128, 128, 128},   // 17 - 32
+    {140, 172, 192, 208, 224, 128, 128, 128, 128},   // 33 - 64
+    {136, 168, 188, 200, 220, 232, 128, 128, 128},   // 65 - 128
+    {132, 164, 184, 196, 216, 228, 240, 128, 128},   // 129 - 256
+    {130, 162, 178, 194, 212, 226, 240, 248, 128},   // 257 - 512
+    {128, 160, 176, 192, 208, 224, 240, 248, 254},   // 513 - 1024
+  }, {
+    {160, 128, 128, 128, 128, 128, 128, 128, 128},   // 3 - 4
+    {152, 176, 128, 128, 128, 128, 128, 128, 128},   // 5 - 8
+    {150, 184, 208, 128, 128, 128, 128, 128, 128},   // 9 - 16
+    {144, 176, 200, 216, 128, 128, 128, 128, 128},   // 17 - 32
+    {140, 172, 192, 208, 224, 128, 128, 128, 128},   // 33 - 64
+    {136, 168, 188, 200, 220, 232, 128, 128, 128},   // 65 - 128
+    {132, 164, 184, 196, 216, 228, 240, 128, 128},   // 129 - 256
+    {130, 162, 178, 194, 212, 226, 240, 248, 128},   // 257 - 512
+    {128, 160, 176, 192, 208, 224, 240, 248, 254},   // 513 - 1024
+  },
+};
+
+#endif  // CONFIG_CODE_NONZEROCOUNT
--- a/vp9/common/vp9_entropy.c
+++ b/vp9/common/vp9_entropy.c
@@ -235,41 +235,14 @@
 };
 struct vp9_token_struct vp9_nzc32x32_encodings[NZC32X32_TOKENS];
 
-const vp9_prob Pcat_nzc[MAX_NZC_CONTEXTS]
-                       [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA] = { {
-    // Bit probabilities are in least to most significance order
-    {176,   0,   0,   0,   0,   0,   0,   0,   0},   // 3 - 4
-    {164, 192,   0,   0,   0,   0,   0,   0,   0},   // 5 - 8
-    {154, 184, 208,   0,   0,   0,   0,   0,   0},   // 9 - 16
-    {144, 176, 200, 216,   0,   0,   0,   0,   0},   // 17 - 32
-    {140, 172, 192, 208, 224,   0,   0,   0,   0},   // 33 - 64
-    {136, 168, 188, 200, 220, 232,   0,   0,   0},   // 65 - 128
-    {132, 164, 184, 196, 216, 228, 240,   0,   0},   // 129 - 256
-    {130, 162, 178, 194, 212, 226, 240, 248,   0},   // 257 - 512
-    {128, 160, 176, 192, 208, 224, 240, 248, 254},   // 513 - 1024
-  }, {
-    {168,   0,   0,   0,   0,   0,   0,   0,   0},   // 3 - 4
-    {152, 184,   0,   0,   0,   0,   0,   0,   0},   // 5 - 8
-    {152, 184, 208,   0,   0,   0,   0,   0,   0},   // 9 - 16
-    {144, 176, 200, 216,   0,   0,   0,   0,   0},   // 17 - 32
-    {140, 172, 192, 208, 224,   0,   0,   0,   0},   // 33 - 64
-    {136, 168, 188, 200, 220, 232,   0,   0,   0},   // 65 - 128
-    {132, 164, 184, 196, 216, 228, 240,   0,   0},   // 129 - 256
-    {130, 162, 178, 194, 212, 226, 240, 248,   0},   // 257 - 512
-    {128, 160, 176, 192, 208, 224, 240, 248, 254},   // 513 - 1024
-  }, {
-    {160,   0,   0,   0,   0,   0,   0,   0,   0},   // 3 - 4
-    {152, 176,   0,   0,   0,   0,   0,   0,   0},   // 5 - 8
-    {150, 184, 208,   0,   0,   0,   0,   0,   0},   // 9 - 16
-    {144, 176, 200, 216,   0,   0,   0,   0,   0},   // 17 - 32
-    {140, 172, 192, 208, 224,   0,   0,   0,   0},   // 33 - 64
-    {136, 168, 188, 200, 220, 232,   0,   0,   0},   // 65 - 128
-    {132, 164, 184, 196, 216, 228, 240,   0,   0},   // 129 - 256
-    {130, 162, 178, 194, 212, 226, 240, 248,   0},   // 257 - 512
-    {128, 160, 176, 192, 208, 224, 240, 248, 254},   // 513 - 1024
-  },
+const int vp9_extranzcbits[NZC32X32_TOKENS] = {
+  0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
 };
 
+const int vp9_basenzcvalue[NZC32X32_TOKENS] = {
+  0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513
+};
+
 #endif  // CONFIG_CODE_NONZEROCOUNT
 
 static vp9_tree_index cat1[2], cat2[4], cat3[6], cat4[8], cat5[10], cat6[28];
@@ -340,17 +313,8 @@
 
 void vp9_default_coef_probs(VP9_COMMON *pc) {
 #if CONFIG_CODE_NONZEROCOUNT
+#ifdef NZC_DEFAULT_COUNTS
   int h, g;
-#endif
-  vpx_memcpy(pc->fc.coef_probs_4x4, default_coef_probs_4x4,
-             sizeof(pc->fc.coef_probs_4x4));
-  vpx_memcpy(pc->fc.coef_probs_8x8, default_coef_probs_8x8,
-             sizeof(pc->fc.coef_probs_8x8));
-  vpx_memcpy(pc->fc.coef_probs_16x16, default_coef_probs_16x16,
-             sizeof(pc->fc.coef_probs_16x16));
-  vpx_memcpy(pc->fc.coef_probs_32x32, default_coef_probs_32x32,
-             sizeof(pc->fc.coef_probs_32x32));
-#if CONFIG_CODE_NONZEROCOUNT
   for (h = 0; h < MAX_NZC_CONTEXTS; ++h) {
     for (g = 0; g < REF_TYPES; ++g) {
       int i;
@@ -362,29 +326,49 @@
         vp9_tree_probs_from_distribution(
           NZC4X4_TOKENS, vp9_nzc4x4_encodings, vp9_nzc4x4_tree,
           pc->fc.nzc_probs_4x4[h][g][i], branch_ct4x4,
-          default_nzc4x4_counts[h][g][i]);
+          default_nzc_counts_4x4[h][g][i]);
       }
       for (i = 0; i < BLOCK_TYPES; ++i) {
         vp9_tree_probs_from_distribution(
           NZC8X8_TOKENS, vp9_nzc8x8_encodings, vp9_nzc8x8_tree,
           pc->fc.nzc_probs_8x8[h][g][i], branch_ct8x8,
-          default_nzc8x8_counts[h][g][i]);
+          default_nzc_counts_8x8[h][g][i]);
       }
       for (i = 0; i < BLOCK_TYPES; ++i) {
         vp9_tree_probs_from_distribution(
           NZC16X16_TOKENS, vp9_nzc16x16_encodings, vp9_nzc16x16_tree,
           pc->fc.nzc_probs_16x16[h][g][i], branch_ct16x16,
-          default_nzc16x16_counts[h][g][i]);
+          default_nzc_counts_16x16[h][g][i]);
       }
       for (i = 0; i < BLOCK_TYPES; ++i) {
         vp9_tree_probs_from_distribution(
           NZC32X32_TOKENS, vp9_nzc32x32_encodings, vp9_nzc32x32_tree,
           pc->fc.nzc_probs_32x32[h][g][i], branch_ct32x32,
-          default_nzc32x32_counts[h][g][i]);
+          default_nzc_counts_32x32[h][g][i]);
       }
     }
   }
+#else
+  vpx_memcpy(pc->fc.nzc_probs_4x4, default_nzc_probs_4x4,
+             sizeof(pc->fc.nzc_probs_4x4));
+  vpx_memcpy(pc->fc.nzc_probs_8x8, default_nzc_probs_8x8,
+             sizeof(pc->fc.nzc_probs_8x8));
+  vpx_memcpy(pc->fc.nzc_probs_16x16, default_nzc_probs_16x16,
+             sizeof(pc->fc.nzc_probs_16x16));
+  vpx_memcpy(pc->fc.nzc_probs_32x32, default_nzc_probs_32x32,
+             sizeof(pc->fc.nzc_probs_32x32));
+#endif
+  vpx_memcpy(pc->fc.nzc_pcat_probs, default_nzc_pcat_probs,
+             sizeof(pc->fc.nzc_pcat_probs));
 #endif  // CONFIG_CODE_NONZEROCOUNTyy
+  vpx_memcpy(pc->fc.coef_probs_4x4, default_coef_probs_4x4,
+             sizeof(pc->fc.coef_probs_4x4));
+  vpx_memcpy(pc->fc.coef_probs_8x8, default_coef_probs_8x8,
+             sizeof(pc->fc.coef_probs_8x8));
+  vpx_memcpy(pc->fc.coef_probs_16x16, default_coef_probs_16x16,
+             sizeof(pc->fc.coef_probs_16x16));
+  vpx_memcpy(pc->fc.coef_probs_32x32, default_coef_probs_32x32,
+             sizeof(pc->fc.coef_probs_32x32));
 }
 
 void vp9_coef_tree_initialize() {
@@ -406,17 +390,20 @@
      (mb_row) >= 0)
 
 #define choose_nzc_context(nzc_exp, t2, t1)     \
-    ((nzc_exp) >= ((t2) << 6) ? 2 : (nzc_exp) >= ((t1) << 6) ? 1 : 0)
+    ((nzc_exp) >= (t2) ? 2 : (nzc_exp) >= (t1) ? 1 : 0)
 
-#define NZC_T2_32X32    32
-#define NZC_T1_32X32     8
-#define NZC_T2_16X16    16
-#define NZC_T1_16X16     4
-#define NZC_T2_8X8       8
-#define NZC_T1_8X8       2
-#define NZC_T2_4X4       4
-#define NZC_T1_4X4       1
+#define NZC_T2_32X32    (16 << 6)
+#define NZC_T1_32X32     (4 << 6)
 
+#define NZC_T2_16X16    (12 << 6)
+#define NZC_T1_16X16     (3 << 6)
+
+#define NZC_T2_8X8       (8 << 6)
+#define NZC_T1_8X8       (2 << 6)
+
+#define NZC_T2_4X4       (4 << 6)
+#define NZC_T1_4X4       (1 << 6)
+
 // Transforms a mb16 block index to a sb64 block index
 static inline int mb16_to_sb64_index(int mb_row, int mb_col, int block) {
   int r = (mb_row & 3);
@@ -1253,7 +1240,7 @@
                        TX_SIZE tx_size,
                        int ref,
                        int type) {
-  int c;
+  int e, c;
   c = codenzc(nzc);
   if (tx_size == TX_32X32)
     cm->fc.nzc_counts_32x32[nzc_context][ref][type][c]++;
@@ -1265,7 +1252,14 @@
     cm->fc.nzc_counts_4x4[nzc_context][ref][type][c]++;
   else
     assert(0);
-  // TODO(debargha): Handle extra bits later if needed
+
+  if ((e = vp9_extranzcbits[c])) {
+    int x = nzc - vp9_basenzcvalue[c];
+    while (e--) {
+      int b = (x >> e) & 1;
+      cm->fc.nzc_pcat_counts[nzc_context][c - NZC_TOKENS_NOEXTRA][e][b]++;
+    }
+  }
 }
 
 static void update_nzcs_sb64(VP9_COMMON *cm,
@@ -1608,6 +1602,27 @@
       }
 }
 
+static void adapt_nzc_pcat(VP9_COMMON *cm, int count_sat, int update_factor) {
+  int c, t;
+  int count, factor;
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (t = 0; t < NZC_TOKENS_EXTRA; ++t) {
+      int bits = vp9_extranzcbits[t + NZC_TOKENS_NOEXTRA];
+      int b;
+      for (b = 0; b < bits; ++b) {
+        vp9_prob prob = get_binary_prob(cm->fc.nzc_pcat_counts[c][t][b][0],
+                                        cm->fc.nzc_pcat_counts[c][t][b][1]);
+        count = cm->fc.nzc_pcat_counts[c][t][b][0] +
+                cm->fc.nzc_pcat_counts[c][t][b][1];
+        count = count > count_sat ? count_sat : count;
+        factor = (update_factor * count / count_sat);
+        cm->fc.nzc_pcat_probs[c][t][b] = weighted_prob(
+            cm->fc.pre_nzc_pcat_probs[c][t][b], prob, factor);
+      }
+    }
+  }
+}
+
 // #define NZC_COUNT_TESTING
 void vp9_adapt_nzc_probs(VP9_COMMON *cm) {
   int count_sat;
@@ -1643,5 +1658,6 @@
   adapt_nzc_probs(cm, 8, count_sat, update_factor);
   adapt_nzc_probs(cm, 16, count_sat, update_factor);
   adapt_nzc_probs(cm, 32, count_sat, update_factor);
+  adapt_nzc_pcat(cm, count_sat, update_factor);
 }
 #endif  // CONFIG_CODE_NONZEROCOUNT
--- a/vp9/common/vp9_entropy.h
+++ b/vp9/common/vp9_entropy.h
@@ -175,8 +175,14 @@
 /* Max number of extra bits */
 #define NZC_BITS_EXTRA          9
 
+/* Tokens without extra bits */
+#define NZC_TOKENS_NOEXTRA      (NZC32X32_TOKENS - NZC_TOKENS_EXTRA)
+
 #define MAX_NZC_CONTEXTS        3
 
+/* whether to update extra bit probabilities */
+#define NZC_PCAT_UPDATE
+
 /* nzc trees */
 extern const vp9_tree_index    vp9_nzc4x4_tree[];
 extern const vp9_tree_index    vp9_nzc8x8_tree[];
@@ -193,8 +199,6 @@
   (x) <= 3 ? (x) : (x) <= 4 ? 3 : (x) <= 8 ? 4 : \
   (x) <= 16 ? 5 : (x) <= 32 ? 6 : (x) <= 64 ? 7 :\
   (x) <= 128 ? 8 : (x) <= 256 ? 9 : (x) <= 512 ? 10 : 11)
-#define extranzcbits(c) ((c) <= 2 ? 0 : (c) - 2)
-#define basenzcvalue(c) ((c) <= 2 ? (c) : (1 << ((c) - 2)) + 1)
 
 int vp9_get_nzc_context_y_sb64(struct VP9Common *cm, MODE_INFO *cur,
                                int mb_row, int mb_col, int block);
@@ -213,9 +217,11 @@
                            int mb_row, int mb_col);
 void vp9_adapt_nzc_probs(struct VP9Common *cm);
 
-/* Extra bit probabilities - block size agnostic */
-extern const vp9_prob Pcat_nzc[MAX_NZC_CONTEXTS][NZC_TOKENS_EXTRA]
-                              [NZC_BITS_EXTRA];
+/* Extra bits array */
+extern const int vp9_extranzcbits[NZC32X32_TOKENS];
+
+/* Base nzc values */
+extern const int vp9_basenzcvalue[NZC32X32_TOKENS];
 
 #endif  // CONFIG_CODE_NONZEROCOUNT
 #endif  // VP9_COMMON_VP9_ENTROPY_H_
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -72,6 +72,8 @@
                           [NZC16X16_NODES];
   vp9_prob nzc_probs_32x32[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
                           [NZC32X32_NODES];
+  vp9_prob nzc_pcat_probs[MAX_NZC_CONTEXTS]
+                         [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA];
 #endif
 
   nmv_context nmvc;
@@ -104,6 +106,8 @@
                               [NZC16X16_NODES];
   vp9_prob pre_nzc_probs_32x32[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
                               [NZC32X32_NODES];
+  vp9_prob pre_nzc_pcat_probs[MAX_NZC_CONTEXTS]
+                             [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA];
 #endif
 
   vp9_coeff_count coef_counts_4x4[BLOCK_TYPES];
@@ -119,6 +123,8 @@
                                [NZC16X16_TOKENS];
   unsigned int nzc_counts_32x32[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
                                [NZC32X32_TOKENS];
+  unsigned int nzc_pcat_counts[MAX_NZC_CONTEXTS]
+                              [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA][2];
 #endif
 
   nmv_context_counts NMVcount;
--- a/vp9/decoder/vp9_decodemv.c
+++ b/vp9/decoder/vp9_decodemv.c
@@ -1201,11 +1201,15 @@
   } else {
     assert(0);
   }
-  nzc = basenzcvalue(c);
-  if ((e = extranzcbits(c))) {
+  nzc = vp9_basenzcvalue[c];
+  if ((e = vp9_extranzcbits[c])) {
     int x = 0;
-    while (e--)
-      x |= (vp9_read(bc, Pcat_nzc[nzc_context][c - 3][e]) << e);
+    while (e--) {
+      int b = vp9_read(
+          bc, cm->fc.nzc_pcat_probs[nzc_context][c - NZC_TOKENS_NOEXTRA][e]);
+      x |= (b << e);
+      cm->fc.nzc_pcat_counts[nzc_context][c - NZC_TOKENS_NOEXTRA][e][b]++;
+    }
     nzc += x;
   }
   if (tx_size == TX_32X32)
--- a/vp9/decoder/vp9_decodframe.c
+++ b/vp9/decoder/vp9_decodframe.c
@@ -1169,6 +1169,25 @@
   }
 }
 
+static void read_nzc_pcat_probs(VP9_COMMON *cm, BOOL_DECODER* const bc) {
+  int c, t, b;
+  vp9_prob upd = NZC_UPDATE_PROB_PCAT;
+  if (!vp9_read_bit(bc)) {
+    return;
+  }
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (t = 0; t < NZC_TOKENS_EXTRA; ++t) {
+      int bits = vp9_extranzcbits[t + NZC_TOKENS_NOEXTRA];
+      for (b = 0; b < bits; ++b) {
+        vp9_prob *p = &cm->fc.nzc_pcat_probs[c][t][b];
+        if (vp9_read(bc, upd)) {
+          *p = read_prob_diff_update(bc, *p);
+        }
+      }
+    }
+  }
+}
+
 static void read_nzc_probs(VP9_COMMON *cm,
                            BOOL_DECODER* const bc) {
   read_nzc_probs_common(cm, bc, 4);
@@ -1178,6 +1197,9 @@
     read_nzc_probs_common(cm, bc, 16);
   if (cm->txfm_mode > ALLOW_16X16)
     read_nzc_probs_common(cm, bc, 32);
+#ifdef NZC_PCAT_UPDATE
+  read_nzc_pcat_probs(cm, bc);
+#endif
 }
 #endif  // CONFIG_CODE_NONZEROCOUNT
 
@@ -1656,6 +1678,8 @@
            pbi->common.fc.nzc_probs_16x16);
   vp9_copy(pbi->common.fc.pre_nzc_probs_32x32,
            pbi->common.fc.nzc_probs_32x32);
+  vp9_copy(pbi->common.fc.pre_nzc_pcat_probs,
+           pbi->common.fc.nzc_pcat_probs);
 #endif
 
   vp9_zero(pbi->common.fc.coef_counts_4x4);
@@ -1679,6 +1703,7 @@
   vp9_zero(pbi->common.fc.nzc_counts_8x8);
   vp9_zero(pbi->common.fc.nzc_counts_16x16);
   vp9_zero(pbi->common.fc.nzc_counts_32x32);
+  vp9_zero(pbi->common.fc.nzc_pcat_counts);
 #endif
 
   read_coef_probs(pbi, &header_bc);
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -50,6 +50,24 @@
 extern unsigned int active_section;
 #endif
 
+#if CONFIG_CODE_NONZEROCOUNT
+#ifdef NZC_STATS
+unsigned int nzc_stats_4x4[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                          [NZC4X4_TOKENS];
+unsigned int nzc_stats_8x8[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                          [NZC8X8_TOKENS];
+unsigned int nzc_stats_16x16[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                          [NZC16X16_TOKENS];
+unsigned int nzc_stats_32x32[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                          [NZC32X32_TOKENS];
+unsigned int nzc_pcat_stats[MAX_NZC_CONTEXTS][NZC_TOKENS_EXTRA]
+                          [NZC_BITS_EXTRA][2];
+void init_nzcstats();
+void update_nzcstats(VP9_COMMON *const cm);
+void print_nzcstats();
+#endif
+#endif
+
 #ifdef MODE_STATS
 int count_mb_seg[4] = { 0, 0, 0, 0 };
 #endif
@@ -1066,10 +1084,14 @@
     assert(0);
   }
 
-  if ((e = extranzcbits(c))) {
-    int x = nzc - basenzcvalue(c);
-    while (e--)
-      vp9_write(bc, (x >> e) & 1, Pcat_nzc[nzc_context][c - 3][e]);
+  if ((e = vp9_extranzcbits[c])) {
+    int x = nzc - vp9_basenzcvalue[c];
+    while (e--) {
+      int b = (x >> e) & 1;
+      vp9_write(bc, b,
+                cm->fc.nzc_pcat_probs[nzc_context][c - NZC_TOKENS_NOEXTRA][e]);
+      // cm->fc.nzc_pcat_counts[nzc_context][c - NZC_TOKENS_NOEXTRA][e][b]++;
+    }
   }
 }
 
@@ -1269,8 +1291,314 @@
       break;
   }
 }
+
+#ifdef NZC_STATS
+void init_nzcstats() {
+  vp9_zero(nzc_stats_4x4);
+  vp9_zero(nzc_stats_8x8);
+  vp9_zero(nzc_stats_16x16);
+  vp9_zero(nzc_stats_32x32);
+  vp9_zero(nzc_pcat_stats);
+}
+
+void update_nzcstats(VP9_COMMON *const cm) {
+  int c, r, b, t;
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (r = 0; r < REF_TYPES; ++r) {
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        for (t = 0; t < NZC4X4_TOKENS; ++t) {
+          nzc_stats_4x4[c][r][b][t] += cm->fc.nzc_counts_4x4[c][r][b][t];
+        }
+      }
+    }
+  }
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (r = 0; r < REF_TYPES; ++r) {
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        for (t = 0; t < NZC8X8_TOKENS; ++t) {
+          nzc_stats_8x8[c][r][b][t] += cm->fc.nzc_counts_8x8[c][r][b][t];
+        }
+      }
+    }
+  }
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (r = 0; r < REF_TYPES; ++r) {
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        for (t = 0; t < NZC16X16_TOKENS; ++t) {
+          nzc_stats_16x16[c][r][b][t] += cm->fc.nzc_counts_16x16[c][r][b][t];
+        }
+      }
+    }
+  }
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (r = 0; r < REF_TYPES; ++r) {
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        for (t = 0; t < NZC32X32_TOKENS; ++t) {
+          nzc_stats_32x32[c][r][b][t] += cm->fc.nzc_counts_32x32[c][r][b][t];
+        }
+      }
+    }
+  }
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (t = 0; t < NZC_TOKENS_EXTRA; ++t) {
+      int bits = vp9_extranzcbits[t + NZC_TOKENS_NOEXTRA];
+      for (b = 0; b < bits; ++b) {
+        nzc_pcat_stats[c][t][b][0] += cm->fc.nzc_pcat_counts[c][t][b][0];
+        nzc_pcat_stats[c][t][b][1] += cm->fc.nzc_pcat_counts[c][t][b][1];
+      }
+    }
+  }
+}
+
+void print_nzcstats() {
+  int c, r, b, t;
+  printf(
+    "static const unsigned int default_nzc_counts_4x4[MAX_NZC_CONTEXTS]\n"
+    "                                                [REF_TYPES]\n"
+    "                                                [BLOCK_TYPES]\n"
+    "                                                [NZC4X4_TOKENS] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        printf("      {");
+        for (t = 0; t < NZC4X4_TOKENS; ++t) {
+          printf(" %-3d,", nzc_stats_4x4[c][r][b][t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const unsigned int default_nzc_counts_8x8[MAX_NZC_CONTEXTS]\n"
+    "                                                [REF_TYPES]\n"
+    "                                                [BLOCK_TYPES]\n"
+    "                                                [NZC8X8_TOKENS] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        printf("      {");
+        for (t = 0; t < NZC8X8_TOKENS; ++t) {
+          printf(" %-3d,", nzc_stats_8x8[c][r][b][t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const unsigned int default_nzc_counts_16x16[MAX_NZC_CONTEXTS]\n"
+    "                                                  [REF_TYPES]\n"
+    "                                                  [BLOCK_TYPES]\n"
+    "                                                  [NZC16X16_TOKENS] = {"
+    "\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        printf("      {");
+        for (t = 0; t < NZC16X16_TOKENS; ++t) {
+          printf(" %-3d,", nzc_stats_16x16[c][r][b][t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const unsigned int default_nzc_counts_32x32[MAX_NZC_CONTEXTS]\n"
+    "                                                  [REF_TYPES]\n"
+    "                                                  [BLOCK_TYPES]\n"
+    "                                                  [NZC32X32_TOKENS] = {"
+    "\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        printf("      {");
+        for (t = 0; t < NZC32X32_TOKENS; ++t) {
+          printf(" %-3d,", nzc_stats_32x32[c][r][b][t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const vp9_prob default_nzc_pcat_counts[MAX_NZC_CONTEXTS]\n"
+    "                                             [NZC_TOKENS_EXTRA]\n"
+    "                                             [NZC_BITS_EXTRA] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (t = 0; t < NZC_TOKENS_EXTRA; ++t) {
+      printf("    {");
+      for (b = 0; b < NZC_BITS_EXTRA; ++b) {
+        printf(" %d/%d,",
+               nzc_pcat_stats[c][t][b][0], nzc_pcat_stats[c][t][b][1]);
+      }
+      printf(" },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const vp9_prob default_nzc_probs_4x4[MAX_NZC_CONTEXTS]\n"
+    "                                           [REF_TYPES]\n"
+    "                                           [BLOCK_TYPES]\n"
+    "                                           [NZC4X4_TOKENS] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        vp9_prob probs[NZC4X4_NODES];
+        unsigned int branch_ct[NZC4X4_NODES][2];
+        vp9_tree_probs_from_distribution(NZC4X4_TOKENS,
+                                         vp9_nzc4x4_encodings,
+                                         vp9_nzc4x4_tree,
+                                         probs, branch_ct,
+                                         nzc_stats_4x4[c][r][b]);
+        printf("      {");
+        for (t = 0; t < NZC4X4_NODES; ++t) {
+          printf(" %-3d,", probs[t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const vp9_prob default_nzc_probs_8x8[MAX_NZC_CONTEXTS]\n"
+    "                                           [REF_TYPES]\n"
+    "                                           [BLOCK_TYPES]\n"
+    "                                           [NZC8X8_TOKENS] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        vp9_prob probs[NZC8X8_NODES];
+        unsigned int branch_ct[NZC8X8_NODES][2];
+        vp9_tree_probs_from_distribution(NZC8X8_TOKENS,
+                                         vp9_nzc8x8_encodings,
+                                         vp9_nzc8x8_tree,
+                                         probs, branch_ct,
+                                         nzc_stats_8x8[c][r][b]);
+        printf("      {");
+        for (t = 0; t < NZC8X8_NODES; ++t) {
+          printf(" %-3d,", probs[t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const vp9_prob default_nzc_probs_16x16[MAX_NZC_CONTEXTS]\n"
+    "                                             [REF_TYPES]\n"
+    "                                             [BLOCK_TYPES]\n"
+    "                                             [NZC16X16_TOKENS] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        vp9_prob probs[NZC16X16_NODES];
+        unsigned int branch_ct[NZC16X16_NODES][2];
+        vp9_tree_probs_from_distribution(NZC16X16_TOKENS,
+                                         vp9_nzc16x16_encodings,
+                                         vp9_nzc16x16_tree,
+                                         probs, branch_ct,
+                                         nzc_stats_16x16[c][r][b]);
+        printf("      {");
+        for (t = 0; t < NZC16X16_NODES; ++t) {
+          printf(" %-3d,", probs[t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const vp9_prob default_nzc_probs_32x32[MAX_NZC_CONTEXTS]\n"
+    "                                             [REF_TYPES]\n"
+    "                                             [BLOCK_TYPES]\n"
+    "                                             [NZC32X32_TOKENS] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (r = 0; r < REF_TYPES; ++r) {
+      printf("    {\n");
+      for (b = 0; b < BLOCK_TYPES; ++b) {
+        vp9_prob probs[NZC32X32_NODES];
+        unsigned int branch_ct[NZC32X32_NODES][2];
+        vp9_tree_probs_from_distribution(NZC32X32_TOKENS,
+                                         vp9_nzc32x32_encodings,
+                                         vp9_nzc32x32_tree,
+                                         probs, branch_ct,
+                                         nzc_stats_32x32[c][r][b]);
+        printf("      {");
+        for (t = 0; t < NZC32X32_NODES; ++t) {
+          printf(" %-3d,", probs[t]);
+        }
+        printf(" },\n");
+      }
+      printf("    },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+
+  printf(
+    "static const vp9_prob default_nzc_pcat_probs[MAX_NZC_CONTEXTS]\n"
+    "                                            [NZC_TOKENS_EXTRA]\n"
+    "                                            [NZC_BITS_EXTRA] = {\n");
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    printf("  {\n");
+    for (t = 0; t < NZC_TOKENS_EXTRA; ++t) {
+      printf("    {");
+      for (b = 0; b < NZC_BITS_EXTRA; ++b) {
+        vp9_prob prob = get_binary_prob(nzc_pcat_stats[c][t][b][0],
+                                        nzc_pcat_stats[c][t][b][1]);
+        printf(" %-3d,", prob);
+      }
+      printf(" },\n");
+    }
+    printf("  },\n");
+  }
+  printf("};\n");
+}
 #endif
 
+#endif  // CONFIG_CODE_NONZEROCOUNT
+
 static void write_modes_b(VP9_COMP *cpi, MODE_INFO *m, vp9_writer *bc,
                           TOKENEXTRA **tok, TOKENEXTRA *tok_end,
                           int mb_row, int mb_col) {
@@ -1593,6 +1921,76 @@
   }
 }
 
+static void update_nzc_pcat_probs(VP9_COMP *cpi, vp9_writer* const bc) {
+  VP9_COMMON *cm = &cpi->common;
+  int c, t, b;
+  int update[2] = {0, 0};
+  int savings = 0;
+  vp9_prob upd = NZC_UPDATE_PROB_PCAT;
+  for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+    for (t = 0; t < NZC_TOKENS_EXTRA; ++t) {
+      int bits = vp9_extranzcbits[t + NZC_TOKENS_NOEXTRA];
+      for (b = 0; b < bits; ++b) {
+        vp9_prob newp = get_binary_prob(cm->fc.nzc_pcat_counts[c][t][b][0],
+                                        cm->fc.nzc_pcat_counts[c][t][b][1]);
+        vp9_prob oldp = cm->fc.nzc_pcat_probs[c][t][b];
+        int s, u = 0;
+#if defined(SEARCH_NEWP)
+        s = prob_diff_update_savings_search(cm->fc.nzc_pcat_counts[c][t][b],
+                                            oldp, &newp, upd);
+        if (s > 0 && newp != oldp)
+          u = 1;
+        if (u)
+          savings += s - (int)(vp9_cost_zero(upd));
+        else
+          savings -= (int)(vp9_cost_zero(upd));
+#else
+        s = prob_update_savings(cm->fc.nzc_pcat_counts[c][t][b],
+                                oldp, newp, upd);
+        if (s > 0)
+          u = 1;
+        if (u)
+          savings += s;
+#endif
+        update[u]++;
+      }
+    }
+  }
+  if (update[1] == 0 || savings < 0) {
+    vp9_write_bit(bc, 0);
+  } else {
+    vp9_write_bit(bc, 1);
+    for (c = 0; c < MAX_NZC_CONTEXTS; ++c) {
+      for (t = 0; t < NZC_TOKENS_EXTRA; ++t) {
+        int bits = vp9_extranzcbits[t + NZC_TOKENS_NOEXTRA];
+        for (b = 0; b < bits; ++b) {
+          vp9_prob newp = get_binary_prob(cm->fc.nzc_pcat_counts[c][t][b][0],
+                                          cm->fc.nzc_pcat_counts[c][t][b][1]);
+          vp9_prob *oldp = &cm->fc.nzc_pcat_probs[c][t][b];
+          int s, u = 0;
+#if defined(SEARCH_NEWP)
+          s = prob_diff_update_savings_search(cm->fc.nzc_pcat_counts[c][t][b],
+                                              *oldp, &newp, upd);
+          if (s > 0 && newp != *oldp)
+            u = 1;
+#else
+          s = prob_update_savings(cm->fc.nzc_pcat_counts[c][t][b],
+                                  *oldp, newp, upd);
+          if (s > 0)
+            u = 1;
+#endif
+          vp9_write(bc, u, upd);
+          if (u) {
+            /* send/use new probability */
+            write_prob_diff_update(bc, newp, *oldp);
+            *oldp = newp;
+          }
+        }
+      }
+    }
+  }
+}
+
 static void update_nzc_probs(VP9_COMP* cpi,
                              vp9_writer* const bc) {
   update_nzc_probs_common(cpi, bc, 4);
@@ -1602,6 +2000,13 @@
     update_nzc_probs_common(cpi, bc, 16);
   if (cpi->common.txfm_mode > ALLOW_16X16)
     update_nzc_probs_common(cpi, bc, 32);
+#ifdef NZC_PCAT_UPDATE
+  update_nzc_pcat_probs(cpi, bc);
+#endif
+#ifdef NZC_STATS
+  if (!cpi->dummy_packing)
+    update_nzcstats(&cpi->common);
+#endif
 }
 #endif  // CONFIG_CODE_NONZEROCOUNT
 
@@ -2282,6 +2687,8 @@
            cpi->common.fc.nzc_probs_16x16);
   vp9_copy(cpi->common.fc.pre_nzc_probs_32x32,
            cpi->common.fc.nzc_probs_32x32);
+  vp9_copy(cpi->common.fc.pre_nzc_pcat_probs,
+           cpi->common.fc.nzc_pcat_probs);
   // NOTE that if the counts are reset, we also need to uncomment
   // the count updates in the write_nzc function
   /*
@@ -2289,6 +2696,7 @@
   vp9_zero(cpi->common.fc.nzc_counts_8x8);
   vp9_zero(cpi->common.fc.nzc_counts_16x16);
   vp9_zero(cpi->common.fc.nzc_counts_32x32);
+  vp9_zero(cpi->common.fc.nzc_pcat_counts);
   */
 #endif
   vp9_copy(cpi->common.fc.pre_sb_ymode_prob, cpi->common.fc.sb_ymode_prob);
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -1286,6 +1286,7 @@
   vp9_zero(cm->fc.nzc_counts_8x8);
   vp9_zero(cm->fc.nzc_counts_16x16);
   vp9_zero(cm->fc.nzc_counts_32x32);
+  vp9_zero(cm->fc.nzc_pcat_counts);
 #endif
 #if CONFIG_NEW_MVREF
   vp9_zero(cpi->mb_mv_ref_count);
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -114,6 +114,13 @@
 extern void print_nmvstats();
 #endif
 
+#if CONFIG_CODE_NONZEROCOUNT
+#ifdef NZC_STATS
+extern void init_nzcstats();
+extern void print_nzcstats();
+#endif
+#endif
+
 #ifdef SPEEDSTATS
 unsigned int frames_at_speed[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 #endif
@@ -1526,6 +1533,11 @@
 #ifdef NMV_STATS
   init_nmvstats();
 #endif
+#if CONFIG_CODE_NONZEROCOUNT
+#ifdef NZC_STATS
+  init_nzcstats();
+#endif
+#endif
 
   /*Initialize the feed-forward activity masking.*/
   cpi->activity_avg = 90 << 12;
@@ -1702,6 +1714,7 @@
   vp9_zero(cm->fc.nzc_counts_8x8);
   vp9_zero(cm->fc.nzc_counts_16x16);
   vp9_zero(cm->fc.nzc_counts_32x32);
+  vp9_zero(cm->fc.nzc_pcat_counts);
 #endif
 
   return (VP9_PTR) cpi;
@@ -1729,6 +1742,12 @@
 #ifdef NMV_STATS
     if (cpi->pass != 1)
       print_nmvstats();
+#endif
+#if CONFIG_CODE_NONZEROCOUNT
+#ifdef NZC_STATS
+    if (cpi->pass != 1)
+      print_nzcstats();
+#endif
 #endif
 
 #if CONFIG_INTERNAL_STATS
--- a/vp9/encoder/vp9_onyx_int.h
+++ b/vp9/encoder/vp9_onyx_int.h
@@ -121,6 +121,8 @@
            [MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES][NZC16X16_NODES];
   vp9_prob nzc_probs_32x32
            [MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES][NZC32X32_NODES];
+  vp9_prob nzc_pcat_probs[MAX_NZC_CONTEXTS]
+                         [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA];
 #endif
 } CODING_CONTEXT;
 
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -190,6 +190,7 @@
   vp9_copy(cc->nzc_probs_8x8, cm->fc.nzc_probs_8x8);
   vp9_copy(cc->nzc_probs_16x16, cm->fc.nzc_probs_16x16);
   vp9_copy(cc->nzc_probs_32x32, cm->fc.nzc_probs_32x32);
+  vp9_copy(cc->nzc_pcat_probs, cm->fc.nzc_pcat_probs);
 #endif
 }
 
@@ -251,6 +252,7 @@
   vp9_copy(cm->fc.nzc_probs_8x8, cc->nzc_probs_8x8);
   vp9_copy(cm->fc.nzc_probs_16x16, cc->nzc_probs_16x16);
   vp9_copy(cm->fc.nzc_probs_32x32, cc->nzc_probs_32x32);
+  vp9_copy(cm->fc.nzc_pcat_probs, cc->nzc_pcat_probs);
 #endif
 }
 
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -183,44 +183,43 @@
   for (nzc_context = 0; nzc_context < MAX_NZC_CONTEXTS; ++nzc_context) {
     for (r = 0; r < REF_TYPES; ++r) {
       for (b = 0; b < BLOCK_TYPES; ++b) {
-        if (block_size == 4)
+        unsigned int *nzc_costs;
+        if (block_size == 4) {
           vp9_cost_tokens(cost,
                           cpi->common.fc.nzc_probs_4x4[nzc_context][r][b],
                           vp9_nzc4x4_tree);
-        else if (block_size == 8)
+          nzc_costs = cpi->mb.nzc_costs_4x4[nzc_context][r][b];
+        } else if (block_size == 8) {
           vp9_cost_tokens(cost,
                           cpi->common.fc.nzc_probs_8x8[nzc_context][r][b],
                           vp9_nzc8x8_tree);
-        else if (block_size == 16)
+          nzc_costs = cpi->mb.nzc_costs_8x8[nzc_context][r][b];
+        } else if (block_size == 16) {
           vp9_cost_tokens(cost,
                           cpi->common.fc.nzc_probs_16x16[nzc_context][r][b],
                           vp9_nzc16x16_tree);
-        else
+          nzc_costs = cpi->mb.nzc_costs_16x16[nzc_context][r][b];
+        } else {
           vp9_cost_tokens(cost,
                           cpi->common.fc.nzc_probs_32x32[nzc_context][r][b],
                           vp9_nzc32x32_tree);
+          nzc_costs = cpi->mb.nzc_costs_32x32[nzc_context][r][b];
+        }
 
         for (nzc = 0; nzc < values; ++nzc) {
           int e, c, totalcost = 0;
           c = codenzc(nzc);
           totalcost = cost[c];
-          if ((e = extranzcbits(c))) {
-            int x = nzc - basenzcvalue(c);
+          if ((e = vp9_extranzcbits[c])) {
+            int x = nzc - vp9_basenzcvalue[c];
             while (e--) {
-              if ((x >> e) & 1)
-                totalcost += vp9_cost_one(Pcat_nzc[nzc_context][c - 3][e]);
-              else
-                totalcost += vp9_cost_zero(Pcat_nzc[nzc_context][c - 3][e]);
+              totalcost += vp9_cost_bit(
+                  cpi->common.fc.nzc_pcat_probs[nzc_context]
+                                               [c - NZC_TOKENS_NOEXTRA][e],
+                  ((x >> e) & 1));
             }
           }
-          if (block_size == 4)
-            cpi->mb.nzc_costs_4x4[nzc_context][r][b][nzc] = totalcost;
-          else if (block_size == 8)
-            cpi->mb.nzc_costs_8x8[nzc_context][r][b][nzc] = totalcost;
-          else if (block_size == 16)
-            cpi->mb.nzc_costs_16x16[nzc_context][r][b][nzc] = totalcost;
-          else
-            cpi->mb.nzc_costs_32x32[nzc_context][r][b][nzc] = totalcost;
+          nzc_costs[nzc] = totalcost;
         }
       }
     }
--- a/vp9/encoder/vp9_tokenize.c
+++ b/vp9/encoder/vp9_tokenize.c
@@ -36,6 +36,21 @@
 extern vp9_coeff_stats tree_update_hist_32x32[BLOCK_TYPES];
 #endif  /* ENTROPY_STATS */
 
+#if CONFIG_CODE_NONZEROCOUNT
+#ifdef NZC_STATS
+unsigned int nzc_counts_4x4[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                           [NZC4X4_TOKENS];
+unsigned int nzc_counts_8x8[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                           [NZC8X8_TOKENS];
+unsigned int nzc_counts_16x16[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                             [NZC16X16_TOKENS];
+unsigned int nzc_counts_32x32[MAX_NZC_CONTEXTS][REF_TYPES][BLOCK_TYPES]
+                             [NZC32X32_TOKENS];
+unsigned int nzc_pcat_counts[MAX_NZC_CONTEXTS][NZC_TOKENS_EXTRA]
+                            [NZC_BITS_EXTRA][2];
+#endif
+#endif
+
 static TOKENVALUE dct_value_tokens[DCT_MAX_VALUE * 2];
 const TOKENVALUE *vp9_dct_value_tokens_ptr;
 static int dct_value_cost[DCT_MAX_VALUE * 2];