From 3b1c76680235e61f4c3ecf0abb191064177a59f0 Mon Sep 17 00:00:00 2001 From: hui su Date: Tue, 12 Jan 2016 16:38:58 -0800 Subject: [PATCH] Add 8-tap interpolation filter options for intra prediction 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 --- vp10/common/blockd.c | 21 ++++ vp10/common/blockd.h | 4 + vp10/common/entropymode.c | 29 ++++-- vp10/common/entropymode.h | 25 +++-- vp10/common/filter.c | 9 ++ vp10/common/filter.h | 12 +++ vp10/common/pred_common.c | 83 ++++++++++++++- vp10/common/pred_common.h | 4 + vp10/common/reconintra.c | 200 +++++++++++++++++++++++------------- vp10/common/reconintra.h | 3 + vp10/common/thread_common.c | 5 +- vp10/decoder/decodeframe.c | 6 ++ vp10/decoder/decodemv.c | 32 +++++- vp10/encoder/bitstream.c | 32 +++++- vp10/encoder/encodeframe.c | 28 +++-- vp10/encoder/encoder.h | 11 +- vp10/encoder/rd.c | 5 + vp10/encoder/rdopt.c | 151 ++++++++++++++++++--------- 18 files changed, 498 insertions(+), 162 deletions(-) diff --git a/vp10/common/blockd.c b/vp10/common/blockd.c index b6f910ff6..5f45077df 100644 --- a/vp10/common/blockd.c +++ b/vp10/common/blockd.c @@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include #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 diff --git a/vp10/common/blockd.h b/vp10/common/blockd.h index 27e33bafa..24e43ab33 100644 --- a/vp10/common/blockd.h +++ b/vp10/common/blockd.h @@ -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, diff --git a/vp10/common/entropymode.c b/vp10/common/entropymode.c index 98e754d47..5c2d51b9a 100644 --- a/vp10/common/entropymode.c +++ b/vp10/common/entropymode.c @@ -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 } diff --git a/vp10/common/entropymode.h b/vp10/common/entropymode.h index 01dcd5266..fbadc4e07 100644 --- a/vp10/common/entropymode.h +++ b/vp10/common/entropymode.h @@ -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) { diff --git a/vp10/common/filter.c b/vp10/common/filter.c index a9225b66e..aaa762881 100644 --- a/vp10/common/filter.c +++ b/vp10/common/filter.c @@ -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 diff --git a/vp10/common/filter.h b/vp10/common/filter.h index de26b76f0..a272db894 100644 --- a/vp10/common/filter.h +++ b/vp10/common/filter.h @@ -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 diff --git a/vp10/common/pred_common.c b/vp10/common/pred_common.c index f9aac8a9e..4dd68410b 100644 --- a/vp10/common/pred_common.c +++ b/vp10/common/pred_common.c @@ -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. diff --git a/vp10/common/pred_common.h b/vp10/common/pred_common.h index 4ebfcdb97..7d2f28a8e 100644 --- a/vp10/common/pred_common.h +++ b/vp10/common/pred_common.h @@ -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, diff --git a/vp10/common/reconintra.c b/vp10/common/reconintra.c index 4be5394d5..feda3a34c 100644 --- a/vp10/common/reconintra.c +++ b/vp10/common/reconintra.c @@ -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 diff --git a/vp10/common/reconintra.h b/vp10/common/reconintra.h index f451fb8f7..77489c163 100644 --- a/vp10/common/reconintra.h +++ b/vp10/common/reconintra.h @@ -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 diff --git a/vp10/common/thread_common.c b/vp10/common/thread_common.c index be8b9d1ea..bacc53459 100644 --- a/vp10/common/thread_common.c +++ b/vp10/common/thread_common.c @@ -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 } diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c index 36f620ecc..91e889688 100644 --- a/vp10/decoder/decodeframe.c +++ b/vp10/decoder/decodeframe.c @@ -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++) diff --git a/vp10/decoder/decodemv.c b/vp10/decoder/decodemv.c index 44b0fc7ec..07dc7a3cc 100644 --- a/vp10/decoder/decodemv.c +++ b/vp10/decoder/decodemv.c @@ -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 } diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c index db2e8ee10..4dfd3207e 100644 --- a/vp10/encoder/bitstream.c +++ b/vp10/encoder/bitstream.c @@ -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) diff --git a/vp10/encoder/encodeframe.c b/vp10/encoder/encodeframe.c index 950c5d366..ecf4ea20c 100644 --- a/vp10/encoder/encodeframe.c +++ b/vp10/encoder/encodeframe.c @@ -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 diff --git a/vp10/encoder/encoder.h b/vp10/encoder/encoder.h index d5c432f8d..c89aee25f 100644 --- a/vp10/encoder/encoder.h +++ b/vp10/encoder/encoder.h @@ -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 diff --git a/vp10/encoder/rd.c b/vp10/encoder/rd.c index 9dede8ee1..1aac71908 100644 --- a/vp10/encoder/rd.c +++ b/vp10/encoder/rd.c @@ -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, diff --git a/vp10/encoder/rdopt.c b/vp10/encoder/rdopt.c index 1a6e6c541..58d72d402 100644 --- a/vp10/encoder/rdopt.c +++ b/vp10/encoder/rdopt.c @@ -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], -- 2.40.0