Add an experiment to disable lpf on tile boundaries This commit adds a new experiment to allow disabling of loop filtering on tile boundaries. It is implemented by adding a syntax field "loopfilter_across_tiles_enabled" into the uncompressed frame header. If it is set to 0, decoder and encoder will disables loop filtering for block edges that are also tile boundaries. Change-Id: Ib80bfd82d49c74f1ba46ae18ceedb30704ac8aa5
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index c3abf2d..1286dda 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -34,6 +34,9 @@ unsigned int static_thresh; unsigned int tile_columns; unsigned int tile_rows; +#if CONFIG_DEBLOCKING_ACROSS_TILES + unsigned int loop_filter_across_tiles_enabled; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES unsigned int arnr_max_frames; unsigned int arnr_strength; unsigned int min_gf_interval; @@ -80,7 +83,10 @@ #else 0, // tile_columns 0, // tile_rows -#endif // CONFIG_EXT_TILE +#endif // CONFIG_EXT_TILE +#if CONFIG_DEBLOCKING_ACROSS_TILES + 0, // loop_filter_across_tiles_enabled +#endif // CONFIG_DEBLOCKING_ACROSS_TILES 7, // arnr_max_frames 5, // arnr_strength 0, // min_gf_interval; 0 -> default decision @@ -250,6 +256,9 @@ RANGE_CHECK_HI(extra_cfg, tile_columns, 6); RANGE_CHECK_HI(extra_cfg, tile_rows, 2); #endif // CONFIG_EXT_TILE +#if CONFIG_DEBLOCKING_ACROSS_TILES + RANGE_CHECK_HI(extra_cfg, loop_filter_across_tiles_enabled, 1); +#endif // CONFIG_DEBLOCKING_ACROSS_TILES RANGE_CHECK_HI(extra_cfg, sharpness, 7); RANGE_CHECK_HI(extra_cfg, arnr_max_frames, 15); RANGE_CHECK_HI(extra_cfg, arnr_strength, 6); @@ -483,6 +492,11 @@ oxcf->tile_rows = extra_cfg->tile_rows; #endif // CONFIG_EXT_TILE +#if CONFIG_DEBLOCKING_ACROSS_TILES + oxcf->loop_filter_across_tiles_enabled = + extra_cfg->loop_filter_across_tiles_enabled; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + oxcf->error_resilient_mode = cfg->g_error_resilient; oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode; @@ -645,6 +659,16 @@ return update_extra_cfg(ctx, &extra_cfg); } +#if CONFIG_DEBLOCKING_ACROSS_TILES +static aom_codec_err_t ctrl_set_tile_loopfilter(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.loop_filter_across_tiles_enabled = + CAST(AV1E_SET_TILE_LOOPFILTER, args); + return update_extra_cfg(ctx, &extra_cfg); +} +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + static aom_codec_err_t ctrl_set_arnr_max_frames(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1329,6 +1353,9 @@ { AOME_SET_STATIC_THRESHOLD, ctrl_set_static_thresh }, { AV1E_SET_TILE_COLUMNS, ctrl_set_tile_columns }, { AV1E_SET_TILE_ROWS, ctrl_set_tile_rows }, +#if CONFIG_DEBLOCKING_ACROSS_TILES + { AV1E_SET_TILE_LOOPFILTER, ctrl_set_tile_loopfilter }, +#endif // CONFIG_DEBLOCKING_ACROSS_TILES { AOME_SET_ARNR_MAXFRAMES, ctrl_set_arnr_max_frames }, { AOME_SET_ARNR_STRENGTH, ctrl_set_arnr_strength }, { AOME_SET_TUNING, ctrl_set_tuning },
diff --git a/av1/common/blockd.h b/av1/common/blockd.h index 9fd5510..859986a 100644 --- a/av1/common/blockd.h +++ b/av1/common/blockd.h
@@ -350,6 +350,9 @@ int num_proj_ref[2]; WarpedMotionParams wm_params[2]; #endif // CONFIG_WARPED_MOTION +#if CONFIG_DEBLOCKING_ACROSS_TILES + TILE_BOUNDARY_TYPE tile_boundary_info; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES } MB_MODE_INFO; typedef struct MODE_INFO {
diff --git a/av1/common/enums.h b/av1/common/enums.h index c2e9329..6889935 100644 --- a/av1/common/enums.h +++ b/av1/common/enums.h
@@ -222,6 +222,15 @@ TX_TYPES, } TX_TYPE; +#if CONFIG_DEBLOCKING_ACROSS_TILES +typedef enum { + TILE_LEFT_BOUNDARY = 1, + TILE_RIGHT_BOUNDARY = 2, + TILE_ABOVE_BOUNDARY = 4, + TILE_BOTTOM_BOUNDARY = 8, +} TILE_BOUNDARY_TYPE; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + #if CONFIG_EXT_TX #define EXT_TX_SIZES 4 // number of sizes that use extended transforms #define EXT_TX_SETS_INTER 4 // Sets of transform selections for INTER
diff --git a/av1/common/loopfilter.c b/av1/common/loopfilter.c index 5821c75..16c3763 100644 --- a/av1/common/loopfilter.c +++ b/av1/common/loopfilter.c
@@ -884,6 +884,34 @@ *int_4x4_y |= (size_mask[block_size] & 0xffffffffffffffffULL) << shift_y; } +#if CONFIG_DEBLOCKING_ACROSS_TILES +// This function update the bit masks for the entire 64x64 region represented +// by mi_row, mi_col. In case one of the edge is a tile boundary, loop filtering +// for that edge is disabled. This function only check the tile boundary info +// for the top left corner mi to determine the boundary information for the +// top and left edge of the whole super block +static void update_tile_boundary_filter_mask(AV1_COMMON *const cm, + const int mi_row, const int mi_col, + LOOP_FILTER_MASK *lfm) { + int i; + MODE_INFO *const mi = cm->mi + mi_row * cm->mi_stride + mi_col; + + if (mi->mbmi.tile_boundary_info & TILE_LEFT_BOUNDARY) { + for (i = 0; i <= TX_32X32; i++) { + lfm->left_y[i] &= 0xfefefefefefefefeULL; + lfm->left_uv[i] &= 0xeeee; + } + } + + if (mi->mbmi.tile_boundary_info & TILE_ABOVE_BOUNDARY) { + for (i = 0; i <= TX_32X32; i++) { + lfm->above_y[i] &= 0xffffffffffffff00ULL; + lfm->above_uv[i] &= 0xfff0; + } + } +} +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + // This function sets up the bit masks for the entire 64x64 region represented // by mi_row, mi_col. // TODO(JBB): This function only works for yv12. @@ -1169,6 +1197,12 @@ } } +#if CONFIG_DEBLOCKING_ACROSS_TILES + if (av1_disable_loopfilter_on_tile_boundary(cm)) { + update_tile_boundary_filter_mask(cm, mi_row, mi_col, lfm); + } +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + // Assert if we try to apply 2 different loop filters at the same position. assert(!(lfm->left_y[TX_16X16] & lfm->left_y[TX_8X8])); assert(!(lfm->left_y[TX_16X16] & lfm->left_y[TX_4X4])); @@ -1410,8 +1444,15 @@ } } - // Disable filtering on the leftmost column + // Disable filtering on the leftmost column or tile boundary border_mask = ~(mi_col == 0); +#if CONFIG_DEBLOCKING_ACROSS_TILES + if (av1_disable_loopfilter_on_tile_boundary(cm) && + ((mib[0]->mbmi.tile_boundary_info & TILE_LEFT_BOUNDARY) != 0)) { + border_mask = 0xfffffffe; + } +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + #if CONFIG_AOM_HIGHBITDEPTH if (cm->use_highbitdepth) { highbd_filter_selectively_vert( @@ -1602,10 +1643,21 @@ unsigned int mask_8x8_r; unsigned int mask_4x4_r; +#if CONFIG_DEBLOCKING_ACROSS_TILES + // Disable filtering on the abovemost row or tile boundary + const MODE_INFO *mi = cm->mi + (mi_row + r) * cm->mi_stride; + if ((av1_disable_loopfilter_on_tile_boundary(cm) && + (mi->mbmi.tile_boundary_info & TILE_ABOVE_BOUNDARY)) || + (mi_row + idx_r == 0)) { + mask_16x16_r = 0; + mask_8x8_r = 0; + mask_4x4_r = 0; +#else if (mi_row + idx_r == 0) { mask_16x16_r = 0; mask_8x8_r = 0; mask_4x4_r = 0; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES } else { mask_16x16_r = mask_16x16[r]; mask_8x8_r = mask_8x8[r];
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h index 2c9505c..fcf2694 100644 --- a/av1/common/onyxc_int.h +++ b/av1/common/onyxc_int.h
@@ -363,6 +363,10 @@ int tile_cols, tile_rows; int tile_width, tile_height; // In MI units +#if CONFIG_DEBLOCKING_ACROSS_TILES + int loop_filter_across_tiles_enabled; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + int byte_alignment; int skip_loop_filter;
diff --git a/av1/common/tile_common.c b/av1/common/tile_common.c index 2c0e5c6..62ceb12 100644 --- a/av1/common/tile_common.c +++ b/av1/common/tile_common.c
@@ -59,3 +59,29 @@ assert(*min_log2_tile_cols <= *max_log2_tile_cols); } #endif // !CONFIG_EXT_TILE + +#if CONFIG_DEBLOCKING_ACROSS_TILES +void av1_update_tile_boundary_info(const struct AV1Common *cm, + const TileInfo *const tile_info, int mi_row, + int mi_col) { + int row, col; + for (row = mi_row; row < (mi_row + cm->mib_size); row++) + for (col = mi_col; col < (mi_col + cm->mib_size); col++) { + MODE_INFO *const mi = cm->mi + row * cm->mi_stride + col; + mi->mbmi.tile_boundary_info = 0; + if (row == tile_info->mi_row_start) + mi->mbmi.tile_boundary_info |= TILE_ABOVE_BOUNDARY; + if (col == tile_info->mi_col_start) + mi->mbmi.tile_boundary_info |= TILE_LEFT_BOUNDARY; + if ((row + 1) >= tile_info->mi_row_end) + mi->mbmi.tile_boundary_info |= TILE_BOTTOM_BOUNDARY; + if ((col + 1) >= tile_info->mi_col_end) + mi->mbmi.tile_boundary_info |= TILE_RIGHT_BOUNDARY; + } +} + +int av1_disable_loopfilter_on_tile_boundary(const struct AV1Common *cm) { + return (!cm->loop_filter_across_tiles_enabled && + (cm->tile_cols * cm->tile_rows > 1)); +} +#endif // CONFIG_DEBLOCKING_ACROSS_TILES
diff --git a/av1/common/tile_common.h b/av1/common/tile_common.h index 2e83820..a5023a7 100644 --- a/av1/common/tile_common.h +++ b/av1/common/tile_common.h
@@ -38,6 +38,13 @@ void av1_get_tile_n_bits(const int mi_cols, int *min_log2_tile_cols, int *max_log2_tile_cols); +#if CONFIG_DEBLOCKING_ACROSS_TILES +void av1_update_tile_boundary_info(const struct AV1Common *cm, + const TileInfo *const tile_info, int mi_row, + int mi_col); +int av1_disable_loopfilter_on_tile_boundary(const struct AV1Common *cm); +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + #ifdef __cplusplus } // extern "C" #endif
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 3fccb0d..a2ae3b3 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -2764,6 +2764,10 @@ cm->tile_height = aom_rb_read_literal(rb, 6) + 1; } +#if CONFIG_DEBLOCKING_ACROSS_TILES + cm->loop_filter_across_tiles_enabled = aom_rb_read_bit(rb); +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + cm->tile_width <<= cm->mib_size_log2; cm->tile_height <<= cm->mib_size_log2; @@ -2799,6 +2803,10 @@ cm->log2_tile_rows = aom_rb_read_bit(rb); if (cm->log2_tile_rows) cm->log2_tile_rows += aom_rb_read_bit(rb); +#if CONFIG_DEBLOCKING_ACROSS_TILES + cm->loop_filter_across_tiles_enabled = aom_rb_read_bit(rb); +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + cm->tile_cols = 1 << cm->log2_tile_cols; cm->tile_rows = 1 << cm->log2_tile_rows; @@ -3264,6 +3272,12 @@ for (mi_col = tile_info.mi_col_start; mi_col < tile_info.mi_col_end; mi_col += cm->mib_size) { +#if CONFIG_DEBLOCKING_ACROSS_TILES + if (av1_disable_loopfilter_on_tile_boundary(cm)) { + av1_update_tile_boundary_info(cm, &tile_info, mi_row, mi_col); + } +#endif // CONFIG_DEBLOCKING_ACROSS_TILES + decode_partition(pbi, &td->xd, #if CONFIG_SUPERTX 0,
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index d721e53..0cb3bf1 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c
@@ -3382,6 +3382,10 @@ aom_wb_write_bit(wb, cm->log2_tile_rows != 0); if (cm->log2_tile_rows != 0) aom_wb_write_bit(wb, cm->log2_tile_rows != 1); #endif // CONFIG_EXT_TILE + +#if CONFIG_DEBLOCKING_ACROSS_TILES + aom_wb_write_bit(wb, cm->loop_filter_across_tiles_enabled); +#endif // CONFIG_DEBLOCKING_ACROSS_TILES } static int get_refresh_mask(AV1_COMP *cpi) {
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index 01fe0b7..beb9126 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c
@@ -4380,6 +4380,11 @@ MODE_INFO **mi = cm->mi_grid_visible + idx_str; PC_TREE *const pc_root = td->pc_root[cm->mib_size_log2 - MIN_MIB_SIZE_LOG2]; +#if CONFIG_DEBLOCKING_ACROSS_TILES + if (av1_disable_loopfilter_on_tile_boundary(cm)) { + av1_update_tile_boundary_info(cm, tile_info, mi_row, mi_col); + } +#endif // CONFIG_DEBLOCKING_ACROSS_TILES if (sf->adaptive_pred_interp_filter) { for (i = 0; i < leaf_nodes; ++i) td->leaf_tree[i].pred_interp_filter = SWITCHABLE;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 0ff8871..e9e7eb3 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -863,6 +863,11 @@ cm->tile_width = ALIGN_POWER_OF_TWO(cm->tile_width, MAX_MIB_SIZE_LOG2); cm->tile_height = ALIGN_POWER_OF_TWO(cm->tile_height, MAX_MIB_SIZE_LOG2); #endif // CONFIG_EXT_TILE + +#if CONFIG_DEBLOCKING_ACROSS_TILES + cm->loop_filter_across_tiles_enabled = + cpi->oxcf.loop_filter_across_tiles_enabled; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES } static void update_frame_size(AV1_COMP *cpi) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index ca5918a..e149bfb 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -238,6 +238,9 @@ int tile_columns; int tile_rows; +#if CONFIG_DEBLOCKING_ACROSS_TILES + int loop_filter_across_tiles_enabled; +#endif // CONFIG_DEBLOCKING_ACROSS_TILES int max_threads;