From: Yue Chen Date: Tue, 13 Aug 2013 17:44:34 +0000 (-0700) Subject: Recursive extrapolation filter X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f99fbcd6820eadc0bf4cc312495a0fa882a83a3e;p=libvpx Recursive extrapolation filter The recursive intra filter is implemented. 6 extrapolation intra filters are added as extra modes for 4x4 and 8x8 blocks. Signaling bits are added at the block level to indicate if a normal intra mode is switched to recursive intra filter mode. They are entropy coded by maintaining a backward adaptive probability table showing the usage of recursive filters at different block-sizes and different intra modes. Bit-rate reduction: +0.458% (derf) Change-Id: I1b8e00405ea1494002ca40de1db52c51259012c4 --- diff --git a/configure b/configure index b84b3cd9f..517ce2691 100755 --- a/configure +++ b/configure @@ -251,6 +251,7 @@ EXPERIMENT_LIST=" non420 alpha interintra + filterintra " CONFIG_LIST=" external_build diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h index 10d12794a..716638da3 100644 --- a/vp9/common/vp9_blockd.h +++ b/vp9/common/vp9_blockd.h @@ -89,6 +89,15 @@ static INLINE int is_inter_mode(MB_PREDICTION_MODE mode) { return mode >= NEARESTMV && mode <= NEWMV; } +#if CONFIG_FILTERINTRA +static INLINE int is_filter_allowed(MB_PREDICTION_MODE mode) { + return mode != DC_PRED && + mode != D45_PRED && + mode != D27_PRED && + mode != D63_PRED; +} +#endif + #define VP9_INTRA_MODES (TM_PRED + 1) #define VP9_INTER_MODES (1 + NEWMV - NEARESTMV) @@ -160,6 +169,9 @@ typedef struct { MB_PREDICTION_MODE mode, uv_mode; #if CONFIG_INTERINTRA MB_PREDICTION_MODE interintra_mode, interintra_uv_mode; +#endif +#if CONFIG_FILTERINTRA + int filterbit, uv_filterbit; #endif MV_REFERENCE_FRAME ref_frame[2]; TX_SIZE txfm_size; @@ -187,6 +199,9 @@ typedef struct { typedef struct { MB_MODE_INFO mbmi; +#if CONFIG_FILTERINTRA + int b_filter_info[4]; +#endif union b_mode_info bmi[4]; } MODE_INFO; diff --git a/vp9/common/vp9_entropymode.c b/vp9/common/vp9_entropymode.c index fb30e018c..b989d34e5 100644 --- a/vp9/common/vp9_entropymode.c +++ b/vp9/common/vp9_entropymode.c @@ -214,6 +214,16 @@ const vp9_prob vp9_kf_y_mode_prob[VP9_INTRA_MODES] } }; +#if CONFIG_FILTERINTRA +const vp9_prob vp9_default_filterintra_prob[TX_SIZES][VP9_INTRA_MODES] = { + // DC V H D45 D135 D117 D153 D27 D63 TM + {160, 160, 160, 160, 160, 160, 160, 160, 160, 160}, // TX_4X4 + {180, 180, 180, 180, 180, 180, 180, 180, 180, 180}, // TX_8X8 + {200, 200, 200, 200, 200, 200, 200, 200, 200, 200}, // TX_16X16 + {220, 220, 220, 220, 220, 220, 220, 220, 220, 220}, // TX_32X32 +}; +#endif + static const vp9_prob default_inter_mode_probs[INTER_MODE_CONTEXTS] [VP9_INTER_MODES - 1] = { {2, 173, 34}, // 0 = both zero mv @@ -339,6 +349,9 @@ void vp9_init_mbmode_probs(VP9_COMMON *cm) { #if CONFIG_INTERINTRA cm->fc.interintra_prob = VP9_DEF_INTERINTRA_PROB; #endif +#if CONFIG_FILTERINTRA + vp9_copy(cm->fc.filterintra_prob, vp9_default_filterintra_prob); +#endif } const vp9_tree_index vp9_switchable_interp_tree[VP9_SWITCHABLE_FILTERS*2-2] = { @@ -467,6 +480,12 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) { counts->interintra); } #endif +#if CONFIG_FILTERINTRA + for (i = 0; i < TX_SIZES; ++i) + for (j = 0; j < VP9_INTRA_MODES; ++j) + fc->filterintra_prob[i][j] = update_ct2(pre_fc->filterintra_prob[i][j], + counts->filterintra[i][j]); +#endif } static void set_default_lf_deltas(struct loopfilter *lf) { diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index cd9183570..171ce9827 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -56,6 +56,9 @@ typedef struct frame_contexts { #if CONFIG_INTERINTRA vp9_prob interintra_prob; #endif +#if CONFIG_FILTERINTRA + vp9_prob filterintra_prob[TX_SIZES][VP9_INTRA_MODES]; +#endif } FRAME_CONTEXT; typedef struct { @@ -78,6 +81,9 @@ typedef struct { #if CONFIG_INTERINTRA unsigned int interintra[2]; #endif +#if CONFIG_FILTERINTRA + unsigned int filterintra[TX_SIZES][VP9_INTRA_MODES][2]; +#endif } FRAME_COUNTS; diff --git a/vp9/common/vp9_reconintra.c b/vp9/common/vp9_reconintra.c index 059d9fc18..32857a378 100644 --- a/vp9/common/vp9_reconintra.c +++ b/vp9/common/vp9_reconintra.c @@ -401,11 +401,110 @@ static void build_intra_predictors(uint8_t *src, int src_stride, } } +#if CONFIG_FILTERINTRA +static void filter_intra_predictors(uint8_t *ypred_ptr, int y_stride, int bs, + uint8_t *yabove_row, uint8_t *yleft_col, + int mode) { + static const int prec_bits = 10; + static const int round_val = 511; + static const int taps[10][3] = { + {438 , 660, -352}, // DC + {1014, 565, -559}, // V + {312, 1017, -312}, // H + {0, 0, 0}, // D45 + {478, 483, 153}, // D135 + {699, 470, -122}, // D117 + {356, 707, 35}, // D153 + {0, 0, 0}, // D27 + {0, 0, 0}, // D63 + {877, 896, -812} // TM + }; + int k, r, c; + int pred[17][17]; + int mean, ipred; + const int c1 = taps[mode][0]; + const int c2 = taps[mode][1]; + const int c3 = taps[mode][2]; + + k = 0; + mean = 0; + while (k < bs) { + mean = mean + (int)yleft_col[r]; + mean = mean + (int)yabove_row[c]; + k++; + } + mean = (mean + bs) / (2 * bs); + + for (r = 0; r < bs; r++) + pred[r + 1][0] = (int)yleft_col[r] - mean; + + for (c = 0; c < bs + 1; c++) + pred[0][c] = (int)yabove_row[c - 1] - mean; + + for (r = 1; r < bs + 1; r++) + for (c = 1; c < bs + 1; c++) { + ipred = c1 * pred[r - 1][c] + c2 * pred[r][c - 1] + + c3 * pred[r - 1][c - 1]; + pred[r][c] = ipred < 0 ? -((-ipred + round_val) >> prec_bits) : + ((ipred + round_val) >> prec_bits); + } + + for (r = 0; r < bs; r++) { + for (c = 0; c < bs; c++) { + ipred = pred[r + 1][c + 1] + mean; + ypred_ptr[c] = clip_pixel(ipred); + } + ypred_ptr += y_stride; + } +} + +static void build_filter_intra_predictors(uint8_t *src, int src_stride, + uint8_t *pred_ptr, int stride, + MB_PREDICTION_MODE mode, TX_SIZE txsz, + int up_available, int left_available, + int right_available) { + int i; + DECLARE_ALIGNED_ARRAY(16, uint8_t, left_col, 64); + DECLARE_ALIGNED_ARRAY(16, uint8_t, yabove_data, 128 + 16); + uint8_t *above_row = yabove_data + 16; + const int bs = 4 << txsz; + + if (left_available) { + for (i = 0; i < bs; i++) + left_col[i] = src[i * src_stride - 1]; + } else { + vpx_memset(left_col, 129, bs); + } + + if (up_available) { + uint8_t *above_ptr = src - src_stride; + if (bs == 4 && right_available && left_available) { + above_row = above_ptr; + } else { + vpx_memcpy(above_row, above_ptr, bs); + if (bs == 4 && right_available) + vpx_memcpy(above_row + bs, above_ptr + bs, bs); + else + vpx_memset(above_row + bs, above_row[bs - 1], bs); + above_row[-1] = left_available ? above_ptr[-1] : 129; + } + } else { + vpx_memset(above_row, 127, bs * 2); + above_row[-1] = 127; + } + + filter_intra_predictors(pred_ptr, stride, bs, above_row, left_col, mode); +} +#endif + void vp9_predict_intra_block(MACROBLOCKD *xd, int block_idx, int bwl_in, TX_SIZE tx_size, int mode, +#if CONFIG_FILTERINTRA + int filterbit, +#endif uint8_t *reference, int ref_stride, uint8_t *predictor, int pre_stride) { const int bwl = bwl_in - tx_size; @@ -413,14 +512,30 @@ void vp9_predict_intra_block(MACROBLOCKD *xd, const int have_top = (block_idx >> bwl) || xd->up_available; const int have_left = (block_idx & wmask) || xd->left_available; const int have_right = ((block_idx & wmask) != wmask); +#if CONFIG_FILTERINTRA + int filterflag = is_filter_allowed(mode) && (tx_size <= TX_8X8) && filterbit; +#endif assert(bwl >= 0); +#if CONFIG_FILTERINTRA + if (!filterflag) { +#endif build_intra_predictors(reference, ref_stride, predictor, pre_stride, mode, tx_size, have_top, have_left, have_right); +#if CONFIG_FILTERINTRA + } else { + build_filter_intra_predictors(reference, ref_stride, + predictor, pre_stride, + mode, + tx_size, + have_top, have_left, + have_right); + } +#endif } #if CONFIG_INTERINTRA @@ -549,7 +664,7 @@ static void combine_interintra(MB_PREDICTION_MODE mode, // Break down rectangular intra prediction for joint spatio-temporal prediction // into two square intra predictions. -void build_intra_predictors_for_interintra(uint8_t *src, int src_stride, +static void build_intra_predictors_for_interintra(uint8_t *src, int src_stride, uint8_t *pred_ptr, int stride, MB_PREDICTION_MODE mode, int bw, int bh, diff --git a/vp9/common/vp9_reconintra.h b/vp9/common/vp9_reconintra.h index 527fff25b..3ca6e2cc4 100644 --- a/vp9/common/vp9_reconintra.h +++ b/vp9/common/vp9_reconintra.h @@ -25,7 +25,11 @@ void vp9_predict_intra_block(MACROBLOCKD *xd, int block_idx, int bwl_in, TX_SIZE tx_size, - int mode, uint8_t *ref, int ref_stride, + int mode, +#if CONFIG_FILTERINTRA + int filterbit, +#endif + uint8_t *ref, int ref_stride, uint8_t *predictor, int pre_stride); #if CONFIG_INTERINTRA void vp9_build_interintra_predictors(MACROBLOCKD *xd, diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c index 26b831a9f..e0be588ac 100644 --- a/vp9/decoder/vp9_decodemv.c +++ b/vp9/decoder/vp9_decodemv.c @@ -169,6 +169,13 @@ static void read_intra_frame_mode_info(VP9D_COMP *pbi, MODE_INFO *m, const MB_PREDICTION_MODE L = xd->left_available ? left_block_mode(m, 0) : DC_PRED; mbmi->mode = read_intra_mode(r, vp9_kf_y_mode_prob[A][L]); +#if CONFIG_FILTERINTRA + if ((mbmi->txfm_size <= TX_8X8) && is_filter_allowed(mbmi->mode)) + mbmi->filterbit = vp9_read(r, + cm->fc.filterintra_prob[mbmi->txfm_size][mbmi->mode]); + else + mbmi->filterbit = 0; +#endif } else { // Only 4x4, 4x8, 8x4 blocks const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; // 1 or 2 @@ -188,13 +195,34 @@ static void read_intra_frame_mode_info(VP9D_COMP *pbi, MODE_INFO *m, m->bmi[ib + 2].as_mode = b_mode; if (num_4x4_w == 2) m->bmi[ib + 1].as_mode = b_mode; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(b_mode)) + m->b_filter_info[ib] = vp9_read(r, + cm->fc.filterintra_prob[0][b_mode]); + else + m->b_filter_info[ib] = 0; + if (num_4x4_h == 2) + m->b_filter_info[ib + 2] = m->b_filter_info[ib]; + if (num_4x4_w == 2) + m->b_filter_info[ib + 1] = m->b_filter_info[ib]; +#endif } } mbmi->mode = m->bmi[3].as_mode; +#if CONFIG_FILTERINTRA + mbmi->filterbit = m->b_filter_info[3]; +#endif } mbmi->uv_mode = read_intra_mode(r, vp9_kf_uv_mode_prob[mbmi->mode]); +#if CONFIG_FILTERINTRA + if ((get_uv_tx_size(mbmi) <= TX_8X8) && is_filter_allowed(mbmi->uv_mode)) + mbmi->uv_filterbit = vp9_read(r, + cm->fc.filterintra_prob[get_uv_tx_size(mbmi)][mbmi->uv_mode]); + else + mbmi->uv_filterbit = 0; +#endif } static int read_mv_component(vp9_reader *r, @@ -390,6 +418,15 @@ static void read_intra_block_mode_info(VP9D_COMP *pbi, MODE_INFO *mi, const int size_group = size_group_lookup[bsize]; mbmi->mode = read_intra_mode(r, cm->fc.y_mode_prob[size_group]); cm->counts.y_mode[size_group][mbmi->mode]++; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mbmi->mode) && (mbmi->txfm_size <= TX_8X8)) { + mbmi->filterbit = vp9_read(r, + cm->fc.filterintra_prob[mbmi->txfm_size][mbmi->mode]); + cm->counts.filterintra[mbmi->txfm_size][mbmi->mode][mbmi->filterbit]++; + } else { + mbmi->filterbit = 0; + } +#endif } else { // Only 4x4, 4x8, 8x4 blocks const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; // 1 or 2 @@ -407,13 +444,40 @@ static void read_intra_block_mode_info(VP9D_COMP *pbi, MODE_INFO *mi, mi->bmi[ib + 2].as_mode = b_mode; if (num_4x4_w == 2) mi->bmi[ib + 1].as_mode = b_mode; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(b_mode)) { + mi->b_filter_info[ib] = vp9_read(r, + cm->fc.filterintra_prob[0][b_mode]); + cm->counts.filterintra[0][b_mode][mi->b_filter_info[ib]]++; + } else { + mi->b_filter_info[ib] = 0; + } + + if (num_4x4_h == 2) + mi->b_filter_info[ib + 2] = mi->b_filter_info[ib]; + if (num_4x4_w == 2) + mi->b_filter_info[ib + 1] = mi->b_filter_info[ib]; +#endif } } mbmi->mode = mi->bmi[3].as_mode; +#if CONFIG_FILTERINTRA + mbmi->filterbit = mi->b_filter_info[3]; +#endif } mbmi->uv_mode = read_intra_mode(r, cm->fc.uv_mode_prob[mbmi->mode]); cm->counts.uv_mode[mbmi->mode][mbmi->uv_mode]++; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mbmi->uv_mode) && (get_uv_tx_size(mbmi) <= TX_8X8)) { + mbmi->uv_filterbit = vp9_read(r, + cm->fc.filterintra_prob[get_uv_tx_size(mbmi)][mbmi->uv_mode]); + cm->counts.filterintra[get_uv_tx_size(mbmi)] + [mbmi->uv_mode][mbmi->uv_filterbit]++; + } else { + mbmi->uv_filterbit = 0; + } +#endif } static int read_is_inter_block(VP9D_COMP *pbi, int segment_id, vp9_reader *r) { diff --git a/vp9/decoder/vp9_decodframe.c b/vp9/decoder/vp9_decodframe.c index 13e5fc821..e9d6f74d4 100644 --- a/vp9/decoder/vp9_decodframe.c +++ b/vp9/decoder/vp9_decodframe.c @@ -140,12 +140,22 @@ static void decode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, const int tx_ib = raster_block >> tx_size; const int mode = plane == 0 ? mi->mbmi.mode : mi->mbmi.uv_mode; +#if CONFIG_FILTERINTRA + int fbit = 0; +#endif if (plane == 0 && mi->mbmi.sb_type < BLOCK_8X8) { assert(bsize == BLOCK_8X8); b_mode = mi->bmi[raster_block].as_mode; +#if CONFIG_FILTERINTRA + fbit = mi->b_filter_info[raster_block]; +#endif } else { b_mode = mode; +#if CONFIG_FILTERINTRA + if (tx_size <= TX_8X8) + fbit = plane == 0? mi->mbmi.filterbit: mi->mbmi.uv_filterbit; +#endif } if (xd->mb_to_right_edge < 0 || xd->mb_to_bottom_edge < 0) @@ -153,6 +163,9 @@ static void decode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, plane_b_size = b_width_log2(bsize) - pd->subsampling_x; vp9_predict_intra_block(xd, tx_ib, plane_b_size, tx_size, b_mode, +#if CONFIG_FILTERINTRA + fbit, +#endif dst, pd->dst.stride, dst, pd->dst.stride); diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index b379838c9..27821ff25 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -447,6 +447,12 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, MODE_INFO *m, vp9_writer *bc) { if (bsize >= BLOCK_8X8) { write_intra_mode(bc, mode, pc->fc.y_mode_prob[size_group_lookup[bsize]]); +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mode) && (mi->txfm_size <= TX_8X8)) { + vp9_write(bc, mi->filterbit, + pc->fc.filterintra_prob[mi->txfm_size][mode]); + } +#endif } else { int idx, idy; const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize]; @@ -455,10 +461,22 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, MODE_INFO *m, vp9_writer *bc) { for (idx = 0; idx < 2; idx += num_4x4_blocks_wide) { const MB_PREDICTION_MODE bm = m->bmi[idy * 2 + idx].as_mode; write_intra_mode(bc, bm, pc->fc.y_mode_prob[0]); +#if CONFIG_FILTERINTRA + if (is_filter_allowed(bm)) { + vp9_write(bc, m->b_filter_info[idy * 2 + idx], + pc->fc.filterintra_prob[0][bm]); + } +#endif } } } write_intra_mode(bc, mi->uv_mode, pc->fc.uv_mode_prob[mode]); +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mi->uv_mode) && (get_uv_tx_size(mi) <= TX_8X8)) { + vp9_write(bc, mi->uv_filterbit, + pc->fc.filterintra_prob[get_uv_tx_size(mi)][mi->uv_mode]); + } +#endif } else { vp9_prob *mv_ref_p; encode_ref_frame(cpi, bc); @@ -570,6 +588,11 @@ static void write_mb_modes_kf(const VP9_COMP *cpi, MODE_INFO *m, const MB_PREDICTION_MODE L = xd->left_available ? left_block_mode(m, 0) : DC_PRED; write_intra_mode(bc, ym, vp9_kf_y_mode_prob[A][L]); +#if CONFIG_FILTERINTRA + if (is_filter_allowed(ym) && (m->mbmi.txfm_size <= TX_8X8)) + vp9_write(bc, m->mbmi.filterbit, + c->fc.filterintra_prob[m->mbmi.txfm_size][ym]); +#endif } else { int idx, idy; const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[m->mbmi.sb_type]; @@ -585,11 +608,21 @@ static void write_mb_modes_kf(const VP9_COMP *cpi, MODE_INFO *m, ++intra_mode_stats[A][L][bm]; #endif write_intra_mode(bc, bm, vp9_kf_y_mode_prob[A][L]); +#if CONFIG_FILTERINTRA + if (is_filter_allowed(bm)) + vp9_write(bc, m->b_filter_info[i], c->fc.filterintra_prob[0][bm]); +#endif } } } write_intra_mode(bc, m->mbmi.uv_mode, vp9_kf_uv_mode_prob[ym]); +#if CONFIG_FILTERINTRA + if (is_filter_allowed(m->mbmi.uv_mode) && + (get_uv_tx_size(&(m->mbmi)) <= TX_8X8)) + vp9_write(bc, m->mbmi.uv_filterbit, + c->fc.filterintra_prob[get_uv_tx_size(&(m->mbmi))][m->mbmi.uv_mode]); +#endif } static void write_modes_b(VP9_COMP *cpi, MODE_INFO *m, vp9_writer *bc, diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 63ff00d99..32d6b0d62 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -2009,6 +2009,10 @@ static void init_encode_frame_mb_context(VP9_COMP *cpi) { xd->mode_info_context->mbmi.mode = DC_PRED; xd->mode_info_context->mbmi.uv_mode = DC_PRED; +#if CONFIG_FILTERINTRA + xd->mode_info_context->mbmi.filterbit = 0; + xd->mode_info_context->mbmi.uv_filterbit = 0; +#endif vp9_zero(cpi->y_mode_count) vp9_zero(cpi->y_uv_mode_count) @@ -2024,6 +2028,9 @@ static void init_encode_frame_mb_context(VP9_COMP *cpi) { vp9_zero(cpi->interintra_count); vp9_zero(cpi->interintra_select_count); #endif +#if CONFIG_FILTERINTRA + vp9_zero(cm->counts.filterintra); +#endif // Note: this memset assumes above_context[0], [1] and [2] // are allocated as part of the same buffer. @@ -2515,13 +2522,30 @@ static void sum_intra_stats(VP9_COMP *cpi, MACROBLOCK *x) { const MACROBLOCKD *xd = &x->e_mbd; const MB_PREDICTION_MODE m = xd->mode_info_context->mbmi.mode; const MB_PREDICTION_MODE uvm = xd->mode_info_context->mbmi.uv_mode; +#if CONFIG_FILTERINTRA + const int uv_fbit = xd->mode_info_context->mbmi.uv_filterbit; + int fbit = xd->mode_info_context->mbmi.filterbit; +#endif ++cpi->y_uv_mode_count[m][uvm]; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(uvm) && + (get_uv_tx_size(&(xd->mode_info_context->mbmi)) <= TX_8X8)) + ++cpi->common.counts.filterintra + [get_uv_tx_size(&(xd->mode_info_context->mbmi))] + [uvm][uv_fbit]; +#endif if (xd->mode_info_context->mbmi.sb_type >= BLOCK_8X8) { const BLOCK_SIZE_TYPE bsize = xd->mode_info_context->mbmi.sb_type; const int bwl = b_width_log2(bsize), bhl = b_height_log2(bsize); const int bsl = MIN(bwl, bhl); ++cpi->y_mode_count[MIN(bsl, 3)][m]; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(m) && + (xd->mode_info_context->mbmi.txfm_size <= TX_8X8)) + ++cpi->common.counts.filterintra[xd->mode_info_context->mbmi.txfm_size] + [m][fbit]; +#endif } else { int idx, idy; int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[ @@ -2532,6 +2556,12 @@ static void sum_intra_stats(VP9_COMP *cpi, MACROBLOCK *x) { for (idx = 0; idx < 2; idx += num_4x4_blocks_wide) { int m = xd->mode_info_context->bmi[idy * 2 + idx].as_mode; ++cpi->y_mode_count[0][m]; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(m)) { + fbit = xd->mode_info_context->b_filter_info[idy * 2 + idx]; + ++cpi->common.counts.filterintra[0][m][fbit]; + } +#endif } } } diff --git a/vp9/encoder/vp9_encodemb.c b/vp9/encoder/vp9_encodemb.c index 40b0a4e5a..5a23b0beb 100644 --- a/vp9/encoder/vp9_encodemb.c +++ b/vp9/encoder/vp9_encodemb.c @@ -640,6 +640,9 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, const int16_t *scan, *iscan; TX_TYPE tx_type; MB_PREDICTION_MODE mode; +#if CONFIG_FILTERINTRA + int fbit = 0; +#endif const int bwl = b_width_log2(bsize) - pd->subsampling_x, bw = 1 << bwl; const int twl = bwl - tx_size, twmask = (1 << twl) - 1; int xoff, yoff; @@ -660,6 +663,9 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, scan = vp9_default_scan_32x32; iscan = vp9_default_iscan_32x32; mode = plane == 0 ? mbmi->mode : mbmi->uv_mode; +#if CONFIG_FILTERINTRA + fbit = plane == 0 ? mbmi->filterbit : mbmi->uv_filterbit; +#endif block >>= 6; xoff = 32 * (block & twmask); yoff = 32 * (block >> twl); @@ -667,6 +673,9 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, src = p->src.buf + yoff * p->src.stride + xoff; src_diff = p->src_diff + 4 * bw * yoff + xoff; vp9_predict_intra_block(xd, block, bwl, TX_32X32, mode, +#if CONFIG_FILTERINTRA + fbit, +#endif dst, pd->dst.stride, dst, pd->dst.stride); vp9_subtract_block(32, 32, src_diff, bw * 4, src, p->src.stride, dst, pd->dst.stride); @@ -685,6 +694,9 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, scan = get_scan_16x16(tx_type); iscan = get_iscan_16x16(tx_type); mode = plane == 0 ? mbmi->mode : mbmi->uv_mode; +#if CONFIG_FILTERINTRA + fbit = plane == 0 ? mbmi->filterbit : mbmi->uv_filterbit; +#endif block >>= 4; xoff = 16 * (block & twmask); yoff = 16 * (block >> twl); @@ -692,6 +704,9 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, src = p->src.buf + yoff * p->src.stride + xoff; src_diff = p->src_diff + 4 * bw * yoff + xoff; vp9_predict_intra_block(xd, block, bwl, TX_16X16, mode, +#if CONFIG_FILTERINTRA + fbit, +#endif dst, pd->dst.stride, dst, pd->dst.stride); vp9_subtract_block(16, 16, src_diff, bw * 4, src, p->src.stride, dst, pd->dst.stride); @@ -714,6 +729,9 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, scan = get_scan_8x8(tx_type); iscan = get_iscan_8x8(tx_type); mode = plane == 0 ? mbmi->mode : mbmi->uv_mode; +#if CONFIG_FILTERINTRA + fbit = plane == 0 ? mbmi->filterbit : mbmi->uv_filterbit; +#endif block >>= 2; xoff = 8 * (block & twmask); yoff = 8 * (block >> twl); @@ -721,6 +739,9 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, src = p->src.buf + yoff * p->src.stride + xoff; src_diff = p->src_diff + 4 * bw * yoff + xoff; vp9_predict_intra_block(xd, block, bwl, TX_8X8, mode, +#if CONFIG_FILTERINTRA + fbit, +#endif dst, pd->dst.stride, dst, pd->dst.stride); vp9_subtract_block(8, 8, src_diff, bw * 4, src, p->src.stride, dst, pd->dst.stride); @@ -747,12 +768,22 @@ void encode_block_intra(int plane, int block, BLOCK_SIZE_TYPE bsize, else mode = plane == 0 ? mbmi->mode : mbmi->uv_mode; +#if CONFIG_FILTERINTRA + if (mbmi->sb_type < BLOCK_8X8 && plane == 0) + fbit = xd->mode_info_context->b_filter_info[block]; + else + fbit = plane == 0 ? mbmi->filterbit : mbmi->uv_filterbit; +#endif + xoff = 4 * (block & twmask); yoff = 4 * (block >> twl); dst = pd->dst.buf + yoff * pd->dst.stride + xoff; src = p->src.buf + yoff * p->src.stride + xoff; src_diff = p->src_diff + 4 * bw * yoff + xoff; vp9_predict_intra_block(xd, block, bwl, TX_4X4, mode, +#if CONFIG_FILTERINTRA + fbit, +#endif dst, pd->dst.stride, dst, pd->dst.stride); vp9_subtract_block(4, 4, src_diff, bw * 4, src, p->src.stride, dst, pd->dst.stride); diff --git a/vp9/encoder/vp9_mbgraph.c b/vp9/encoder/vp9_mbgraph.c index 314e195d2..b8d801695 100644 --- a/vp9/encoder/vp9_mbgraph.c +++ b/vp9/encoder/vp9_mbgraph.c @@ -146,7 +146,13 @@ static int find_best_16x16_intra(VP9_COMP *cpi, unsigned int err; xd->mode_info_context->mbmi.mode = mode; +#if CONFIG_FILTERINTRA + xd->mode_info_context->mbmi.filterbit = 0; +#endif vp9_predict_intra_block(xd, 0, 2, TX_16X16, mode, +#if CONFIG_FILTERINTRA + 0, +#endif x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].dst.buf, xd->plane[0].dst.stride); err = vp9_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride, diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_onyx_int.h index d8282de09..9f948f2e6 100644 --- a/vp9/encoder/vp9_onyx_int.h +++ b/vp9/encoder/vp9_onyx_int.h @@ -99,6 +99,9 @@ typedef struct { #if CONFIG_INTERINTRA vp9_prob interintra_prob; #endif +#if CONFIG_FILTERINTRA + vp9_prob filterintra_prob[TX_SIZES][VP9_INTRA_MODES]; +#endif } CODING_CONTEXT; typedef struct { diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index dece23b66..c6e5b2dde 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -109,6 +109,9 @@ void vp9_save_coding_context(VP9_COMP *cpi) { #if CONFIG_INTERINTRA cc->interintra_prob = cm->fc.interintra_prob; #endif +#if CONFIG_FILTERINTRA + vp9_copy(cc->filterintra_prob, cm->fc.filterintra_prob); +#endif } void vp9_restore_coding_context(VP9_COMP *cpi) { @@ -151,6 +154,9 @@ void vp9_restore_coding_context(VP9_COMP *cpi) { #if CONFIG_INTERINTRA cm->fc.interintra_prob = cc->interintra_prob; #endif +#if CONFIG_FILTERINTRA + vp9_copy(cm->fc.filterintra_prob, cc->filterintra_prob); +#endif } void vp9_setup_key_frame(VP9_COMP *cpi) { diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 1994360a4..c6b6443e3 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -1155,6 +1155,9 @@ static int conditional_skipintra(MB_PREDICTION_MODE mode, static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib, MB_PREDICTION_MODE *best_mode, +#if CONFIG_FILTERINTRA + int *best_fbit, +#endif int *bmode_costs, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, int *bestrate, int *bestratey, @@ -1182,6 +1185,9 @@ static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib, const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize]; const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize]; int idx, idy, block; +#if CONFIG_FILTERINTRA + int mode_ext, fbit; +#endif uint8_t best_dst[8 * 8]; assert(ib < 4); @@ -1190,6 +1196,7 @@ static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib, vpx_memcpy(tl, l, sizeof(tl)); xd->mode_info_context->mbmi.txfm_size = TX_4X4; +#if !CONFIG_FILTERINTRA for (mode = DC_PRED; mode <= TM_PRED; ++mode) { int64_t this_rd; int ratey = 0; @@ -1201,6 +1208,20 @@ static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib, } rate = bmode_costs[mode]; +#else + for (mode_ext = 2 * DC_PRED; mode_ext <= 2 * TM_PRED + 1; ++mode_ext) { + int64_t this_rd; + int ratey = 0; + + fbit = mode_ext & 1; + mode = mode_ext >> 1; + if (fbit && !is_filter_allowed(mode)) + continue; + + rate = bmode_costs[mode]; + if (is_filter_allowed(mode)) + rate += vp9_cost_bit(cpi->common.fc.filterintra_prob[0][mode], fbit); +#endif distortion = 0; vpx_memcpy(tempa, ta, sizeof(ta)); @@ -1215,11 +1236,17 @@ static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib, block = ib + idy * 2 + idx; xd->mode_info_context->bmi[block].as_mode = mode; +#if CONFIG_FILTERINTRA + xd->mode_info_context->b_filter_info[block] = fbit; +#endif src_diff = raster_block_offset_int16(xd, BLOCK_8X8, 0, block, p->src_diff); coeff = BLOCK_OFFSET(x->plane[0].coeff, block, 16); vp9_predict_intra_block(xd, block, 1, TX_4X4, mode, +#if CONFIG_FILTERINTRA + fbit, +#endif x->skip_encode ? src : dst, x->skip_encode ? src_stride : dst_stride, dst, dst_stride); @@ -1264,6 +1291,9 @@ static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib, *bestdistortion = distortion; best_rd = this_rd; *best_mode = mode; +#if CONFIG_FILTERINTRA + *best_fbit = fbit; +#endif vpx_memcpy(a, tempa, sizeof(tempa)); vpx_memcpy(l, templ, sizeof(templ)); for (idy = 0; idy < num_4x4_blocks_high * 4; ++idy) @@ -1314,6 +1344,9 @@ static int64_t rd_pick_intra_sub_8x8_y_mode(VP9_COMP * const cpi, for (idx = 0; idx < 2; idx += num_4x4_blocks_wide) { const int mis = xd->mode_info_stride; MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); +#if CONFIG_FILTERINTRA + int UNINITIALIZED_IS_SAFE(best_fbit); +#endif int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(ry); int64_t UNINITIALIZED_IS_SAFE(d), this_rd; i = idy * 2 + idx; @@ -1326,7 +1359,11 @@ static int64_t rd_pick_intra_sub_8x8_y_mode(VP9_COMP * const cpi, bmode_costs = mb->y_mode_costs[A][L]; } - this_rd = rd_pick_intra4x4block(cpi, mb, i, &best_mode, bmode_costs, + this_rd = rd_pick_intra4x4block(cpi, mb, i, &best_mode, +#if CONFIG_FILTERINTRA + &best_fbit, +#endif + bmode_costs, t_above + idx, t_left + idy, &r, &ry, &d, bsize, best_rd - total_rd); @@ -1343,6 +1380,13 @@ static int64_t rd_pick_intra_sub_8x8_y_mode(VP9_COMP * const cpi, mic->bmi[i + j * 2].as_mode = best_mode; for (j = 1; j < num_4x4_blocks_wide; ++j) mic->bmi[i + j].as_mode = best_mode; +#if CONFIG_FILTERINTRA + mic->b_filter_info[i] = best_fbit; + for (j = 1; j < num_4x4_blocks_high; ++j) + mic->b_filter_info[i + j * 2] = best_fbit; + for (j = 1; j < num_4x4_blocks_wide; ++j) + mic->b_filter_info[i + j] = best_fbit; +#endif if (total_rd >= best_rd) return INT64_MAX; @@ -1353,6 +1397,9 @@ static int64_t rd_pick_intra_sub_8x8_y_mode(VP9_COMP * const cpi, *rate_y = tot_rate_y; *distortion = total_distortion; xd->mode_info_context->mbmi.mode = mic->bmi[3].as_mode; +#if CONFIG_FILTERINTRA + xd->mode_info_context->mbmi.filterbit = mic->b_filter_info[3]; +#endif return RDCOST(mb->rdmult, mb->rddiv, cost, total_distortion); } @@ -1371,16 +1418,31 @@ static int64_t rd_pick_intra_sby_mode(VP9_COMP *cpi, MACROBLOCK *x, TX_SIZE UNINITIALIZED_IS_SAFE(best_tx); int i; int *bmode_costs = x->mbmode_cost; +#if CONFIG_FILTERINTRA + int mode_ext, fbit, fbit_selected = 0; +#endif if (cpi->sf.tx_size_search_method == USE_FULL_RD) for (i = 0; i < TX_MODES; i++) tx_cache[i] = INT64_MAX; /* Y Search for intra prediction mode */ +#if !CONFIG_FILTERINTRA for (mode = DC_PRED; mode <= TM_PRED; mode++) { int64_t local_tx_cache[TX_MODES]; MODE_INFO *const mic = xd->mode_info_context; const int mis = xd->mode_info_stride; +#else + for (mode_ext = 2 * DC_PRED; mode_ext <= 2 * TM_PRED + 1; mode_ext++) { + int64_t local_tx_cache[TX_MODES]; + MODE_INFO *const mic = xd->mode_info_context; + const int mis = xd->mode_info_stride; + + fbit = mode_ext & 1; + mode = mode_ext >> 1; + if (fbit && !is_filter_allowed(mode)) + continue; +#endif if (cpi->common.frame_type == KEY_FRAME) { const MB_PREDICTION_MODE A = above_block_mode(mic, 0, mis); @@ -1390,6 +1452,9 @@ static int64_t rd_pick_intra_sby_mode(VP9_COMP *cpi, MACROBLOCK *x, bmode_costs = x->y_mode_costs[A][L]; } x->e_mbd.mode_info_context->mbmi.mode = mode; +#if CONFIG_FILTERINTRA + x->e_mbd.mode_info_context->mbmi.filterbit = fbit; +#endif super_block_yrd(cpi, x, &this_rate_tokenonly, &this_distortion, &s, NULL, bsize, local_tx_cache, best_rd); @@ -1398,10 +1463,20 @@ static int64_t rd_pick_intra_sby_mode(VP9_COMP *cpi, MACROBLOCK *x, continue; this_rate = this_rate_tokenonly + bmode_costs[mode]; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mode) && + (xd->mode_info_context->mbmi.txfm_size <= TX_8X8)) + this_rate += vp9_cost_bit(cpi->common.fc.filterintra_prob + [xd->mode_info_context->mbmi.txfm_size][mode], + fbit); +#endif this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion); if (this_rd < best_rd) { mode_selected = mode; +#if CONFIG_FILTERINTRA + fbit_selected = fbit; +#endif best_rd = this_rd; best_tx = x->e_mbd.mode_info_context->mbmi.txfm_size; *rate = this_rate; @@ -1422,6 +1497,9 @@ static int64_t rd_pick_intra_sby_mode(VP9_COMP *cpi, MACROBLOCK *x, } x->e_mbd.mode_info_context->mbmi.mode = mode_selected; +#if CONFIG_FILTERINTRA + x->e_mbd.mode_info_context->mbmi.filterbit = fbit_selected; +#endif x->e_mbd.mode_info_context->mbmi.txfm_size = best_tx; return best_rd; @@ -1472,16 +1550,40 @@ static int64_t rd_pick_intra_sbuv_mode(VP9_COMP *cpi, MACROBLOCK *x, MB_PREDICTION_MODE last_mode = bsize <= BLOCK_8X8 ? TM_PRED : cpi->sf.last_chroma_intra_mode; +#if CONFIG_FILTERINTRA + int mode_ext, fbit = 0, fbit_selected = 0; + for (mode_ext = 2 * DC_PRED; mode_ext <= 2 * last_mode + 1; mode_ext++) { + mode = mode_ext >> 1; + fbit = mode_ext & 1; + + if (fbit && !is_filter_allowed(mode)) + continue; + if (fbit && is_filter_allowed(mode) && + (get_uv_tx_size(&(x->e_mbd.mode_info_context->mbmi)) != TX_4X4)) + continue; + + x->e_mbd.mode_info_context->mbmi.uv_filterbit = fbit; +#else for (mode = DC_PRED; mode <= last_mode; mode++) { +#endif x->e_mbd.mode_info_context->mbmi.uv_mode = mode; super_block_uvrd(&cpi->common, x, &this_rate_tokenonly, &this_distortion, &s, NULL, bsize); this_rate = this_rate_tokenonly + x->intra_uv_mode_cost[cpi->common.frame_type][mode]; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mode) && + (get_uv_tx_size(&(x->e_mbd.mode_info_context->mbmi)) <= TX_8X8)) + this_rate += vp9_cost_bit(cpi->common.fc.filterintra_prob + [get_uv_tx_size(&(x->e_mbd.mode_info_context->mbmi))][mode], fbit); +#endif this_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_distortion); if (this_rd < best_rd) { mode_selected = mode; +#if CONFIG_FILTERINTRA + fbit_selected = fbit; +#endif best_rd = this_rd; *rate = this_rate; *rate_tokenonly = this_rate_tokenonly; @@ -1491,6 +1593,9 @@ static int64_t rd_pick_intra_sbuv_mode(VP9_COMP *cpi, MACROBLOCK *x, } x->e_mbd.mode_info_context->mbmi.uv_mode = mode_selected; +#if CONFIG_FILTERINTRA + x->e_mbd.mode_info_context->mbmi.uv_filterbit = fbit_selected; +#endif return best_rd; } @@ -3286,6 +3391,9 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, int64_t dist_uv[TX_SIZES]; int skip_uv[TX_SIZES]; MB_PREDICTION_MODE mode_uv[TX_SIZES]; +#if CONFIG_FILTERINTRA + int fbit_uv[TX_SIZES]; +#endif struct scale_factors scale_factor[4]; unsigned int ref_frame_mask = 0; unsigned int mode_mask = 0; @@ -3598,12 +3706,18 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, &rate_uv_tokenonly[TX_4X4], &dist_uv[TX_4X4], &skip_uv[TX_4X4], &mode_uv[TX_4X4]); +#if CONFIG_FILTERINTRA + fbit_uv[TX_4X4] = mbmi->uv_filterbit; +#endif } rate2 += rate_uv_intra[TX_4X4]; rate_uv = rate_uv_tokenonly[TX_4X4]; distortion2 += dist_uv[TX_4X4]; distortion_uv = dist_uv[TX_4X4]; mbmi->uv_mode = mode_uv[TX_4X4]; +#if CONFIG_FILTERINTRA + mbmi->uv_filterbit = fbit_uv[TX_4X4]; +#endif tx_cache[ONLY_4X4] = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); for (i = 0; i < TX_MODES; ++i) tx_cache[i] = tx_cache[ONLY_4X4]; @@ -3630,9 +3744,39 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, if (conditional_skipintra(mbmi->mode, best_intra_mode)) continue; } +#if CONFIG_FILTERINTRA + mbmi->filterbit = 0; +#endif super_block_yrd(cpi, x, &rate_y, &distortion_y, &skippable, NULL, bsize, tx_cache, best_rd); +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mbmi->mode)) { + int temp_txfm_size, skippable_fil, rate_y_fil = 0; + int64_t distortion_y_fil = 0; + int64_t tx_cache_fil[TX_MODES]; + int rate0, rate1; + temp_txfm_size = mbmi->txfm_size; + mbmi->filterbit = 1; + super_block_yrd(cpi, x, &rate_y_fil, &distortion_y_fil, &skippable_fil, + NULL, bsize, tx_cache_fil, best_rd); + rate0 = vp9_cost_bit( + cm->fc.filterintra_prob[temp_txfm_size][mbmi->mode], 0); + rate1 = vp9_cost_bit( + cm->fc.filterintra_prob[mbmi->txfm_size][mbmi->mode], 1); + if (RDCOST(x->rdmult, x->rddiv, rate_y + rate0, distortion_y) <= + RDCOST(x->rdmult, x->rddiv, rate_y_fil + rate1, distortion_y_fil)) { + mbmi->txfm_size = temp_txfm_size; + mbmi->filterbit = 0; + } else { + rate_y = rate_y_fil; + distortion_y = distortion_y_fil; + skippable = skippable_fil; + vpx_memcpy(tx_cache, tx_cache_fil, TX_MODES * sizeof(int64_t)); + } + } +#endif + if (rate_y == INT_MAX) continue; @@ -3642,14 +3786,25 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, &rate_uv_tokenonly[uv_tx], &dist_uv[uv_tx], &skip_uv[uv_tx], &mode_uv[uv_tx]); +#if CONFIG_FILTERINTRA + fbit_uv[uv_tx] = mbmi->uv_filterbit; +#endif } rate_uv = rate_uv_tokenonly[uv_tx]; distortion_uv = dist_uv[uv_tx]; skippable = skippable && skip_uv[uv_tx]; mbmi->uv_mode = mode_uv[uv_tx]; +#if CONFIG_FILTERINTRA + mbmi->uv_filterbit = fbit_uv[uv_tx]; +#endif rate2 = rate_y + x->mbmode_cost[mbmi->mode] + rate_uv_intra[uv_tx]; +#if CONFIG_FILTERINTRA + if (is_filter_allowed(mbmi->mode) && mbmi->txfm_size <= TX_8X8) + rate2 += vp9_cost_bit( + cm->fc.filterintra_prob[mbmi->txfm_size][mbmi->mode], mbmi->filterbit); +#endif if (mbmi->mode != DC_PRED && mbmi->mode != TM_PRED) rate2 += intra_cost_penalty; distortion2 = distortion_y + distortion_uv;