From 287443092b27500fcb33a32a1a56f63f0b308ca3 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Thu, 13 Apr 2017 14:46:22 -0700 Subject: [PATCH] intrabc: Add initial skeleton Missing features: * RDOPT (Forced on for certain blocks) * Any form of border extension * Non MI sized right and bottom edges * MV prediction Present features: * Force intrabc for some blocks * Carry intrabc in the bitstream * Validate DV is causal * Reconstruct intrabc block assuming border extension is unnecessary Change-Id: Ib1f6868e89bfacc2a4edfc876485bad1b347263b --- av1/common/blockd.h | 16 ++++ av1/common/entropymode.h | 10 +++ av1/common/entropymv.c | 5 +- av1/common/mvref_common.h | 51 +++++++++++++ av1/common/reconinter.c | 32 +++++++- av1/common/reconinter.h | 1 + av1/decoder/decodeframe.c | 25 ++++-- av1/decoder/decodemv.c | 45 +++++++++++ av1/encoder/bitstream.c | 18 +++++ av1/encoder/encodeframe.c | 9 +++ av1/encoder/encodemv.c | 19 +++++ av1/encoder/encodemv.h | 5 ++ av1/encoder/rdopt.c | 42 ++++++++++ test/intrabc_test.cc | 157 ++++++++++++++++++++++++++++++++++++++ test/test.mk | 1 + 15 files changed, 427 insertions(+), 9 deletions(-) create mode 100644 test/intrabc_test.cc diff --git a/av1/common/blockd.h b/av1/common/blockd.h index 32c01d4fc..6bbb4c5fe 100644 --- a/av1/common/blockd.h +++ b/av1/common/blockd.h @@ -324,6 +324,9 @@ typedef struct { #if CONFIG_PALETTE PALETTE_MODE_INFO palette_mode_info; #endif // CONFIG_PALETTE +#if CONFIG_INTRABC + uint8_t use_intrabc; +#endif // CONFIG_INTRABC // Only for INTER blocks #if CONFIG_DUAL_FILTER @@ -396,6 +399,12 @@ typedef struct MODE_INFO { b_mode_info bmi[4]; } MODE_INFO; +#if CONFIG_INTRABC +static INLINE int is_intrabc_block(const MB_MODE_INFO *mbmi) { + return mbmi->use_intrabc; +} +#endif + static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) { #if CONFIG_CB4X4 (void)block; @@ -406,6 +415,9 @@ static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) { } static INLINE int is_inter_block(const MB_MODE_INFO *mbmi) { +#if CONFIG_INTRABC + if (is_intrabc_block(mbmi)) return 1; +#endif return mbmi->ref_frame[0] > INTRA_FRAME; } @@ -911,6 +923,10 @@ static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type, const MACROBLOCKD *xd, int block, TX_SIZE tx_size) { const MODE_INFO *const mi = xd->mi[0]; const MB_MODE_INFO *const mbmi = &mi->mbmi; +#if CONFIG_INTRABC + // TODO(aconverse@google.com): Revisit this decision + if (is_intrabc_block(mbmi)) return DCT_DCT; +#endif // CONFIG_INTRABC #if !CONFIG_TXK_SEL const int block_raster_idx = av1_block_index_to_raster_order(tx_size, block); if (FIXED_TX_TYPE) diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h index e31a39a88..3fb5bdf52 100644 --- a/av1/common/entropymode.h +++ b/av1/common/entropymode.h @@ -69,6 +69,10 @@ extern "C" { #define PALETTE_MAX_BLOCK_SIZE (64 * 64) #endif // CONFIG_PALETTE +#if CONFIG_INTRABC +#define INTRABC_PROB 192 +#endif // CONFIG_INTRABC + struct AV1Common; typedef struct { @@ -218,6 +222,9 @@ typedef struct frame_contexts { nmv_context nmvc[NMV_CONTEXTS]; #else nmv_context nmvc; +#endif +#if CONFIG_INTRABC + nmv_context ndvc; #endif int initialized; #if CONFIG_EXT_TX @@ -381,6 +388,9 @@ typedef struct FRAME_COUNTS { #else nmv_context_counts mv; #endif +#if CONFIG_INTRABC + nmv_context_counts dv; +#endif #if CONFIG_DELTA_Q unsigned int delta_q[DELTA_Q_PROBS][2]; #endif diff --git a/av1/common/entropymv.c b/av1/common/entropymv.c index e3aecba80..3e71f6f28 100644 --- a/av1/common/entropymv.c +++ b/av1/common/entropymv.c @@ -332,7 +332,10 @@ void av1_init_mv_probs(AV1_COMMON *cm) { } #else cm->fc->nmvc = default_nmv_context; -#endif +#endif // CONFIG_REF_MV +#if CONFIG_INTRABC + cm->fc->ndvc = default_nmv_context; +#endif // CONFIG_INTRABC #if CONFIG_GLOBAL_MOTION av1_copy(cm->fc->global_motion_types_prob, default_global_motion_types_prob); #endif // CONFIG_GLOBAL_MOTION diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h index a8abcbad1..7c1161d85 100644 --- a/av1/common/mvref_common.h +++ b/av1/common/mvref_common.h @@ -515,6 +515,57 @@ int findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col, int *pts, int *pts_inref); #endif // CONFIG_WARPED_MOTION +#if CONFIG_INTRABC +static INLINE void av1_find_ref_dv(int_mv *ref_dv, int mi_row, int mi_col) { + // TODO(aconverse@google.com): Handle tiles and such + (void)mi_col; + if (mi_row < MAX_MIB_SIZE) { + ref_dv->as_mv.row = 0; + ref_dv->as_mv.col = -MI_SIZE * MAX_MIB_SIZE; + } else { + ref_dv->as_mv.row = -MI_SIZE * MAX_MIB_SIZE; + ref_dv->as_mv.col = 0; + } +} + +static INLINE int is_dv_valid(const MV dv, const TileInfo *const tile, + int mi_row, int mi_col, BLOCK_SIZE bsize) { + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + const int SCALE_PX_TO_MV = 8; + // Disallow subpixel for now + // SUBPEL_MASK is not the correct scale + if ((dv.row & (SCALE_PX_TO_MV - 1) || dv.col & (SCALE_PX_TO_MV - 1))) + return 0; + // Is the source top-left inside the current tile? + const int src_top_edge = mi_row * MI_SIZE * SCALE_PX_TO_MV + dv.row; + const int tile_top_edge = tile->mi_row_start * MI_SIZE * SCALE_PX_TO_MV; + if (src_top_edge < tile_top_edge) return 0; + const int src_left_edge = mi_col * MI_SIZE * SCALE_PX_TO_MV + dv.col; + const int tile_left_edge = tile->mi_col_start * MI_SIZE * SCALE_PX_TO_MV; + if (src_left_edge < tile_left_edge) return 0; + // Is the bottom right inside the current tile? + const int src_bottom_edge = (mi_row * MI_SIZE + bh) * SCALE_PX_TO_MV + dv.row; + const int tile_bottom_edge = tile->mi_row_end * MI_SIZE * SCALE_PX_TO_MV; + if (src_bottom_edge > tile_bottom_edge) return 0; + const int src_right_edge = (mi_col * MI_SIZE + bw) * SCALE_PX_TO_MV + dv.col; + const int tile_right_edge = tile->mi_col_end * MI_SIZE * SCALE_PX_TO_MV; + if (src_right_edge > tile_right_edge) return 0; + // Is the bottom right within an already coded SB? + const int active_sb_top_edge = + (mi_row & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV; + const int active_sb_bottom_edge = + ((mi_row & ~MAX_MIB_MASK) + MAX_MIB_SIZE) * MI_SIZE * SCALE_PX_TO_MV; + const int active_sb_left_edge = + (mi_col & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV; + if (src_bottom_edge > active_sb_bottom_edge) return 0; + if (src_bottom_edge > active_sb_top_edge && + src_right_edge > active_sb_left_edge) + return 0; + return 1; +} +#endif // CONFIG_INTRABC + #ifdef __cplusplus } // extern "C" #endif diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c index 9245b6cb5..eee34585f 100644 --- a/av1/common/reconinter.c +++ b/av1/common/reconinter.c @@ -906,6 +906,18 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, #endif // CONFIG_MOTION_VAR const int is_compound = has_second_ref(&mi->mbmi); int ref; +#if CONFIG_INTRABC + const int is_intrabc = is_intrabc_block(&mi->mbmi); + struct scale_factors sf_identity; +#if CONFIG_HIGHBITDEPTH + av1_setup_scale_factors_for_frame( + &sf_identity, 64, 64, 64, 64, + xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH); +#else + av1_setup_scale_factors_for_frame(&sf_identity, 64, 64, 64, 64); +#endif // CONFIG_HIGHBITDEPTH + assert(IMPLIES(is_intrabc, !is_compound)); +#endif // CONFIG_INTRABC #if CONFIG_GLOBAL_MOTION int is_global[2]; for (ref = 0; ref < 1 + is_compound; ++ref) { @@ -946,9 +958,15 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, for (idx = 0; idx < b8_s; idx += b4_w) { const int chr_idx = (idy * 2) + idx; for (ref = 0; ref < 1 + is_compound; ++ref) { + struct buf_2d *const dst_buf = &pd->dst; +#if CONFIG_INTRABC + const struct scale_factors *const sf = + is_intrabc ? &sf_identity : &xd->block_refs[ref]->sf; + struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; +#else const struct scale_factors *const sf = &xd->block_refs[ref]->sf; struct buf_2d *const pre_buf = &pd->pre[ref]; - struct buf_2d *const dst_buf = &pd->dst; +#endif // CONFIG_INTRABC uint8_t *dst = dst_buf->buf; const MV mv = mi->bmi[chr_idx].as_mv[ref].as_mv; const MV mv_q4 = clamp_mv_to_umv_border_sb( @@ -1038,8 +1056,14 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, #endif // CONFIG_CONVOLVE_ROUND for (ref = 0; ref < 1 + is_compound; ++ref) { +#if CONFIG_INTRABC + const struct scale_factors *const sf = + is_intrabc ? &sf_identity : &xd->block_refs[ref]->sf; + struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; +#else const struct scale_factors *const sf = &xd->block_refs[ref]->sf; struct buf_2d *const pre_buf = &pd->pre[ref]; +#endif // CONFIG_INTRABC #if CONFIG_CB4X4 const MV mv = mi->mbmi.mv[ref].as_mv; #else @@ -1090,8 +1114,14 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, ConvolveParams conv_params = get_conv_params(ref, plane); #endif // CONFIG_CONVOLVE_ROUND for (ref = 0; ref < 1 + is_compound; ++ref) { +#if CONFIG_INTRABC + const struct scale_factors *const sf = + is_intrabc ? &sf_identity : &xd->block_refs[ref]->sf; + struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; +#else const struct scale_factors *const sf = &xd->block_refs[ref]->sf; struct buf_2d *const pre_buf = &pd->pre[ref]; +#endif // CONFIG_INTRABC #if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION WarpTypesAllowed warp_types; #if CONFIG_GLOBAL_MOTION diff --git a/av1/common/reconinter.h b/av1/common/reconinter.h index 55cb239e9..15f5ffa47 100644 --- a/av1/common/reconinter.h +++ b/av1/common/reconinter.h @@ -57,6 +57,7 @@ static INLINE void inter_predictor(const uint8_t *src, int src_stride, av1_get_interp_filter_params(interp_filter); #endif + assert(sf); #if CONFIG_DUAL_FILTER if (interp_filter_params_x.taps == SUBPEL_TAPS && interp_filter_params_y.taps == SUBPEL_TAPS && w > 2 && h > 2 && diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 91b140dc2..8d14095b8 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -1728,13 +1728,24 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi, for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; - RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME]; - - xd->block_refs[ref] = ref_buf; - if ((!av1_is_valid_scale(&ref_buf->sf))) - aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM, - "Reference frame has invalid dimensions"); - av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, &ref_buf->sf); + if (frame < LAST_FRAME) { +#if CONFIG_INTRABC + assert(is_intrabc_block(mbmi)); + assert(frame == INTRA_FRAME); + assert(ref == 0); +#else + assert(0); +#endif // CONFIG_INTRABC + } else { + RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME]; + + xd->block_refs[ref] = ref_buf; + if ((!av1_is_valid_scale(&ref_buf->sf))) + aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM, + "Reference frame has invalid dimensions"); + av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, + &ref_buf->sf); + } } #if CONFIG_CB4X4 diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c index 3a2ab56f2..24e7ceeaa 100644 --- a/av1/decoder/decodemv.c +++ b/av1/decoder/decodemv.c @@ -902,6 +902,32 @@ void av1_read_tx_type(const AV1_COMMON *const cm, MACROBLOCKD *xd, } } +#if CONFIG_INTRABC +static INLINE void read_mv(aom_reader *r, MV *mv, const MV *ref, + nmv_context *ctx, nmv_context_counts *counts, + int allow_hp); + +static INLINE int is_mv_valid(const MV *mv); + +static INLINE int assign_dv(AV1_COMMON *cm, MACROBLOCKD *xd, int_mv *mv, + const int_mv *ref_mv, int mi_row, int mi_col, + BLOCK_SIZE bsize, aom_reader *r) { +#if CONFIG_EC_ADAPT + FRAME_CONTEXT *ec_ctx = xd->tile_ctx; + (void)cm; +#else + FRAME_CONTEXT *ec_ctx = cm->fc; +#endif + FRAME_COUNTS *counts = xd->counts; + nmv_context_counts *const dv_counts = counts ? &counts->dv : NULL; + read_mv(r, &mv->as_mv, &ref_mv->as_mv, &ec_ctx->ndvc, dv_counts, 0); + int valid = is_mv_valid(&mv->as_mv) && + is_dv_valid(mv->as_mv, &xd->tile, mi_row, mi_col, bsize); + // TODO(aconverse@google.com): additional validation + return valid; +} +#endif // CONFIG_INTRABC + static void read_intra_frame_mode_info(AV1_COMMON *const cm, MACROBLOCKD *const xd, int mi_row, int mi_col, aom_reader *r) { @@ -942,6 +968,21 @@ static void read_intra_frame_mode_info(AV1_COMMON *const cm, mbmi->ref_frame[0] = INTRA_FRAME; mbmi->ref_frame[1] = NONE_FRAME; +#if CONFIG_INTRABC + if (bsize >= BLOCK_8X8 && cm->allow_screen_content_tools) { + mbmi->use_intrabc = aom_read(r, INTRABC_PROB, ACCT_STR); + if (mbmi->use_intrabc) { + int_mv dv_ref; + mbmi->mode = mbmi->uv_mode = DC_PRED; + mbmi->interp_filter = BILINEAR; + av1_find_ref_dv(&dv_ref, mi_row, mi_col); + xd->corrupted |= + !assign_dv(cm, xd, &mbmi->mv[0], &dv_ref, mi_row, mi_col, bsize, r); + return; + } + } +#endif // CONFIG_INTRABC + #if CONFIG_CB4X4 (void)i; mbmi->mode = @@ -2283,6 +2324,10 @@ void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd, MV_REF *frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col; int w, h; +#if CONFIG_INTRABC + mi->mbmi.use_intrabc = 0; +#endif // CONFIG_INTRABC + if (frame_is_intra_only(cm)) { read_intra_frame_mode_info(cm, xd, mi_row, mi_col, r); #if CONFIG_REF_MV diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index ed2d5f3eb..a24b79e7a 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c @@ -221,6 +221,9 @@ static void write_intra_mode_kf(const AV1_COMMON *cm, FRAME_CONTEXT *frame_ctx, const MODE_INFO *mi, const MODE_INFO *above_mi, const MODE_INFO *left_mi, int block, PREDICTION_MODE mode, aom_writer *w) { +#if CONFIG_INTRABC + assert(!is_intrabc_block(&mi->mbmi)); +#endif // CONFIG_INTRABC #if CONFIG_EC_MULTISYMBOL aom_write_symbol(w, av1_intra_mode_ind[mode], get_y_mode_cdf(frame_ctx, mi, above_mi, left_mi, block), @@ -2094,6 +2097,21 @@ static void write_mb_modes_kf(AV1_COMMON *cm, const MACROBLOCKD *xd, !xd->lossless[mbmi->segment_id]) write_selected_tx_size(cm, xd, w); +#if CONFIG_INTRABC + if (bsize >= BLOCK_8X8 && cm->allow_screen_content_tools) { + int use_intrabc = is_intrabc_block(mbmi); + aom_write(w, use_intrabc, INTRABC_PROB); + if (use_intrabc) { + assert(mbmi->mode == DC_PRED); + assert(mbmi->uv_mode == DC_PRED); + int_mv dv_ref; + av1_find_ref_dv(&dv_ref, mi_row, mi_col); + av1_encode_dv(w, &mbmi->mv[0].as_mv, &dv_ref.as_mv, &ec_ctx->ndvc); + return; + } + } +#endif // CONFIG_INTRABC + if (bsize >= BLOCK_8X8 || unify_bsize) { write_intra_mode_kf(cm, ec_ctx, mi, above_mi, left_mi, 0, mbmi->mode, w); } else { diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index 8ab42d25a..23beab26e 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c @@ -5882,6 +5882,11 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td, const int unify_bsize = 0; const BLOCK_SIZE block_size = AOMMAX(bsize, BLOCK_8X8); #endif +#if CONFIG_INTRABC + // TODO(aconverse@google.com): Remove this when the non-synthetic encoder + // side intrabc is added + assert(IMPLIES(is_intrabc_block(mbmi), mbmi->skip)); +#endif #if CONFIG_PVQ x->pvq_speed = 0; @@ -5964,7 +5969,11 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td, set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); for (ref = 0; ref < 1 + is_compound; ++ref) { YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, mbmi->ref_frame[ref]); +#if CONFIG_INTRABC + assert(IMPLIES(!is_intrabc_block(mbmi), cfg)); +#else assert(cfg != NULL); +#endif // !CONFIG_INTRABC av1_setup_pre_planes(xd, ref, cfg, mi_row, mi_col, &xd->block_refs[ref]->sf); } diff --git a/av1/encoder/encodemv.c b/av1/encoder/encodemv.c index 7a3737966..a2a53f840 100644 --- a/av1/encoder/encodemv.c +++ b/av1/encoder/encodemv.c @@ -278,6 +278,25 @@ void av1_encode_mv(AV1_COMP *cpi, aom_writer *w, const MV *mv, const MV *ref, } } +#if CONFIG_INTRABC +void av1_encode_dv(aom_writer *w, const MV *mv, const MV *ref, + nmv_context *mvctx) { + const MV diff = { mv->row - ref->row, mv->col - ref->col }; + const MV_JOINT_TYPE j = av1_get_mv_joint(&diff); + +#if CONFIG_EC_MULTISYMBOL + aom_write_symbol(w, j, mvctx->joint_cdf, MV_JOINTS); +#else + av1_write_token(w, av1_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]); +#endif + if (mv_joint_vertical(j)) + encode_mv_component(w, diff.row, &mvctx->comps[0], 0); + + if (mv_joint_horizontal(j)) + encode_mv_component(w, diff.col, &mvctx->comps[1], 0); +} +#endif // CONFIG_INTRABC + void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2], const nmv_context *ctx, int usehp) { av1_cost_tokens(mvjoint, ctx->joints, av1_mv_joint_tree); diff --git a/av1/encoder/encodemv.h b/av1/encoder/encodemv.h index 5fea65224..6d442147f 100644 --- a/av1/encoder/encodemv.h +++ b/av1/encoder/encodemv.h @@ -31,6 +31,11 @@ void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2], void av1_update_mv_count(ThreadData *td); +#if CONFIG_INTRABC +void av1_encode_dv(aom_writer *w, const MV *mv, const MV *ref, + nmv_context *mvctx); +#endif // CONFIG_INTRABC + #ifdef __cplusplus } // extern "C" #endif diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 109168303..f94f1f4ae 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c @@ -9166,6 +9166,39 @@ static int64_t handle_inter_mode( return 0; // The rate-distortion cost will be re-calculated by caller. } +#if CONFIG_INTRABC +// This is a dummy function that forces intrabc on for testing purposes +// TODO(aconverse@google.com): Implement a real intrabc search +static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, + RD_COST *rd_cost, BLOCK_SIZE bsize, + int64_t best_rd) { + MACROBLOCKD *const xd = &x->e_mbd; + (void)best_rd; + if (bsize >= BLOCK_8X8 && cpi->common.allow_screen_content_tools) { + if (xd->mb_to_top_edge == -MAX_SB_SIZE * 8) { + MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi; + mbmi->use_intrabc = 1; + mbmi->mode = DC_PRED; + mbmi->uv_mode = DC_PRED; + mbmi->mv[0].as_mv.row = -MAX_SB_SIZE * 8; + mbmi->mv[0].as_mv.col = 0; + mbmi->interp_filter = BILINEAR; + mbmi->skip = 1; + x->skip = 1; + const int mi_row = -xd->mb_to_top_edge / (8 * MI_SIZE); + const int mi_col = -xd->mb_to_left_edge / (8 * MI_SIZE); + av1_build_inter_predictors_sb(xd, mi_row, mi_col, NULL, bsize); + rd_cost->rate = 1; + rd_cost->dist = 0; + rd_cost->rdcost = + RDCOST(x->rdmult, x->rddiv, rd_cost->rate, rd_cost->dist); + return rd_cost->rdcost; + } + } + return INT64_MAX; +} +#endif // CONFIG_INTRABC + void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, RD_COST *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd) { @@ -9181,6 +9214,9 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, ctx->skip = 0; xd->mi[0]->mbmi.ref_frame[0] = INTRA_FRAME; xd->mi[0]->mbmi.ref_frame[1] = NONE_FRAME; +#if CONFIG_INTRABC + xd->mi[0]->mbmi.use_intrabc = 0; +#endif // CONFIG_INTRABC if (bsize >= BLOCK_8X8 || unify_bsize) { if (rd_pick_intra_sby_mode(cpi, x, &rate_y, &rate_y_tokenonly, &dist_y, @@ -9220,6 +9256,12 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, rd_cost->dist = dist_y + dist_uv; } +#if CONFIG_INTRABC + if (rd_pick_intrabc_mode_sb(cpi, x, rd_cost, bsize, best_rd) < best_rd) { + ctx->skip = x->skip; // FIXME where is the proper place to set this?! + } +#endif + ctx->mic = *xd->mi[0]; ctx->mbmi_ext = *x->mbmi_ext; rd_cost->rdcost = RDCOST(x->rdmult, x->rddiv, rd_cost->rate, rd_cost->dist); diff --git a/test/intrabc_test.cc b/test/intrabc_test.cc new file mode 100644 index 000000000..84cfa5c48 --- /dev/null +++ b/test/intrabc_test.cc @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2017, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include "third_party/googletest/src/googletest/include/gtest/gtest.h" + +#include "./aom_config.h" +#include "av1/common/enums.h" +#include "av1/common/mv.h" +#include "av1/common/mvref_common.h" +#include "av1/common/tile_common.h" + +namespace { +TEST(IntrabcTest, DvValidation) { + struct DvTestCase { + MV dv; + int mi_row_offset; + int mi_col_offset; + BLOCK_SIZE bsize; + bool valid; + }; + const int kSubPelScale = 8; + const int kTileMaxMibWidth = 8; + const DvTestCase kDvCases[] = { +#if CONFIG_EXT_PARTITION + { { 0, 0 }, 0, 0, BLOCK_128X128, false }, +#endif + { { 0, 0 }, 0, 0, BLOCK_64X64, false }, + { { 0, 0 }, 0, 0, BLOCK_32X32, false }, + { { 0, 0 }, 0, 0, BLOCK_16X16, false }, + { { 0, 0 }, 0, 0, BLOCK_8X8, false }, + { { 0, 0 }, 0, 0, BLOCK_4X4, false }, + { { -MAX_SB_SIZE * kSubPelScale, -MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_16X16, + true }, + { { 0, -MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_16X16, + true }, + { { -MAX_SB_SIZE * kSubPelScale, 0 }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_16X16, + true }, + { { MAX_SB_SIZE * kSubPelScale, 0 }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_16X16, + false }, + { { 0, MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_16X16, + false }, + { { -32 * kSubPelScale, -32 * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_32X32, + true }, + { { -32 * kSubPelScale, -32 * kSubPelScale }, + 32 / MI_SIZE, + 32 / MI_SIZE, + BLOCK_32X32, + false }, + { { -32 * kSubPelScale - kSubPelScale / 2, -32 * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_32X32, + false }, + { { -33 * kSubPelScale, -32 * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_32X32, + true }, + { { -32 * kSubPelScale, -32 * kSubPelScale - kSubPelScale / 2 }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_32X32, + false }, + { { -32 * kSubPelScale, -33 * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_32X32, + true }, + { { -MAX_SB_SIZE * kSubPelScale, -MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + true }, + { { -(MAX_SB_SIZE + 1) * kSubPelScale, -MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + false }, + { { -MAX_SB_SIZE * kSubPelScale, -(MAX_SB_SIZE + 1) * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + false }, + { { -(MAX_SB_SIZE - 1) * kSubPelScale, -MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + true }, + { { -MAX_SB_SIZE * kSubPelScale, -(MAX_SB_SIZE - 1) * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + true }, + { { -(MAX_SB_SIZE - 1) * kSubPelScale, -(MAX_SB_SIZE - 1) * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + false }, + { { -MAX_SB_SIZE * kSubPelScale, MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + true }, + { { -MAX_SB_SIZE * kSubPelScale, + (kTileMaxMibWidth - 2) * MAX_SB_SIZE * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + true }, + { { -MAX_SB_SIZE * kSubPelScale, + ((kTileMaxMibWidth - 2) * MAX_SB_SIZE + 1) * kSubPelScale }, + MAX_SB_SIZE / MI_SIZE, + MAX_SB_SIZE / MI_SIZE, + BLOCK_LARGEST, + false }, + }; + TileInfo tile; + tile.mi_row_start = 8 * MAX_MIB_SIZE; + tile.mi_row_end = 16 * MAX_MIB_SIZE; + tile.mi_col_start = 24 * MAX_MIB_SIZE; + tile.mi_col_end = tile.mi_col_start + kTileMaxMibWidth * MAX_MIB_SIZE; + for (int i = 0; i < static_cast(GTEST_ARRAY_SIZE_(kDvCases)); ++i) { + EXPECT_EQ(kDvCases[i].valid, + is_dv_valid(kDvCases[i].dv, &tile, + tile.mi_row_start + kDvCases[i].mi_row_offset, + tile.mi_col_start + kDvCases[i].mi_col_offset, + kDvCases[i].bsize)) + << "DvCases[" << i << "]"; + } +} +} // namespace diff --git a/test/test.mk b/test/test.mk index c60cc3d9d..b9bbb9dc3 100644 --- a/test/test.mk +++ b/test/test.mk @@ -148,6 +148,7 @@ LIBAOM_TEST_SRCS-$(HAVE_SSSE3) += simd_ssse3_test.cc LIBAOM_TEST_SRCS-$(HAVE_SSE4_1) += simd_sse4_test.cc LIBAOM_TEST_SRCS-$(HAVE_NEON) += simd_neon_test.cc LIBAOM_TEST_SRCS-yes += intrapred_test.cc +LIBAOM_TEST_SRCS-$(CONFIG_INTRABC) += intrabc_test.cc #LIBAOM_TEST_SRCS-$(CONFIG_AV1_DECODER) += av1_thread_test.cc LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += dct16x16_test.cc LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += dct32x32_test.cc -- GitLab