]> granicus.if.org Git - libvpx/commitdiff
Add 8-tap interpolation filter options for intra prediction
authorhui su <huisu@google.com>
Wed, 13 Jan 2016 00:38:58 +0000 (16:38 -0800)
committerhui su <huisu@google.com>
Wed, 3 Feb 2016 22:19:20 +0000 (14:19 -0800)
BD-rate performance improvement (on top of ext-intra):
derflr  0.22%
hevclr  0.36%
hevcmr  0.48%
hevchr  0.37%
stdhd   0.19%

Average speed impact on some derf clips is about 40% slower (on
top of ext-intra). Speed improvment is a to-do.

Change-Id: I8fe3fe8c5e4f60d0462778adbcc15c84dfbe7a25

18 files changed:
vp10/common/blockd.c
vp10/common/blockd.h
vp10/common/entropymode.c
vp10/common/entropymode.h
vp10/common/filter.c
vp10/common/filter.h
vp10/common/pred_common.c
vp10/common/pred_common.h
vp10/common/reconintra.c
vp10/common/reconintra.h
vp10/common/thread_common.c
vp10/decoder/decodeframe.c
vp10/decoder/decodemv.c
vp10/encoder/bitstream.c
vp10/encoder/encodeframe.c
vp10/encoder/encoder.h
vp10/encoder/rd.c
vp10/encoder/rdopt.c

index b6f910ff68f7a800c487e3009c9fa8d73920db3d..5f45077dfd3df97c642a94a13c60f25e32622887 100644 (file)
@@ -8,6 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <math.h>
 #include "vp10/common/blockd.h"
 
 PREDICTION_MODE vp10_left_block_mode(const MODE_INFO *cur_mi,
@@ -134,3 +135,23 @@ void vp10_setup_block_planes(MACROBLOCKD *xd, int ss_x, int ss_y) {
     xd->plane[i].subsampling_y = i ? ss_y : 0;
   }
 }
+
+#if CONFIG_EXT_INTRA
+#define PI 3.14159265
+// Returns whether filter selection is needed for a given
+// intra prediction angle.
+int pick_intra_filter(int angle) {
+  if (angle % 45 == 0)
+    return 0;
+  if (angle > 90 && angle < 180) {
+    return 1;
+  } else {
+    double t = tan(angle * PI / 180.0);
+    double n;
+    if (angle < 90)
+      t = 1 / t;
+    n = floor(t);
+    return (t - n) * 1024 > 1;
+  }
+}
+#endif  // CONFIG_EXT_INTRA
index 27e33bafa6a1fc46ed7db1342f8ac0ee800284ca..24e43ab3329bad9e437d322c0c5bf8cbc3394d2e 100644 (file)
@@ -163,6 +163,8 @@ typedef struct {
 #if CONFIG_EXT_INTRA
   EXT_INTRA_MODE_INFO ext_intra_mode_info;
   int8_t angle_delta[2];
+  // To-Do (huisu): this may be replaced by interp_filter
+  INTRA_FILTER intra_filter;
 #endif  // CONFIG_EXT_INTRA
 
   int_mv mv[2];
@@ -413,6 +415,8 @@ static const TX_TYPE filter_intra_mode_to_tx_type_lookup[FILTER_INTRA_MODES] = {
   ADST_DCT,   // FILTER_D63
   ADST_ADST,  // FILTER_TM
 };
+
+int pick_intra_filter(int angle);
 #endif  // CONFIG_EXT_INTRA
 
 static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type,
index 98e754d475d14d3e32f220a5f6a40f4d8385b973..5c2d51b9a78ee0fdf3217a01e4cfcf9f56419cec 100644 (file)
@@ -1220,9 +1220,7 @@ default_intra_ext_tx_prob[EXT_TX_SETS_INTRA][EXT_TX_SIZES]
     },
   },
 };
-
 #else
-
 const vpx_tree_index vp10_ext_tx_tree[TREE_SIZE(TX_TYPES)] = {
   -DCT_DCT, 2,
   -ADST_ADST, 4,
@@ -1244,6 +1242,24 @@ static const vpx_prob default_inter_ext_tx_prob[EXT_TX_SIZES]
 };
 #endif  // CONFIG_EXT_TX
 
