Commit f27b1605 authored by Yue Chen's avatar Yue Chen

Add rd loop of NCOBMC

At the final round of encoding of each superblock, will go through
each prediction block to check if ncobmc mode is better than non-
overlapped prediction. Note that causal obmc mode is dumped here.

PSNR gain (MOTION_VAR + NCOBMC): -2.845% lowres

Change-Id: Ibe504f7f1882446a08ba426e1e9824bca73bf655
parent 2615d6ea
......@@ -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,
......
......@@ -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
......
......@@ -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);
}
}
......
......@@ -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
......
......@@ -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
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment