Stabilize temporal filtering and TPL motion search for HBD Favor zero motion vector (0,0) in stationary/near-stationary regions during temporal filtering motion search and TPL mode estimation. Disable sub-block motion estimation in temporal filtering and clamp filter strength to 0 for low-contrast blocks when sharpness is 3. Bug: 548701298 Change-Id: Id5f1a8ed67a1b609159a15a969064419b053beab
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c index be7ff38..97be8fc 100644 --- a/av1/encoder/temporal_filter.c +++ b/av1/encoder/temporal_filter.c
@@ -382,6 +382,27 @@ *is_dc_diff_large = 50 * error < sse; if (src_var <= 2 * (int64_t)distortion) *is_low_cntras = 1; +#if CONFIG_AV1_HIGHBITDEPTH + const MACROBLOCKD *xd = &mb->e_mbd; + if (xd->bd > 8 && cpi->oxcf.algo_cfg.sharpness == 3) { + // Favor zero motion vector (0,0) for stationary/near-stationary regions + // when zero-motion error is close to the best found error or sufficiently + // small. + unsigned int zero_sse; + unsigned int zero_error = cpi->ppi->fn_ptr[block_size].vf( + ref_frame->y_buffer + y_offset, y_stride, + frame_to_filter->y_buffer + y_offset, y_stride, &zero_sse); + if (zero_error <= error + (error >> 4) || (zero_error / mb_pels) < 16) { + best_mv.as_mv = kZeroMv; + block_mv = kZeroMv; + *ref_mv = kZeroMv; + error = zero_error; + distortion = (int)zero_error; + block_mse = DIVIDE_AND_ROUND(error, mb_pels); + } + } +#endif + // On 4 mid-blocks in the 64x64 tf block. if (allow_me_for_sub_blks) { // midblock_size is 32x32, which corresponds to each 32x32 block in the @@ -1092,7 +1113,12 @@ // partition only if the difference between max and min source variance of // 4x4 blocks is greater than a threshold (which is derived empirically). bool allow_me_for_sub_blks = true; - if (cpi->sf.hl_sf.allow_sub_blk_me_in_tf) { + // In high bit-depth sharpness mode, disable sub-block motion estimation to + // avoid inconsistent filtering across sub-partitions and preserve + // sharpness. + if (mbd->bd > 8 && cpi->oxcf.algo_cfg.sharpness == 3) { + allow_me_for_sub_blks = false; + } else if (cpi->sf.hl_sf.allow_sub_blk_me_in_tf) { const int is_hbd = is_frame_high_bitdepth(frame_to_filter); // Initialize minimum variance to a large value and maximum variance to 0. double blk_4x4_var_min = DBL_MAX; @@ -1139,7 +1165,7 @@ filter_strength = AOMMIN(filter_strength, 1); if (cpi->oxcf.algo_cfg.sharpness == 3 && is_low_cntras) - filter_strength = AOMMIN(filter_strength, 3); + filter_strength = AOMMIN(filter_strength, mbd->bd > 8 ? 0 : 3); // Perform weighted averaging. if (frame == filter_frame_idx) { // Frame to be filtered.
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c index a22341b..34cf2bf 100644 --- a/av1/encoder/tpl_model.c +++ b/av1/encoder/tpl_model.c
@@ -854,6 +854,20 @@ cpi, x, src_mb_buffer, ref_mb, src_stride, ref_stride, src_width, ref_width, bsize, center_mvs[idx].mv.as_mv, &this_mv); +#if CONFIG_AV1_HIGHBITDEPTH + if (xd->bd > 8 && cpi->oxcf.algo_cfg.sharpness == 3) { + // Bias towards (0,0) / short motion vectors in stationary background. + // Require a noticeable SAD improvement before replacing (0,0) with a + // non-zero MV. + if (bestsme != UINT32_MAX && best_rfidx_mv.as_int == 0 && + this_mv.as_int != 0) { + if (thissme + (thissme >> 4) >= bestsme) { + continue; + } + } + } +#endif + if (thissme < bestsme) { bestsme = thissme; best_rfidx_mv = this_mv;