+#if CONFIG_EXT_INTRA
+static const vpx_prob
+default_intra_filter_probs[INTRA_FILTERS + 1][INTRA_FILTERS - 1] = {
+    { 98,  63,  60,  },
+    { 98,  82,  80,  },
+    { 94,  65, 103,  },
+    { 49,  25,  24,  },
+    { 72,  38,  50,  },
+};
+static const vpx_prob default_ext_intra_probs[2] = {230, 230};
+
+const vpx_tree_index vp10_intra_filter_tree[TREE_SIZE(INTRA_FILTERS)] = {
+  -INTRA_FILTER_LINEAR, 2,
+  -INTRA_FILTER_8TAP, 4,
+  -INTRA_FILTER_8TAP_SHARP, -INTRA_FILTER_8TAP_SMOOTH,
+};
+#endif  // CONFIG_EXT_INTRA
+
 #if CONFIG_SUPERTX
 static const vpx_prob default_supertx_prob[PARTITION_SUPERTX_CONTEXTS]
                                           [TX_SIZES] = {
@@ -1258,10 +1274,6 @@ static const struct segmentation_probs default_seg_probs = {
   { 128, 128, 128 },
 };
 
-#if CONFIG_EXT_INTRA
-static  const vpx_prob default_ext_intra_probs[2] = {230, 230};
-#endif  // CONFIG_EXT_INTRA
-
 static void init_mode_probs(FRAME_CONTEXT *fc) {
   vp10_copy(fc->uv_mode_prob, default_uv_probs);
   vp10_copy(fc->y_mode_prob, default_if_y_probs);
@@ -1295,6 +1307,7 @@ static void init_mode_probs(FRAME_CONTEXT *fc) {
   vp10_copy(fc->seg.pred_probs, default_seg_probs.pred_probs);
 #if CONFIG_EXT_INTRA
   vp10_copy(fc->ext_intra_probs, default_ext_intra_probs);
+  vp10_copy(fc->intra_filter_probs, default_intra_filter_probs);
 #endif  // CONFIG_EXT_INTRA
   vp10_copy(fc->inter_ext_tx_prob, default_inter_ext_tx_prob);
   vp10_copy(fc->intra_ext_tx_prob, default_intra_ext_tx_prob);
@@ -1494,6 +1507,10 @@ void vp10_adapt_intra_frame_probs(VP10_COMMON *cm) {
     fc->ext_intra_probs[i] = mode_mv_merge_probs(
               pre_fc->ext_intra_probs[i], counts->ext_intra[i]);
   }
+
+  for (i = 0; i < INTRA_FILTERS + 1; ++i)
+    vpx_tree_merge_probs(vp10_intra_filter_tree, pre_fc->intra_filter_probs[i],
+                         counts->intra_filter[i], fc->intra_filter_probs[i]);
 #endif  // CONFIG_EXT_INTRA
 }
 
index 01dcd5266081e6701fd99c9394a3e8df6b4215e6..fbadc4e0712790f21db96f05bb56ced58862f622 100644 (file)
@@ -103,6 +103,7 @@ typedef struct frame_contexts {
   struct segmentation_probs seg;
 #if CONFIG_EXT_INTRA
   vpx_prob ext_intra_probs[PLANE_TYPES];
+  vpx_prob intra_filter_probs[INTRA_FILTERS + 1][INTRA_FILTERS - 1];
 #endif  // CONFIG_EXT_INTRA
 } FRAME_CONTEXT;
 
@@ -154,6 +155,7 @@ typedef struct FRAME_COUNTS {
   struct seg_counts seg;
 #if CONFIG_EXT_INTRA
   unsigned int ext_intra[PLANE_TYPES][2];
+  unsigned int intra_filter[INTRA_FILTERS + 1][INTRA_FILTERS];
 #endif  // CONFIG_EXT_INTRA
 } FRAME_COUNTS;
 
@@ -182,7 +184,18 @@ extern const vpx_tree_index vp10_switchable_interp_tree
 extern const vpx_tree_index vp10_palette_size_tree[TREE_SIZE(PALETTE_SIZES)];
 extern const vpx_tree_index
 vp10_palette_color_tree[PALETTE_MAX_SIZE - 1][TREE_SIZE(PALETTE_COLORS)];
-
+#if CONFIG_EXT_INTRA
+extern const vpx_tree_index vp10_intra_filter_tree[TREE_SIZE(INTRA_FILTERS)];
+#endif  // CONFIG_EXT_INTRA
+#if CONFIG_EXT_TX
+extern const vpx_tree_index
+    vp10_ext_tx_inter_tree[EXT_TX_SETS_INTER][TREE_SIZE(TX_TYPES)];
+extern const vpx_tree_index
+    vp10_ext_tx_intra_tree[EXT_TX_SETS_INTRA][TREE_SIZE(TX_TYPES)];
+#else
+extern const vpx_tree_index
+    vp10_ext_tx_tree[TREE_SIZE(TX_TYPES)];
+#endif  // CONFIG_EXT_TX
 
 void vp10_setup_past_independence(struct VP10Common *cm);
 
@@ -196,16 +209,6 @@ void vp10_tx_counts_to_branch_counts_16x16(const unsigned int *tx_count_16x16p,
 void vp10_tx_counts_to_branch_counts_8x8(const unsigned int *tx_count_8x8p,
                                     unsigned int (*ct_8x8p)[2]);
 
-#if CONFIG_EXT_TX
-extern const vpx_tree_index
-    vp10_ext_tx_inter_tree[EXT_TX_SETS_INTER][TREE_SIZE(TX_TYPES)];
-extern const vpx_tree_index
-    vp10_ext_tx_intra_tree[EXT_TX_SETS_INTRA][TREE_SIZE(TX_TYPES)];
-#else
-extern const vpx_tree_index
-    vp10_ext_tx_tree[TREE_SIZE(TX_TYPES)];
-#endif  // CONFIG_EXT_TX
-
 static INLINE int vp10_ceil_log2(int n) {
   int i = 1, p = 2;
   while (p < n) {
index a9225b66e283646eb619e928fe2109a718178d7b..aaa7628811edafdbe51ca75b82b9a18d687859a8 100644 (file)
@@ -192,3 +192,12 @@ const InterpKernel *vp10_filter_kernels[SWITCHABLE_FILTERS + 1] = {
 #endif
   bilinear_filters
 };
+
+#if CONFIG_EXT_INTRA
+const InterpKernel *vp10_intra_filter_kernels[INTRA_FILTERS] = {
+    NULL,                     // INTRA_FILTER_LINEAR
+    sub_pel_filters_8,        // INTRA_FILTER_8TAP
+    sub_pel_filters_8sharp,   // INTRA_FILTER_8TAP_SHARP
+    sub_pel_filters_8smooth,  // INTRA_FILTER_8TAP_SMOOTH
+};
+#endif  // CONFIG_EXT_INTRA
index de26b76f01d8d1c7565d8071dc17ae28979d27ee..a272db89455a990e0ca38684008cf2a825a77c92 100644 (file)
@@ -43,6 +43,18 @@ typedef uint8_t INTERP_FILTER;
 
 extern const InterpKernel *vp10_filter_kernels[SWITCHABLE_FILTERS + 1];
 
+#if CONFIG_EXT_INTRA
+typedef enum {
+  INTRA_FILTER_LINEAR,
+  INTRA_FILTER_8TAP,
+  INTRA_FILTER_8TAP_SHARP,
+  INTRA_FILTER_8TAP_SMOOTH,
+  INTRA_FILTERS,
+} INTRA_FILTER;
+
+extern const InterpKernel *vp10_intra_filter_kernels[INTRA_FILTERS];
+#endif  // CONFIG_EXT_INTRA
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
index f9aac8a9e2ec5ba219dce14424fa95fea8699338..4dd68410b30eafcdb5290bdf076809960f9f5554 100644 (file)
@@ -21,10 +21,10 @@ int vp10_get_pred_context_switchable_interp(const MACROBLOCKD *xd) {
   // The prediction flags in these dummy entries are initialized to 0.
   const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
   const int left_type = xd->left_available && is_inter_block(left_mbmi) ?
-                            left_mbmi->interp_filter : SWITCHABLE_FILTERS;
+      left_mbmi->interp_filter : SWITCHABLE_FILTERS;
   const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
   const int above_type = xd->up_available && is_inter_block(above_mbmi) ?
-                             above_mbmi->interp_filter : SWITCHABLE_FILTERS;
+      above_mbmi->interp_filter : SWITCHABLE_FILTERS;
 
   if (left_type == above_type)
     return left_type;
@@ -36,6 +36,85 @@ int vp10_get_pred_context_switchable_interp(const MACROBLOCKD *xd) {
     return SWITCHABLE_FILTERS;
 }
 
+#if CONFIG_EXT_INTRA
+int vp10_get_pred_context_intra_interp(const MACROBLOCKD *xd) {
+  const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
+  const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
+  int left_type = INTRA_FILTERS, above_type = INTRA_FILTERS;
+
+  if (xd->left_available && left_mbmi->sb_type >= BLOCK_8X8) {
+    PREDICTION_MODE mode = left_mbmi->mode;
+    if (is_inter_block(left_mbmi)) {
+      switch (left_mbmi->interp_filter) {
+        case EIGHTTAP:
+          left_type = INTRA_FILTER_8TAP;
+          break;
+        case EIGHTTAP_SMOOTH:
+          left_type = INTRA_FILTER_8TAP_SMOOTH;
+          break;
+        case EIGHTTAP_SHARP:
+          left_type = INTRA_FILTER_8TAP_SHARP;
+          break;
+        case BILINEAR:
+          left_type = INTRA_FILTERS;
+          break;
+        default:
+          break;
+      }
+    } else {
+      if (mode != DC_PRED && mode != TM_PRED) {
+        int p_angle;
+        p_angle = mode_to_angle_map[mode] +
+            left_mbmi->angle_delta[0] * ANGLE_STEP;
+        if (pick_intra_filter(p_angle)) {
+          left_type = left_mbmi->intra_filter;
+        }
+      }
+    }
+  }
+
+  if (xd->up_available && above_mbmi->sb_type >= BLOCK_8X8) {
+    if (is_inter_block(above_mbmi)) {
+      switch (above_mbmi->interp_filter) {
+        case EIGHTTAP:
+          above_type = INTRA_FILTER_8TAP;
+          break;
+        case EIGHTTAP_SMOOTH:
+          above_type = INTRA_FILTER_8TAP_SMOOTH;
+          break;
+        case EIGHTTAP_SHARP:
+          above_type = INTRA_FILTER_8TAP_SHARP;
+          break;
+        case BILINEAR:
+          above_type = INTRA_FILTERS;
+          break;
+        default:
+          break;
+      }
+    } else {
+      PREDICTION_MODE mode = above_mbmi->mode;
+      if (mode != DC_PRED && mode != TM_PRED) {
+        int p_angle;
+        p_angle = mode_to_angle_map[mode] +
+            above_mbmi->angle_delta[0] * ANGLE_STEP;
+        if (pick_intra_filter(p_angle)) {
+          above_type = above_mbmi->intra_filter;
+        }
+      }
+    }
+  }
+
+  if (left_type == above_type)
+    return left_type;
+  else if (left_type == INTRA_FILTERS && above_type != INTRA_FILTERS)
+    return above_type;
+  else if (left_type != INTRA_FILTERS && above_type == INTRA_FILTERS)
+    return left_type;
+  else
+    return INTRA_FILTERS;
+}
+#endif  // CONFIG_EXT_INTRA
+
 // The mode info data structure has a one element border above and to the
 // left of the entries corresponding to real macroblocks.
 // The prediction flags in these dummy entries are initialized to 0.
index 4ebfcdb9787794b22a95f1dfb60e7755700086d8..7d2f28a8e3ce6149165522a4fc4f8317da68ec85 100644 (file)
@@ -68,6 +68,10 @@ static INLINE vpx_prob vp10_get_skip_prob(const VP10_COMMON *cm,
 
 int vp10_get_pred_context_switchable_interp(const MACROBLOCKD *xd);
 
+#if CONFIG_EXT_INTRA
+int vp10_get_pred_context_intra_interp(const MACROBLOCKD *xd);
+#endif  // CONFIG_EXT_INTRA
+
 int vp10_get_intra_inter_context(const MACROBLOCKD *xd);
 
 static INLINE vpx_prob vp10_get_intra_inter_prob(const VP10_COMMON *cm,
index 4be5394d5c65da376cf5372a0ed054c8ca729063..feda3a34ce3afe1102f698d7ad2acb9cbdbfc540 100644 (file)
@@ -248,10 +248,39 @@ static const uint8_t ext_intra_extend_modes[FILTER_INTRA_MODES] = {
   NEED_LEFT | NEED_ABOVE,      // FILTER_TM
 };
 
+static int intra_subpel_interp(int base, int shift, const uint8_t *ref,
+                               int ref_start_idx, int ref_end_idx,
+                               INTRA_FILTER filter_type) {
+  int val, k, idx, filter_idx = 0;
+  const int16_t *filter = NULL;
+
+  if (filter_type == INTRA_FILTER_LINEAR) {
+    val = ref[base] * (256 - shift) + ref[base + 1] * shift;
+    val = ROUND_POWER_OF_TWO(val, 8);
+  } else {
+    filter_idx = ROUND_POWER_OF_TWO(shift, 8 - SUBPEL_BITS);
+    filter = vp10_intra_filter_kernels[filter_type][filter_idx];
+
+    if (filter_idx < (1 << SUBPEL_BITS)) {
+      val = 0;
+      for (k = 0; k < SUBPEL_TAPS; ++k) {
+        idx = base + 1 - (SUBPEL_TAPS / 2) + k;
+        idx = VPXMAX(VPXMIN(idx, ref_end_idx), ref_start_idx);
+        val += ref[idx] * filter[k];
+      }
+      val = ROUND_POWER_OF_TWO(val, FILTER_BITS);
+    } else {
+      val = ref[base + 1];
+    }
+  }
+
+  return val;
+}
+
 // Directional prediction, zone 1: 0 < angle < 90
 static void dr_prediction_z1(uint8_t *dst, ptrdiff_t stride, int bs,
                              const uint8_t *above, const uint8_t *left,
-                             int dx, int dy) {
+                             int dx, int dy, INTRA_FILTER filter_type) {
   int r, c, x, y, base, shift, val;
 
   (void)left;
@@ -262,12 +291,12 @@ static void dr_prediction_z1(uint8_t *dst, ptrdiff_t stride, int bs,
   for (r = 0; r < bs; ++r) {
     y = r + 1;
     for (c = 0; c < bs; ++c) {
-      x = c * 256 - y * dx;
+      x = (c << 8) - y * dx;
       base = x >> 8;
-      shift = x - base * 256;
+      shift = x - (base << 8);
       if (base < 2 * bs - 1) {
-        val =
-            (above[base] * (256 - shift) + above[base + 1] * shift + 128) >> 8;
+        val = intra_subpel_interp(base, shift, above, 0, 2 * bs - 1,
+                                  filter_type);
         dst[c] = clip_pixel(val);
       } else {
         dst[c] = above[2 * bs - 1];
@@ -280,8 +309,8 @@ static void dr_prediction_z1(uint8_t *dst, ptrdiff_t stride, int bs,
 // Directional prediction, zone 2: 90 < angle < 180
 static void dr_prediction_z2(uint8_t *dst, ptrdiff_t stride, int bs,
                              const uint8_t *above, const uint8_t *left,
-                             int dx, int dy) {
-  int r, c, x, y, val1, val2, shift, val, base;
+                             int dx, int dy, INTRA_FILTER filter_type) {
+  int r, c, x, y, shift, val, base;
 
   assert(dx > 0);
   assert(dy > 0);
@@ -289,32 +318,22 @@ static void dr_prediction_z2(uint8_t *dst, ptrdiff_t stride, int bs,
   for (r = 0; r < bs; ++r) {
     for (c = 0; c < bs; ++c) {
       y = r + 1;
-      x = c * 256 - y * dx;
-      if (x >= -256) {
-        if (x <= 0) {
-          val1 = above[-1];
-          val2 = above[0];
-          shift = x + 256;
-        } else {
-          base = x >> 8;
-          val1 = above[base];
-          val2 = above[base + 1];
-          shift = x - base * 256;
-        }
+      x = (c << 8) - y * dx;
+      base = x >> 8;
+      if (base >= -1) {
+        shift = x - (base << 8);
+        val = intra_subpel_interp(base, shift, above, -1, bs - 1, filter_type);
       } else {
         x = c + 1;
-        y = r * 256 - x * dy;
+        y = (r << 8) - x * dy;
         base = y >> 8;
         if (base >= 0) {
-          val1 = left[base];
-          val2 = left[base + 1];
-          shift = y - base * 256;
+          shift = y - (base  << 8);
+          val = intra_subpel_interp(base, shift, left, 0, bs - 1, filter_type);
         } else {
-          val1 = val2 = left[0];
-          shift = 0;
+          val = left[0];
         }
       }
-      val = (val1 * (256 - shift) + val2 * shift + 128) >> 8;
       dst[c] = clip_pixel(val);
     }
     dst += stride;
@@ -324,26 +343,27 @@ static void dr_prediction_z2(uint8_t *dst, ptrdiff_t stride, int bs,
 // Directional prediction, zone 3: 180 < angle < 270
 static void dr_prediction_z3(uint8_t *dst, ptrdiff_t stride, int bs,
                              const uint8_t *above, const uint8_t *left,
-                             int dx, int dy) {
+                             int dx, int dy, INTRA_FILTER filter_type) {
   int r, c, x, y, base, shift, val;
 
   (void)above;
   (void)dx;
+
   assert(dx == 1);
   assert(dy < 0);
 
   for (r = 0; r < bs; ++r) {
     for (c = 0; c < bs; ++c) {
       x = c + 1;
-      y = r * 256 - x * dy;
+      y = (r << 8) - x * dy;
       base = y >> 8;
-      shift = y - base * 256;
+      shift = y - (base << 8);
       if (base < 2 * bs - 1) {
-        val =
-            (left[base] * (256 - shift) + left[base + 1] * shift + 128) >> 8;
+        val = intra_subpel_interp(base, shift, left, 0, 2 * bs - 1,
+                                  filter_type);
         dst[c] = clip_pixel(val);
       } else {
-        dst[c] = left[bs - 1];
+        dst[c] = left[ 2 * bs - 1];
       }
     }
     dst += stride;
@@ -351,7 +371,8 @@ static void dr_prediction_z3(uint8_t *dst, ptrdiff_t stride, int bs,
 }
 
 static void dr_predictor(uint8_t *dst, ptrdiff_t stride, TX_SIZE tx_size,
-                         const uint8_t *above, const uint8_t *left, int angle) {
+                         const uint8_t *above, const uint8_t *left, int angle,
+                         INTRA_FILTER filter_type) {
   double t = 0;
   int dx, dy;
   int bs = 4 << tx_size;
@@ -361,16 +382,16 @@ static void dr_predictor(uint8_t *dst, ptrdiff_t stride, TX_SIZE tx_size,
   if (angle > 0 && angle < 90) {
     dx = -((int)(256 / t));
     dy = 1;
-    dr_prediction_z1(dst, stride, bs, above, left, dx, dy);
+    dr_prediction_z1(dst, stride, bs, above, left, dx, dy, filter_type);
   } else if (angle > 90 && angle < 180) {
     t = -t;
     dx = (int)(256 / t);
     dy = (int)(256 * t);
-    dr_prediction_z2(dst, stride, bs, above, left, dx, dy);
+    dr_prediction_z2(dst, stride, bs, above, left, dx, dy, filter_type);
   } else if (angle > 180 && angle < 270) {
     dx = 1;
     dy = -((int)(256 * t));
-    dr_prediction_z3(dst, stride, bs, above, left, dx, dy);
+    dr_prediction_z3(dst, stride, bs, above, left, dx, dy, filter_type);
   } else if (angle == 90) {
     pred[V_PRED][tx_size](dst, stride, above, left);
   } else if (angle == 180) {
@@ -535,10 +556,40 @@ static void (*filter_intra_predictors[EXT_INTRA_MODES])(uint8_t *dst,
 };
 
 #if CONFIG_VP9_HIGHBITDEPTH
+static int highbd_intra_subpel_interp(int base, int shift, const uint16_t *ref,
+                                      int ref_start_idx, int ref_end_idx,
+                                      INTRA_FILTER filter_type) {
+  int val, k, idx, filter_idx = 0;
+  const int16_t *filter = NULL;
+
+  if (filter_type == INTRA_FILTER_LINEAR) {
+    val = ref[base] * (256 - shift) + ref[base + 1] * shift;
+    val = ROUND_POWER_OF_TWO(val, 8);
+  } else {
+    filter_idx = ROUND_POWER_OF_TWO(shift, 8 - SUBPEL_BITS);
+    filter = vp10_intra_filter_kernels[filter_type][filter_idx];
+
+    if (filter_idx < (1 << SUBPEL_BITS)) {
+      val = 0;
+      for (k = 0; k < SUBPEL_TAPS; ++k) {
+        idx = base + 1 - (SUBPEL_TAPS / 2) + k;
+        idx = VPXMAX(VPXMIN(idx, ref_end_idx), ref_start_idx);
+        val += ref[idx] * filter[k];
+      }
+      val = ROUND_POWER_OF_TWO(val, FILTER_BITS);
+    } else {
+      val = ref[base + 1];
+    }
+  }
+
+  return val;
+}
+
 // Directional prediction, zone 1: 0 < angle < 90
 static void highbd_dr_prediction_z1(uint16_t *dst, ptrdiff_t stride, int bs,
                                     const uint16_t *above, const uint16_t *left,
-                                    int dx, int dy, int bd) {
+                                    int dx, int dy, int bd,
+                                    INTRA_FILTER filter_type) {
   int r, c, x, y, base, shift, val;
 
   (void)left;
@@ -549,12 +600,12 @@ static void highbd_dr_prediction_z1(uint16_t *dst, ptrdiff_t stride, int bs,
   for (r = 0; r < bs; ++r) {
     y = r + 1;
     for (c = 0; c < bs; ++c) {
-      x = c * 256 - y * dx;
+      x = (c << 8) - y * dx;
       base = x >> 8;
-      shift = x - base * 256;
+      shift = x - (base << 8);
       if (base < 2 * bs - 1) {
-        val =
-            (above[base] * (256 - shift) + above[base + 1] * shift + 128) >> 8;
+        val = highbd_intra_subpel_interp(base, shift, above, 0, 2 * bs - 1,
+                                         filter_type);
         dst[c] = clip_pixel_highbd(val, bd);
       } else {
         dst[c] = above[2 * bs - 1];
@@ -567,8 +618,9 @@ static void highbd_dr_prediction_z1(uint16_t *dst, ptrdiff_t stride, int bs,
 // Directional prediction, zone 2: 90 < angle < 180
 static void highbd_dr_prediction_z2(uint16_t *dst, ptrdiff_t stride, int bs,
                                     const uint16_t *above, const uint16_t *left,
-                                    int dx, int dy, int bd) {
-  int r, c, x, y, val1, val2, shift, val, base;
+                                    int dx, int dy, int bd,
+                                    INTRA_FILTER filter_type) {
+  int r, c, x, y, shift, val, base;
 
   assert(dx > 0);
   assert(dy > 0);
@@ -576,32 +628,24 @@ static void highbd_dr_prediction_z2(uint16_t *dst, ptrdiff_t stride, int bs,
   for (r = 0; r < bs; ++r) {
     for (c = 0; c < bs; ++c) {
       y = r + 1;
-      x = c * 256 - y * dx;
-      if (x >= -256) {
-        if (x <= 0) {
-          val1 = above[-1];
-          val2 = above[0];
-          shift = x + 256;
-        } else {
-          base = x >> 8;
-          val1 = above[base];
-          val2 = above[base + 1];
-          shift = x - base * 256;
-        }
+      x = (c << 8) - y * dx;
+      base = x >> 8;
+      if (base >= -1) {
+        shift = x - (base << 8);
+        val = highbd_intra_subpel_interp(base, shift, above, -1, bs - 1,
+                                         filter_type);
       } else {
         x = c + 1;
-        y = r * 256 - x * dy;
+        y = (r << 8) - x * dy;
         base = y >> 8;
         if (base >= 0) {
-          val1 = left[base];
-          val2 = left[base + 1];
-          shift = y - base * 256;
+          shift = y - (base  << 8);
+          val = highbd_intra_subpel_interp(base, shift, left, 0, bs - 1,
+                                           filter_type);
         } else {
-          val1 = val2 = left[0];
-          shift = 0;
+          val = left[0];
         }
       }
-      val = (val1 * (256 - shift) + val2 * shift + 128) >> 8;
       dst[c] = clip_pixel_highbd(val, bd);
     }
     dst += stride;
@@ -611,7 +655,8 @@ static void highbd_dr_prediction_z2(uint16_t *dst, ptrdiff_t stride, int bs,
 // Directional prediction, zone 3: 180 < angle < 270
 static void highbd_dr_prediction_z3(uint16_t *dst, ptrdiff_t stride, int bs,
                                     const uint16_t *above, const uint16_t *left,
-                                    int dx, int dy, int bd) {
+                                    int dx, int dy, int bd,
+                                    INTRA_FILTER filter_type) {
   int r, c, x, y, base, shift, val;
 
   (void)above;
@@ -622,15 +667,15 @@ static void highbd_dr_prediction_z3(uint16_t *dst, ptrdiff_t stride, int bs,
   for (r = 0; r < bs; ++r) {
     for (c = 0; c < bs; ++c) {
       x = c + 1;
-      y = r * 256 - x * dy;
+      y = (r << 8) - x * dy;
       base = y >> 8;
-      shift = y - base * 256;
+      shift = y - (base << 8);
       if (base < 2 * bs - 1) {
-        val =
-            (left[base] * (256 - shift) + left[base + 1] * shift + 128) >> 8;
+        val = highbd_intra_subpel_interp(base, shift, left, 0, 2 * bs - 1,
+                                         filter_type);
         dst[c] = clip_pixel_highbd(val, bd);
       } else {
-        dst[c] = left[bs - 1];
+        dst[c] = left[2 * bs - 1];
       }
     }
     dst += stride;
@@ -663,7 +708,7 @@ static INLINE void highbd_h_predictor(uint16_t *dst, ptrdiff_t stride,
 
 static void highbd_dr_predictor(uint16_t *dst, ptrdiff_t stride, int bs,
                                 const uint16_t *above, const uint16_t *left,
-                                int angle, int bd) {
+                                int angle, int bd, INTRA_FILTER filter) {
   double t = 0;
   int dx, dy;
 
@@ -672,16 +717,16 @@ static void highbd_dr_predictor(uint16_t *dst, ptrdiff_t stride, int bs,
   if (angle > 0 && angle < 90) {
     dx = -((int)(256 / t));
     dy = 1;
-    highbd_dr_prediction_z1(dst, stride, bs, above, left, dx, dy, bd);
+    highbd_dr_prediction_z1(dst, stride, bs, above, left, dx, dy, bd, filter);
   } else if (angle > 90 && angle < 180) {
     t = -t;
     dx = (int)(256 / t);
     dy = (int)(256 * t);
-    highbd_dr_prediction_z2(dst, stride, bs, above, left, dx, dy, bd);
+    highbd_dr_prediction_z2(dst, stride, bs, above, left, dx, dy, bd, filter);
   } else if (angle > 180 && angle < 270) {
     dx = 1;
     dy = -((int)(256 * t));
-    highbd_dr_prediction_z3(dst, stride, bs, above, left, dx, dy, bd);
+    highbd_dr_prediction_z3(dst, stride, bs, above, left, dx, dy, bd, filter);
   } else if (angle == 90) {
     highbd_v_predictor(dst, stride, bs, above, left, bd);
   } else if (angle == 180) {
@@ -961,8 +1006,11 @@ static void build_intra_predictors_high(const MACROBLOCKD *xd,
 
   if (mode != DC_PRED && mode != TM_PRED &&
       xd->mi[0]->mbmi.sb_type >= BLOCK_8X8) {
+    INTRA_FILTER filter = INTRA_FILTER_LINEAR;
+    if (plane == 0 && pick_intra_filter(p_angle))
+      filter = xd->mi[0]->mbmi.intra_filter;
     highbd_dr_predictor(dst, dst_stride, bs, const_above_row, left_col,
-                        p_angle, xd->bd);
+                        p_angle, xd->bd, filter);
     return;
   }
 #endif  // CONFIG_EXT_INTRA
@@ -1118,7 +1166,11 @@ static void build_intra_predictors(const MACROBLOCKD *xd, const uint8_t *ref,
 
   if (mode != DC_PRED && mode != TM_PRED &&
       xd->mi[0]->mbmi.sb_type >= BLOCK_8X8) {
-    dr_predictor(dst, dst_stride, tx_size, const_above_row, left_col, p_angle);
+    INTRA_FILTER filter = INTRA_FILTER_LINEAR;
+    if (plane == 0 && pick_intra_filter(p_angle))
+      filter = xd->mi[0]->mbmi.intra_filter;
+    dr_predictor(dst, dst_stride, tx_size, const_above_row, left_col, p_angle,
+                 filter);
     return;
   }
 #endif  // CONFIG_EXT_INTRA
index f451fb8f7008bf39e324c96d832f7c8c3980c502..77489c1633537180f77b0b18da645f444a2bf3d6 100644 (file)
@@ -25,6 +25,9 @@ void vp10_predict_intra_block(const MACROBLOCKD *xd, int bwl_in, int bhl_in,
                              const uint8_t *ref, int ref_stride,
                              uint8_t *dst, int dst_stride,
                              int aoff, int loff, int plane);
+#if CONFIG_EXT_INTRA
+int pick_intra_filter(int angle);
+#endif  // CONFIG_EXT_INTRA
 #ifdef __cplusplus
 }  // extern "C"
 #endif
index be8b9d1ea744dc2844397836dacd9bc70cb04f65..bacc534591e96df8735c10ff4fdb329252e3bd33 100644 (file)
@@ -520,7 +520,10 @@ void vp10_accumulate_frame_counts(VP10_COMMON *cm, FRAME_COUNTS *counts,
 
 #if CONFIG_EXT_INTRA
   for (i = 0; i < PLANE_TYPES; ++i)
-    for (j = 0; j < 2; j++)
+    for (j = 0; j < 2; ++j)
       cm->counts.ext_intra[i][j] += counts->ext_intra[i][j];
+  for (i = 0; i < INTRA_FILTERS + 1; ++i)
+    for (j = 0; j < INTRA_FILTERS; ++j)
+      cm->counts.intra_filter[i][j] += counts->intra_filter[i][j];
 #endif  // CONFIG_EXT_INTRA
 }
index 36f620ecc171b2642281745264612c3ed128fbf1..91e889688676ca8ebac613d575f6ece0999b1a9c 100644 (file)
@@ -3263,6 +3263,12 @@ static int read_compressed_header(VP10Decoder *pbi, const uint8_t *data,
     for (i = 0; i < PARTITION_TYPES - 1; ++i)
       vp10_diff_update_prob(&r, &fc->partition_prob[j][i]);
 
+#if CONFIG_EXT_INTRA
+  for (i = 0; i < INTRA_FILTERS + 1; ++i)
+    for (j = 0; j < INTRA_FILTERS - 1; ++j)
+      vp10_diff_update_prob(&r, &fc->intra_filter_probs[i][j]);
+#endif  // CONFIG_EXT_INTRA
+
   if (frame_is_intra_only(cm)) {
     vp10_copy(cm->kf_y_prob, vp10_kf_y_mode_prob);
     for (k = 0; k < INTRA_MODES; k++)
index 44b0fc7eca1db5b7c233141b7c488b66e99725d6..07dc7a3cc5d029bb55b3b84321a8aed9b45412c1 100644 (file)
@@ -491,9 +491,23 @@ static void read_intra_frame_mode_info(VP10_COMMON *const cm,
       mbmi->mode = read_intra_mode(r,
           get_y_mode_probs(cm, mi, above_mi, left_mi, 0));
 #if CONFIG_EXT_INTRA
-      if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED)
+      if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED) {
+        int p_angle;
+        const int ctx = vp10_get_pred_context_intra_interp(xd);
         mbmi->angle_delta[0] =
             read_uniform(r, 2 * MAX_ANGLE_DELTAS + 1) - MAX_ANGLE_DELTAS;
+        p_angle = mode_to_angle_map[mbmi->mode] +
+            mbmi->angle_delta[0] * ANGLE_STEP;
+        if (pick_intra_filter(p_angle)) {
+          FRAME_COUNTS *counts = xd->counts;
+          mbmi->intra_filter = vpx_read_tree(r, vp10_intra_filter_tree,
+                                             cm->fc->intra_filter_probs[ctx]);
+          if (counts)
+            ++counts->intra_filter[ctx][mbmi->intra_filter];
+        } else {
+          mbmi->intra_filter = INTRA_FILTER_LINEAR;
+        }
+      }
 #endif  // CONFIG_EXT_INTRA
   }
 
@@ -773,9 +787,23 @@ static void read_intra_block_mode_info(VP10_COMMON *const cm,
       mbmi->mode = read_intra_mode_y(cm, xd, r, size_group_lookup[bsize]);
 #if CONFIG_EXT_INTRA
       mbmi->angle_delta[0] = 0;
-      if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED)
+      if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED) {
+        int p_angle;
         mbmi->angle_delta[0] =
             read_uniform(r, 2 * MAX_ANGLE_DELTAS + 1) - MAX_ANGLE_DELTAS;
+        p_angle =
+            mode_to_angle_map[mbmi->mode] + mbmi->angle_delta[0] * ANGLE_STEP;
+        if (pick_intra_filter(p_angle)) {
+          FRAME_COUNTS *counts = xd->counts;
+          const int ctx = vp10_get_pred_context_intra_interp(xd);
+          mbmi->intra_filter = vpx_read_tree(r, vp10_intra_filter_tree,
+                                             cm->fc->intra_filter_probs[ctx]);
+          if (counts)
+            ++counts->intra_filter[ctx][mbmi->intra_filter];
+        } else {
+          mbmi->intra_filter = INTRA_FILTER_LINEAR;
+        }
+      }
 #endif  // CONFIG_EXT_INTRA
   }
 
index db2e8ee1050b8ea9422d80994de62d27ea1d65d6..4dfd3207e33ed93d5d3d3c611203f29948d9ae0e 100644 (file)
@@ -97,6 +97,9 @@ static struct vp10_token ext_tx_intra_encodings[EXT_TX_SETS_INTRA][TX_TYPES];
 #else
 static struct vp10_token ext_tx_encodings[TX_TYPES];
 #endif  // CONFIG_EXT_TX
+#if CONFIG_EXT_INTRA
+static struct vp10_token intra_filter_encodings[INTRA_FILTERS];
+#endif  // CONFIG_EXT_INTRA
 
 void vp10_encode_token_init() {
 #if CONFIG_EXT_TX
@@ -110,6 +113,9 @@ void vp10_encode_token_init() {
 #else
   vp10_tokens_from_tree(ext_tx_encodings, vp10_ext_tx_tree);
 #endif  // CONFIG_EXT_TX
+#if CONFIG_EXT_INTRA
+  vp10_tokens_from_tree(intra_filter_encodings, vp10_intra_filter_tree);
+#endif  // CONFIG_EXT_INTRA
 }
 
 #if CONFIG_SUPERTX
@@ -936,8 +942,16 @@ static void pack_inter_mode_mvs(VP10_COMP *cpi, const MODE_INFO *mi,
       write_intra_mode(w, mode, cm->fc->y_mode_prob[size_group_lookup[bsize]]);
 #if CONFIG_EXT_INTRA
       if (mode != DC_PRED && mode != TM_PRED) {
+        int p_angle;
+        const int intra_filter_ctx = vp10_get_pred_context_intra_interp(xd);
         write_uniform(w, 2 * MAX_ANGLE_DELTAS + 1,
                       MAX_ANGLE_DELTAS + mbmi->angle_delta[0]);
+        p_angle = mode_to_angle_map[mode] + mbmi->angle_delta[0] * ANGLE_STEP;
+        if (pick_intra_filter(p_angle)) {
+          vp10_write_token(w, vp10_intra_filter_tree,
+                           cm->fc->intra_filter_probs[intra_filter_ctx],
+                           &intra_filter_encodings[mbmi->intra_filter]);
+        }
       }
 #endif  // CONFIG_EXT_INTRA
     } else {
@@ -1188,9 +1202,19 @@ static void write_mb_modes_kf(const VP10_COMMON *cm, const MACROBLOCKD *xd,
     write_intra_mode(w, mbmi->mode,
                      get_y_mode_probs(cm, mi, above_mi, left_mi, 0));
 #if CONFIG_EXT_INTRA
-    if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED)
+    if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED) {
+      int p_angle;
+      const int intra_filter_ctx = vp10_get_pred_context_intra_interp(xd);
       write_uniform(w, 2 * MAX_ANGLE_DELTAS + 1,
                     MAX_ANGLE_DELTAS + mbmi->angle_delta[0]);
+      p_angle =
+          mode_to_angle_map[mbmi->mode] + mbmi->angle_delta[0] * ANGLE_STEP;
+      if (pick_intra_filter(p_angle)) {
+        vp10_write_token(w, vp10_intra_filter_tree,
+                         cm->fc->intra_filter_probs[intra_filter_ctx],
+                         &intra_filter_encodings[mbmi->intra_filter]);
+      }
+    }
 #endif  // CONFIG_EXT_INTRA
   } else {
     const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];
@@ -2292,6 +2316,12 @@ static size_t write_compressed_header(VP10_COMP *cpi, uint8_t *data) {
     prob_diff_update(vp10_partition_tree, fc->partition_prob[i],
                      counts->partition[i], PARTITION_TYPES, &header_bc);
 
+#if CONFIG_EXT_INTRA
+  for (i = 0; i < INTRA_FILTERS + 1; ++i)
+    prob_diff_update(vp10_intra_filter_tree, fc->intra_filter_probs[i],
+                     counts->intra_filter[i], INTRA_FILTERS, &header_bc);
+#endif  // CONFIG_EXT_INTRA
+
   if (frame_is_intra_only(cm)) {
     vp10_copy(cm->kf_y_prob, vp10_kf_y_mode_prob);
     for (i = 0; i < INTRA_MODES; ++i)
index 950c5d366e57d4d3ab0ee8aa2cd6e057898aa7f2..ecf4ea20cd7b67c5e6fc46efa75b9688588294d9 100644 (file)
@@ -4344,6 +4344,24 @@ static void encode_superblock(VP10_COMP *cpi, ThreadData *td,
       sum_intra_stats(td->counts, mi, xd->above_mi, xd->left_mi,
                       frame_is_intra_only(cm));
 
+#if CONFIG_EXT_INTRA
+    if (output_enabled && bsize >= BLOCK_8X8) {
+      FRAME_COUNTS *counts = td->counts;
+      if (mbmi->mode == DC_PRED)
+        ++counts->ext_intra[0][mbmi->ext_intra_mode_info.use_ext_intra_mode[0]];
+      if (mbmi->uv_mode == DC_PRED)
+        ++counts->ext_intra[1][mbmi->ext_intra_mode_info.use_ext_intra_mode[1]];
+      if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED) {
+        int p_angle;
+        const int intra_filter_ctx = vp10_get_pred_context_intra_interp(xd);
+        p_angle = mode_to_angle_map[mbmi->mode] +
+            mbmi->angle_delta[0] * ANGLE_STEP;
+        if (pick_intra_filter(p_angle))
+          ++counts->intra_filter[intra_filter_ctx][mbmi->intra_filter];
+      }
+    }
+#endif  // CONFIG_EXT_INTRA
+
     if (bsize >= BLOCK_8X8 && output_enabled) {
       if (mbmi->palette_mode_info.palette_size[0] > 0) {
         mbmi->palette_mode_info.palette_first_color_idx[0] =
@@ -4436,16 +4454,6 @@ static void encode_superblock(VP10_COMP *cpi, ThreadData *td,
       }
     }
 #endif  // CONFIG_EXT_TX
-#if CONFIG_EXT_INTRA
-    if (bsize >= BLOCK_8X8 && !is_inter_block(mbmi)) {
-      if (mbmi->mode == DC_PRED)
-        ++td->counts->ext_intra[0]
-                              [mbmi->ext_intra_mode_info.use_ext_intra_mode[0]];
-      if (mbmi->uv_mode == DC_PRED)
-        ++td->counts->ext_intra[1]
-                              [mbmi->ext_intra_mode_info.use_ext_intra_mode[1]];
-    }
-#endif  // CONFIG_EXT_INTRA
   }
 
 #if CONFIG_VAR_TX
index d5c432f8dfd14d757a985706b2b68d68d54651ea..c89aee25f65eb595cc837730f05f347be77a133b 100644 (file)
@@ -496,10 +496,6 @@ typedef struct VP10_COMP {
                                                  [PALETTE_COLORS];
   int palette_uv_color_cost[PALETTE_MAX_SIZE - 1][PALETTE_COLOR_CONTEXTS]
                                                   [PALETTE_COLORS];
-
-  int multi_arf_allowed;
-  int multi_arf_enabled;
-  int multi_arf_last_grp_enabled;
 #if CONFIG_EXT_TX
   int inter_tx_type_costs[EXT_TX_SETS_INTER][EXT_TX_SIZES][TX_TYPES];
   int intra_tx_type_costs[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
@@ -508,6 +504,13 @@ typedef struct VP10_COMP {
   int intra_tx_type_costs[EXT_TX_SIZES][TX_TYPES][TX_TYPES];
   int inter_tx_type_costs[EXT_TX_SIZES][TX_TYPES];
 #endif  // CONFIG_EXT_TX
+#if CONFIG_EXT_INTRA
+  int intra_filter_cost[INTRA_FILTERS + 1][INTRA_FILTERS];
+#endif  // CONFIG_EXT_INTRA
+
+  int multi_arf_allowed;
+  int multi_arf_enabled;
+  int multi_arf_last_grp_enabled;
 #if CONFIG_VP9_TEMPORAL_DENOISING
   VP9_DENOISER denoiser;
 #endif
index 9dede8ee1f5c32f360e42a67a5df05e2e5f5faa0..1aac71908bc7a27bbc4b843f05c5d73d73de47a5 100644 (file)
@@ -137,6 +137,11 @@ static void fill_mode_costs(VP10_COMP *cpi) {
                      vp10_ext_tx_tree);
   }
 #endif  // CONFIG_EXT_TX
+#if CONFIG_EXT_INTRA
+  for (i = 0; i < INTRA_FILTERS + 1; ++i)
+    vp10_cost_tokens(cpi->intra_filter_cost[i], fc->intra_filter_probs[i],
+                     vp10_intra_filter_tree);
+#endif  // CONFIG_EXT_INTRA
 }
 
 static void fill_token_costs(vp10_coeff_cost *c,
index 1a6e6c541d2309e998a7a4e052a70dbbef213bce..58d72d40285c4ece61d7162bf014cea6aba9400c 100644 (file)
@@ -1699,6 +1699,7 @@ static int64_t rd_pick_intra_sub_8x8_y_mode(VP10_COMP *cpi, MACROBLOCK *mb,
 
 #if CONFIG_EXT_INTRA
   mic->mbmi.ext_intra_mode_info.use_ext_intra_mode[0] = 0;
+  mic->mbmi.intra_filter = INTRA_FILTER_LINEAR;
 #endif  // CONFIG_EXT_INTRA
 
   // Pick modes for each sub-block (of size 4x4, 4x8, or 8x4) in an 8x8 block.
@@ -1815,7 +1816,9 @@ static int64_t rd_pick_intra_angle_sby(VP10_COMP *cpi, MACROBLOCK *x,
   MODE_INFO *const mic = xd->mi[0];
   MB_MODE_INFO *mbmi = &mic->mbmi;
   int this_rate, this_rate_tokenonly, s;
-  int angle_delta, best_angle_delta = 0;
+  int angle_delta, best_angle_delta = 0, p_angle;
+  const int intra_filter_ctx = vp10_get_pred_context_intra_interp(xd);
+  INTRA_FILTER filter, best_filter = INTRA_FILTER_LINEAR;
   const double rd_adjust = 1.2;
   int64_t this_distortion, this_rd, sse_dummy;
   TX_SIZE best_tx_size = mic->mbmi.tx_size;
@@ -1831,46 +1834,97 @@ static int64_t rd_pick_intra_angle_sby(VP10_COMP *cpi, MACROBLOCK *x,
 
     for (i = 0; i < level1; ++i) {
       mic->mbmi.angle_delta[0] = deltas_level1[i];
-      super_block_yrd(cpi, x, &this_rate_tokenonly, &this_distortion,
-                      &s, NULL, bsize,
-                      (i == 0 && best_rd < INT64_MAX) ? best_rd * rd_adjust :
-                          best_rd);
-      if (this_rate_tokenonly == INT_MAX) {
-        if (i == 0)
-          break;
-        else
+      p_angle = mode_to_angle_map[mbmi->mode] +
+          mbmi->angle_delta[0] * ANGLE_STEP;
+      for (filter = INTRA_FILTER_LINEAR; filter < INTRA_FILTERS; ++filter) {
+        if (!pick_intra_filter(p_angle) && filter != INTRA_FILTER_LINEAR)
           continue;
-      }
-      this_rate = this_rate_tokenonly + rate_overhead;
-      this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion);
-      if (i == 0 && best_rd < INT64_MAX && this_rd > best_rd * rd_adjust)
-        break;
-      if (this_rd < best_rd) {
-        best_i              = i;
-        best_rd             = this_rd;
-        best_angle_delta    = mbmi->angle_delta[0];
-        best_tx_size        = mbmi->tx_size;
-        best_tx_type        = mbmi->tx_type;
-        *rate               = this_rate;
-        *rate_tokenonly     = this_rate_tokenonly;
-        *distortion         = this_distortion;
-        *skippable          = s;
+        mic->mbmi.intra_filter = filter;
+        super_block_yrd(cpi, x, &this_rate_tokenonly, &this_distortion,
+                        &s, NULL, bsize,
+                        (i == 0 && filter == INTRA_FILTER_LINEAR &&
+                         best_rd < INT64_MAX) ? best_rd * rd_adjust : best_rd);
+        if (this_rate_tokenonly == INT_MAX) {
+          if (i == 0 && filter == INTRA_FILTER_LINEAR)
+            return best_rd;
+          else
+            continue;
+        }
+        this_rate = this_rate_tokenonly + rate_overhead +
+            cpi->intra_filter_cost[intra_filter_ctx][filter];
+        this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion);
+        if (i == 0 && filter == INTRA_FILTER_LINEAR &&
+            best_rd < INT64_MAX && this_rd > best_rd * rd_adjust)
+          return best_rd;
+        if (this_rd < best_rd) {
+          best_i              = i;
+          best_rd             = this_rd;
+          best_angle_delta    = mbmi->angle_delta[0];
+          best_tx_size        = mbmi->tx_size;
+          best_filter         = mbmi->intra_filter;
+          best_tx_type        = mbmi->tx_type;
+          *rate               = this_rate;
+          *rate_tokenonly     = this_rate_tokenonly;
+          *distortion         = this_distortion;
+          *skippable          = s;
+        }
       }
     }
 
     if (best_i >= 0) {
       for (j = 0; j < level2; ++j) {
         mic->mbmi.angle_delta[0] = deltas_level2[best_i][j];
+        p_angle = mode_to_angle_map[mbmi->mode] +
+            mbmi->angle_delta[0] * ANGLE_STEP;
+        for (filter = INTRA_FILTER_LINEAR; filter < INTRA_FILTERS; ++filter) {
+          mic->mbmi.intra_filter = filter;
+          if (!pick_intra_filter(p_angle) && filter != INTRA_FILTER_LINEAR)
+            continue;
+          super_block_yrd(cpi, x, &this_rate_tokenonly, &this_distortion,
+                          &s, NULL, bsize, best_rd);
+          if (this_rate_tokenonly == INT_MAX)
+            continue;
+          this_rate = this_rate_tokenonly + rate_overhead +
+              cpi->intra_filter_cost[intra_filter_ctx][filter];
+          this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion);
+          if (this_rd < best_rd) {
+            best_rd             = this_rd;
+            best_angle_delta    = mbmi->angle_delta[0];
+            best_tx_size        = mbmi->tx_size;
+            best_filter         = mbmi->intra_filter;
+            best_tx_type        = mbmi->tx_type;
+            *rate               = this_rate;
+            *rate_tokenonly     = this_rate_tokenonly;
+            *distortion         = this_distortion;
+            *skippable          = s;
+          }
+        }
+      }
+    }
+  } else {
+    for (angle_delta = -MAX_ANGLE_DELTAS; angle_delta <= MAX_ANGLE_DELTAS;
+        ++angle_delta) {
+      mbmi->angle_delta[0] = angle_delta;
+      p_angle = mode_to_angle_map[mbmi->mode] +
+          mbmi->angle_delta[0] * ANGLE_STEP;
+      for (filter = INTRA_FILTER_LINEAR; filter < INTRA_FILTERS; ++filter) {
+        mic->mbmi.intra_filter = filter;
+        if (!pick_intra_filter(p_angle) && filter != INTRA_FILTER_LINEAR)
+          continue;
         super_block_yrd(cpi, x, &this_rate_tokenonly, &this_distortion,
                         &s, NULL, bsize, best_rd);
         if (this_rate_tokenonly == INT_MAX)
           continue;
-        this_rate = this_rate_tokenonly + rate_overhead;
+
+        this_rate = this_rate_tokenonly + rate_overhead +
+            cpi->intra_filter_cost[intra_filter_ctx][filter];
         this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion);
+
         if (this_rd < best_rd) {
           best_rd             = this_rd;
           best_angle_delta    = mbmi->angle_delta[0];
           best_tx_size        = mbmi->tx_size;
+          best_filter         = mbmi->intra_filter;
           best_tx_type        = mbmi->tx_type;
           *rate               = this_rate;
           *rate_tokenonly     = this_rate_tokenonly;
@@ -1879,34 +1933,11 @@ static int64_t rd_pick_intra_angle_sby(VP10_COMP *cpi, MACROBLOCK *x,
         }
       }
     }
-  } else {
-    for (angle_delta = -MAX_ANGLE_DELTAS; angle_delta <= MAX_ANGLE_DELTAS;
-        ++angle_delta) {
-      mic->mbmi.angle_delta[0] = angle_delta;
-
-      super_block_yrd(cpi, x, &this_rate_tokenonly, &this_distortion,
-                      &s, NULL, bsize, best_rd);
-      if (this_rate_tokenonly == INT_MAX)
-        continue;
-
-      this_rate = this_rate_tokenonly + rate_overhead;
-      this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion);
-
-      if (this_rd < best_rd) {
-        best_rd             = this_rd;
-        best_angle_delta    = mbmi->angle_delta[0];
-        best_tx_size        = mbmi->tx_size;
-        best_tx_type        = mbmi->tx_type;
-        *rate               = this_rate;
-        *rate_tokenonly     = this_rate_tokenonly;
-        *distortion         = this_distortion;
-        *skippable          = s;
-      }
-    }
   }
 
   mbmi->tx_size = best_tx_size;
   mbmi->angle_delta[0] = best_angle_delta;
+  mic->mbmi.intra_filter = best_filter;
   mbmi->tx_type = best_tx_type;
 
   if (*rate_tokenonly < INT_MAX) {
@@ -2031,8 +2062,10 @@ static int64_t rd_pick_intra_sby_mode(VP10_COMP *cpi, MACROBLOCK *x,
   int64_t this_distortion, this_rd;
   TX_SIZE best_tx = TX_4X4;
 #if CONFIG_EXT_INTRA
+  const int intra_filter_ctx = vp10_get_pred_context_intra_interp(xd);
   EXT_INTRA_MODE_INFO ext_intra_mode_info;
   int is_directional_mode, rate_overhead, best_angle_delta = 0;
+  INTRA_FILTER best_filter = INTRA_FILTER_LINEAR;
   uint8_t directional_mode_skip_mask[INTRA_MODES];
   const int src_stride = x->plane[0].src.stride;
   const uint8_t *src = x->plane[0].src.buf;
@@ -2127,10 +2160,17 @@ static int64_t rd_pick_intra_sby_mode(VP10_COMP *cpi, MACROBLOCK *x,
 #if CONFIG_EXT_INTRA
     if (mode == DC_PRED && ALLOW_FILTER_INTRA_MODES)
       this_rate += vp10_cost_bit(cpi->common.fc->ext_intra_probs[0], 0);
-    if (is_directional_mode)
+    if (is_directional_mode) {
+      int p_angle;
       this_rate += write_uniform_cost(2 * MAX_ANGLE_DELTAS + 1,
                                       MAX_ANGLE_DELTAS +
                                       mic->mbmi.angle_delta[0]);
+      p_angle = mode_to_angle_map[mic->mbmi.mode] +
+          mic->mbmi.angle_delta[0] * ANGLE_STEP;
+      if (pick_intra_filter(p_angle))
+        this_rate +=
+            cpi->intra_filter_cost[intra_filter_ctx][mic->mbmi.intra_filter];
+    }
 #endif  // CONFIG_EXT_INTRA
     this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion);
 
@@ -2140,6 +2180,7 @@ static int64_t rd_pick_intra_sby_mode(VP10_COMP *cpi, MACROBLOCK *x,
       best_tx         = mic->mbmi.tx_size;
 #if CONFIG_EXT_INTRA
       best_angle_delta = mic->mbmi.angle_delta[0];
+      best_filter     = mic->mbmi.intra_filter;
 #endif  // CONFIG_EXT_INTRA
       best_tx_type    = mic->mbmi.tx_type;
       *rate           = this_rate;
@@ -2178,6 +2219,7 @@ static int64_t rd_pick_intra_sby_mode(VP10_COMP *cpi, MACROBLOCK *x,
   mic->mbmi.tx_size = best_tx;
 #if CONFIG_EXT_INTRA
   mic->mbmi.angle_delta[0] = best_angle_delta;
+  mic->mbmi.intra_filter = best_filter;
 #endif  // CONFIG_EXT_INTRA
   mic->mbmi.tx_type = best_tx_type;
   mic->mbmi.palette_mode_info.palette_size[0] =
@@ -6240,10 +6282,17 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi,
 
       rate2 = rate_y + intra_mode_cost[mbmi->mode] + rate_uv_intra[uv_tx];
 #if CONFIG_EXT_INTRA
-      if (is_directional_mode)
+      if (is_directional_mode) {
+        int p_angle;
+        const int intra_filter_ctx = vp10_get_pred_context_intra_interp(xd);
         rate2 += write_uniform_cost(2 * MAX_ANGLE_DELTAS + 1,
                                     MAX_ANGLE_DELTAS +
                                     mbmi->angle_delta[0]);
+        p_angle = mode_to_angle_map[mbmi->mode] +
+            mbmi->angle_delta[0] * ANGLE_STEP;
+        if (pick_intra_filter(p_angle))
+          rate2 += cpi->intra_filter_cost[intra_filter_ctx][mbmi->intra_filter];
+      }
 
       if (mbmi->mode == DC_PRED && ALLOW_FILTER_INTRA_MODES) {
         rate2 += vp10_cost_bit(cm->fc->ext_intra_probs[0],