diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c index 4df6079b3..ee3e47629 100644 --- a/av1/common/reconinter.c +++ b/av1/common/reconinter.c @@ -736,7 +736,9 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, struct macroblockd_plane *const pd = &xd->plane[plane]; #if CONFIG_MOTION_VAR const MODE_INFO *mi = xd->mi[mi_col_offset + xd->mi_stride * mi_row_offset]; +#if !CONFIG_CB4X4 const int build_for_obmc = !(mi_col_offset == 0 && mi_row_offset == 0); +#endif #else const MODE_INFO *mi = xd->mi[0]; #endif // CONFIG_MOTION_VAR @@ -2256,9 +2258,7 @@ void av1_build_ncobmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd, #if CONFIG_AOM_HIGHBITDEPTH } #endif // CONFIG_AOM_HIGHBITDEPTH - // causal obmc pred - // replace by bottom and right preds av1_build_prediction_by_bottom_preds(cm, xd, mi_row, mi_col, dst_buf1, dst_width1, dst_height1, dst_stride1); av1_build_prediction_by_right_preds(cm, xd, mi_row, mi_col, dst_buf2, diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 7d822aeaf..2414185c9 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -1665,7 +1665,11 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi, #endif // CONFIG_WARPED_MOTION #if CONFIG_MOTION_VAR if (mbmi->motion_mode == OBMC_CAUSAL) { +#if CONFIG_NCOBMC + av1_build_ncobmc_inter_predictors_sb(cm, xd, mi_row, mi_col); +#else av1_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); +#endif } #endif // CONFIG_MOTION_VAR diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index 1545aaeab..d91ad51ef 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c @@ -2187,19 +2187,21 @@ static void write_tokens_sb(AV1_COMP *cpi, const TileInfo *const tile, const TOKENEXTRA *const tok_end, int mi_row, int mi_col, BLOCK_SIZE bsize) { const AV1_COMMON *const cm = &cpi->common; - const int bsl = b_width_log2_lookup[bsize]; - const int bs = (1 << bsl) / 4; + const int hbs = mi_size_wide[bsize] / 2; PARTITION_TYPE partition; BLOCK_SIZE subsize; - const MODE_INFO *m = NULL; +#if CONFIG_CB4X4 + const int unify_bsize = 1; +#else + const int unify_bsize = 0; +#endif if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; - m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col]; - partition = partition_lookup[bsl][m->mbmi.sb_type]; + partition = get_partition(cm, mi_row, mi_col, bsize); subsize = get_subsize(bsize, partition); - if (subsize < BLOCK_8X8) { + if (subsize < BLOCK_8X8 && !unify_bsize) { write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); } else { switch (partition) { @@ -2208,23 +2210,45 @@ static void write_tokens_sb(AV1_COMP *cpi, const TileInfo *const tile, break; case PARTITION_HORZ: write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); - if (mi_row + bs < cm->mi_rows) - write_tokens_b(cpi, tile, w, tok, tok_end, mi_row + bs, mi_col); + if (mi_row + hbs < cm->mi_rows) + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col); break; case PARTITION_VERT: write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); - if (mi_col + bs < cm->mi_cols) - write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col + bs); + if (mi_col + hbs < cm->mi_cols) + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col + hbs); break; case PARTITION_SPLIT: write_tokens_sb(cpi, tile, w, tok, tok_end, mi_row, mi_col, subsize); - write_tokens_sb(cpi, tile, w, tok, tok_end, mi_row, mi_col + bs, + write_tokens_sb(cpi, tile, w, tok, tok_end, mi_row, mi_col + hbs, subsize); - write_tokens_sb(cpi, tile, w, tok, tok_end, mi_row + bs, mi_col, + write_tokens_sb(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col, subsize); - write_tokens_sb(cpi, tile, w, tok, tok_end, mi_row + bs, mi_col + bs, + write_tokens_sb(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col + hbs, subsize); break; +#if CONFIG_EXT_PARTITION_TYPES + case PARTITION_HORZ_A: + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col + hbs); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col); + break; + case PARTITION_HORZ_B: + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col + hbs); + break; + case PARTITION_VERT_A: + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col + hbs); + break; + case PARTITION_VERT_B: + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row, mi_col + hbs); + write_tokens_b(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col + hbs); + break; +#endif // CONFIG_EXT_PARTITION_TYPES default: assert(0); } } diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index c5a9c41d2..34c1c9864 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c @@ -1635,6 +1635,110 @@ static void update_supertx_param_sb(const AV1_COMP *const cpi, ThreadData *td, } #endif // CONFIG_SUPERTX +#if CONFIG_MOTION_VAR && CONFIG_NCOBMC +static void set_mode_info_b(const AV1_COMP *const cpi, + const TileInfo *const tile, ThreadData *td, + int mi_row, int mi_col, BLOCK_SIZE bsize, + PICK_MODE_CONTEXT *ctx) { + MACROBLOCK *const x = &td->mb; + set_offsets(cpi, tile, x, mi_row, mi_col, bsize); + update_state(cpi, td, ctx, mi_row, mi_col, bsize, 1); +} + +static void set_mode_info_sb(const AV1_COMP *const cpi, ThreadData *td, + const TileInfo *const tile, TOKENEXTRA **tp, + int mi_row, int mi_col, BLOCK_SIZE bsize, + PC_TREE *pc_tree) { + const AV1_COMMON *const cm = &cpi->common; + const int bsl = b_width_log2_lookup[bsize], hbs = (1 << bsl) / 4; + const PARTITION_TYPE partition = pc_tree->partitioning; + BLOCK_SIZE subsize = get_subsize(bsize, partition); +#if CONFIG_EXT_PARTITION_TYPES + const BLOCK_SIZE bsize2 = get_subsize(bsize, PARTITION_SPLIT); +#endif +#if CONFIG_CB4X4 + const int unify_bsize = 1; +#else + const int unify_bsize = 0; + assert(bsize >= BLOCK_8X8); +#endif + + if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + + switch (partition) { + case PARTITION_NONE: + set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize, &pc_tree->none); + break; + case PARTITION_VERT: + set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize, + &pc_tree->vertical[0]); + if (mi_col + hbs < cm->mi_cols && (bsize > BLOCK_8X8 || unify_bsize)) { + set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, subsize, + &pc_tree->vertical[1]); + } + break; + case PARTITION_HORZ: + set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize, + &pc_tree->horizontal[0]); + if (mi_row + hbs < cm->mi_rows && (bsize > BLOCK_8X8 || unify_bsize)) { + set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, subsize, + &pc_tree->horizontal[1]); + } + break; + case PARTITION_SPLIT: + if (bsize == BLOCK_8X8 && !unify_bsize) { + set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize, + pc_tree->leaf_split[0]); + } else { + set_mode_info_sb(cpi, td, tile, tp, mi_row, mi_col, subsize, + pc_tree->split[0]); + set_mode_info_sb(cpi, td, tile, tp, mi_row, mi_col + hbs, subsize, + pc_tree->split[1]); + set_mode_info_sb(cpi, td, tile, tp, mi_row + hbs, mi_col, subsize, + pc_tree->split[2]); + set_mode_info_sb(cpi, td, tile, tp, mi_row + hbs, mi_col + hbs, subsize, + pc_tree->split[3]); + } + break; +#if CONFIG_EXT_PARTITION_TYPES + case PARTITION_HORZ_A: + set_mode_info_b(cpi, tile, td, mi_row, mi_col, bsize2, + &pc_tree->horizontala[0]); + set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, bsize2, + &pc_tree->horizontala[1]); + set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, subsize, + &pc_tree->horizontala[2]); + break; + case PARTITION_HORZ_B: + set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize, + &pc_tree->horizontalb[0]); + set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, bsize2, + &pc_tree->horizontalb[1]); + set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col + hbs, bsize2, + &pc_tree->horizontalb[2]); + break; + case PARTITION_VERT_A: + set_mode_info_b(cpi, tile, td, mi_row, mi_col, bsize2, + &pc_tree->verticala[0]); + set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, bsize2, + &pc_tree->verticala[1]); + set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, subsize, + &pc_tree->verticala[2]); + break; + case PARTITION_VERT_B: + set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize, + &pc_tree->verticalb[0]); + set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, bsize2, + &pc_tree->verticalb[1]); + set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col + hbs, bsize2, + &pc_tree->verticalb[2]); + break; +#endif // CONFIG_EXT_PARTITION_TYPES + default: assert(0 && "Invalid partition type."); break; + } +} +#endif + void av1_setup_src_planes(MACROBLOCK *x, const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col) { uint8_t *const buffers[3] = { src->y_buffer, src->u_buffer, src->v_buffer }; @@ -2242,11 +2346,27 @@ static void encode_b(const AV1_COMP *const cpi, const TileInfo *const tile, #endif PICK_MODE_CONTEXT *ctx, int *rate) { MACROBLOCK *const x = &td->mb; +#if CONFIG_MOTION_VAR && CONFIG_NCOBMC + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi; + int check_ncobmc; +#endif + set_offsets(cpi, tile, x, mi_row, mi_col, bsize); #if CONFIG_EXT_PARTITION_TYPES x->e_mbd.mi[0]->mbmi.partition = partition; #endif update_state(cpi, td, ctx, mi_row, mi_col, bsize, dry_run); +#if CONFIG_MOTION_VAR && CONFIG_NCOBMC + mbmi = &xd->mi[0]->mbmi; + check_ncobmc = + is_inter_block(mbmi) && motion_mode_allowed(mbmi) >= OBMC_CAUSAL; + if (!dry_run && check_ncobmc) { + av1_check_ncobmc_rd(cpi, x, mi_row, mi_col); + av1_setup_dst_planes(x->e_mbd.plane, get_frame_new_buffer(&cpi->common), + mi_row, mi_col); + } +#endif encode_superblock(cpi, td, tp, dry_run, mi_row, mi_col, bsize, ctx, rate); if (!dry_run) { @@ -4357,6 +4477,9 @@ static void rd_pick_partition(const AV1_COMP *const cpi, ThreadData *td, if (best_rdc.rate < INT_MAX && best_rdc.dist < INT64_MAX && pc_tree->index != 3) { if (bsize == cm->sb_size) { +#if CONFIG_MOTION_VAR && CONFIG_NCOBMC + set_mode_info_sb(cpi, td, tile_info, tp, mi_row, mi_col, bsize, pc_tree); +#endif encode_sb(cpi, td, tile_info, tp, mi_row, mi_col, OUTPUT_ENABLED, bsize, pc_tree, NULL); } else { @@ -5517,7 +5640,12 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td, #if CONFIG_MOTION_VAR if (mbmi->motion_mode == OBMC_CAUSAL) { - av1_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); +#if CONFIG_NCOBMC + if (dry_run == OUTPUT_ENABLED) + av1_build_ncobmc_inter_predictors_sb(cm, xd, mi_row, mi_col); + else +#endif + av1_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); } #endif // CONFIG_MOTION_VAR diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index d20b3adae..f542ce15e 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c @@ -11573,4 +11573,105 @@ static void calc_target_weighted_pred(const AV1_COMMON *cm, const MACROBLOCK *x, #endif // CONFIG_AOM_HIGHBITDEPTH } } + +#if CONFIG_NCOBMC +void av1_check_ncobmc_rd(const struct AV1_COMP *cpi, struct macroblock *x, + int mi_row, int mi_col) { + const AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi; + MB_MODE_INFO backup_mbmi; + BLOCK_SIZE bsize = mbmi->sb_type; + int ref, skip_blk, backup_skip = x->skip; + int64_t rd_causal; + RD_STATS rd_stats_y, rd_stats_uv; + int rate_skip0 = av1_cost_bit(av1_get_skip_prob(cm, xd), 0); + int rate_skip1 = av1_cost_bit(av1_get_skip_prob(cm, xd), 1); + + // Recompute the best causal predictor and rd + mbmi->motion_mode = SIMPLE_TRANSLATION; + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { + YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, mbmi->ref_frame[ref]); + assert(cfg != NULL); + av1_setup_pre_planes(xd, ref, cfg, mi_row, mi_col, + &xd->block_refs[ref]->sf); + } + av1_setup_dst_planes(x->e_mbd.plane, get_frame_new_buffer(&cpi->common), + mi_row, mi_col); + + av1_build_inter_predictors_sb(xd, mi_row, mi_col, NULL, bsize); + + av1_subtract_plane(x, bsize, 0); + super_block_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX); + super_block_uvrd(cpi, x, &rd_stats_uv, bsize, INT64_MAX); + assert(rd_stats_y.rate != INT_MAX && rd_stats_uv.rate != INT_MAX); + if (rd_stats_y.skip && rd_stats_uv.skip) { + rd_stats_y.rate = rate_skip1; + rd_stats_uv.rate = 0; + rd_stats_y.dist = rd_stats_y.sse; + rd_stats_uv.dist = rd_stats_uv.sse; + skip_blk = 0; + } else if (RDCOST(x->rdmult, x->rddiv, + (rd_stats_y.rate + rd_stats_uv.rate + rate_skip0), + (rd_stats_y.dist + rd_stats_uv.dist)) > + RDCOST(x->rdmult, x->rddiv, rate_skip1, + (rd_stats_y.sse + rd_stats_uv.sse))) { + rd_stats_y.rate = rate_skip1; + rd_stats_uv.rate = 0; + rd_stats_y.dist = rd_stats_y.sse; + rd_stats_uv.dist = rd_stats_uv.sse; + skip_blk = 1; + } else { + rd_stats_y.rate += rate_skip0; + skip_blk = 0; + } + backup_skip = skip_blk; + backup_mbmi = *mbmi; + rd_causal = RDCOST(x->rdmult, x->rddiv, (rd_stats_y.rate + rd_stats_uv.rate), + (rd_stats_y.dist + rd_stats_uv.dist)); + rd_causal += RDCOST(x->rdmult, x->rddiv, + av1_cost_bit(cm->fc->motion_mode_prob[bsize][0], 0), 0); + + // Check non-causal mode + mbmi->motion_mode = OBMC_CAUSAL; + av1_build_ncobmc_inter_predictors_sb(cm, xd, mi_row, mi_col); + + av1_subtract_plane(x, bsize, 0); + super_block_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX); + super_block_uvrd(cpi, x, &rd_stats_uv, bsize, INT64_MAX); + assert(rd_stats_y.rate != INT_MAX && rd_stats_uv.rate != INT_MAX); + if (rd_stats_y.skip && rd_stats_uv.skip) { + rd_stats_y.rate = rate_skip1; + rd_stats_uv.rate = 0; + rd_stats_y.dist = rd_stats_y.sse; + rd_stats_uv.dist = rd_stats_uv.sse; + skip_blk = 0; + } else if (RDCOST(x->rdmult, x->rddiv, + (rd_stats_y.rate + rd_stats_uv.rate + rate_skip0), + (rd_stats_y.dist + rd_stats_uv.dist)) > + RDCOST(x->rdmult, x->rddiv, rate_skip1, + (rd_stats_y.sse + rd_stats_uv.sse))) { + rd_stats_y.rate = rate_skip1; + rd_stats_uv.rate = 0; + rd_stats_y.dist = rd_stats_y.sse; + rd_stats_uv.dist = rd_stats_uv.sse; + skip_blk = 1; + } else { + rd_stats_y.rate += rate_skip0; + skip_blk = 0; + } + + if (rd_causal > + RDCOST(x->rdmult, x->rddiv, + rd_stats_y.rate + rd_stats_uv.rate + + av1_cost_bit(cm->fc->motion_mode_prob[bsize][0], 1), + (rd_stats_y.dist + rd_stats_uv.dist))) { + x->skip = skip_blk; + } else { + *mbmi = backup_mbmi; + x->skip = backup_skip; + } +} +#endif #endif // CONFIG_MOTION_VAR diff --git a/av1/encoder/rdopt.h b/av1/encoder/rdopt.h index 301e5aa3a..b586b458d 100644 --- a/av1/encoder/rdopt.h +++ b/av1/encoder/rdopt.h @@ -176,6 +176,11 @@ void av1_rd_pick_inter_mode_sub8x8(const struct AV1_COMP *cpi, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far); +#if CONFIG_MOTION_VAR && CONFIG_NCOBMC +void av1_check_ncobmc_rd(const struct AV1_COMP *cpi, struct macroblock *x, + int mi_row, int mi_col); +#endif // CONFIG_MOTION_VAR && CONFIG_NCOBMC + #if CONFIG_SUPERTX #if CONFIG_VAR_TX void av1_tx_block_rd_b(const AV1_COMP *cpi, MACROBLOCK *x, TX_SIZE tx_size,