Unify two strategies for temporal filtering.
Currently, there are two strategies for temporal filtering, i.e., YUV
and plane-wise. The difference is that YUV is mostly used for lowres
videos while plane-wise is commonly used for midres and hdres.
This CL unifies the filtering strategies. After recent improvements on
plane-wise stragegy, it shows better performance on lowres videos than
YUV strategy. So, to simplify the filtering process, we always choose
the plane-wise stragegy regardless of the video resolution.
See https://aomedia-review.googlesource.com/c/aom/+/108961 and
https://aomedia-review.googlesource.com/c/aom/+/108965 for the
improvements on plane-wise strategy.
NOTE: This CL only affects the performance on lowres datasets.
Experimental results:
Under Speed-4 (two-pass mode):
avg PSNR ovr PSNR SSIM
ugc360p -0.180 -0.180 -0.094
lowres -0.044 -0.227 -0.189
lowres2 -0.040 -0.184 -0.185
Under Speed-1 (two-pass mode):
avg PSNR ovr PSNR SSIM
ugc360p -0.210 -0.236 -0.108
lowres -0.014 -0.161 -0.118
lowres2 0.086 -0.042 -0.016
STATS_CHANGED
Change-Id: I73687c363bcc077b7383aea117d4703be62cf6fb
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index 583cfb7..a637df5 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -218,9 +218,6 @@
// Inputs:
// block_mse: Motion search error (MSE) for the entire block.
// subblock_mses: Pointer to the search errors (MSE) for 4 sub-blocks.
-// use_planewise_strategy: Whether to use plane-wise filtering strategy. This
-// field will affect the filter weight for the
-// to-filter frame.
// is_second_arf: Whether the to-filter frame is the second ARF. This field
// will affect the filter weight for the to-filter frame.
// subblock_filter_weights: Pointer to the assigned filter weight for each
@@ -228,15 +225,15 @@
// element will be used for the entire block.
// Returns: Whether to use 4 sub-blocks to replace the original block.
static int tf_get_filter_weight(const int block_mse, const int *subblock_mses,
- const int use_planewise_strategy,
const int is_second_arf,
int *subblock_filter_weights) {
// `block_mse` is initialized as INT_MAX and will be overwritten after the
// motion search with reference frame, therefore INT_MAX can ONLY be accessed
// by to-filter frame.
if (block_mse == INT_MAX) {
- const int weight = use_planewise_strategy ? TF_PLANEWISE_FILTER_WEIGHT_SCALE
- : is_second_arf ? 64 : 32;
+ const int weight = TF_ENABLE_PLANEWISE_STRATEGY
+ ? TF_PLANEWISE_FILTER_WEIGHT_SCALE
+ : is_second_arf ? 64 : 32;
subblock_filter_weights[0] = subblock_filter_weights[1] =
subblock_filter_weights[2] = subblock_filter_weights[3] = weight;
return 0;
@@ -782,7 +779,6 @@
// mb_row: Row index of the block in the entire frame.
// mb_col: Column index of the block in the entire frame.
// num_planes: Number of planes in the frame.
-// use_planewise_strategy: Whether to use plane-wise strategy or YUV strategy.
// strength: Strength for filter weight adjustment. (Used in YUV strategy)
// use_subblock: Whether to use 4 sub-blocks to replace the original block.
// (Used in YUV strategy)
@@ -805,15 +801,16 @@
void av1_apply_temporal_filter_others(
const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd,
const BLOCK_SIZE block_size, const int mb_row, const int mb_col,
- const int num_planes, const int use_planewise_strategy, const int strength,
- const int use_subblock, const int *subblock_filter_weights,
- const double *noise_levels, const int block_mse, const int *subblock_mses,
- const int q_factor, const uint8_t *pred, uint32_t *accum, uint16_t *count) {
+ const int num_planes, const int strength, const int use_subblock,
+ const int *subblock_filter_weights, const double *noise_levels,
+ const int block_mse, const int *subblock_mses, const int q_factor,
+ const uint8_t *pred, uint32_t *accum, uint16_t *count) {
assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE);
- if (use_planewise_strategy) { // Commonly used for high-resolution video.
- // TODO(any): avx2 and sse2 version should also support high bit-depth.
- if (is_frame_high_bitdepth(frame_to_filter)) {
+ if (TF_ENABLE_PLANEWISE_STRATEGY) {
+ // TODO(any): avx2 and sse2 version should be changed to align with C
+ // function before using.
+ if (is_frame_high_bitdepth(frame_to_filter) || block_size != BLOCK_32X32) {
av1_apply_temporal_filter_planewise_c(
frame_to_filter, mbd, block_size, mb_row, mb_col, num_planes,
noise_levels, use_subblock, block_mse, subblock_mses, q_factor, pred,
@@ -830,7 +827,8 @@
return;
}
const int adj_strength = strength + 2 * (mbd->bd - 8);
- if (num_planes == 3 && TF_YUV_FILTER_WEIGHT_SCALE == 3) {
+ if (num_planes == 3 && TF_YUV_FILTER_WEIGHT_SCALE == 3 &&
+ block_size != BLOCK_32X32) {
av1_apply_temporal_filter_yuv(frame_to_filter, mbd, block_size, mb_row,
mb_col, num_planes, adj_strength,
use_subblock, subblock_filter_weights, pred,
@@ -976,8 +974,6 @@
// Do filtering.
FRAME_DIFF diff = { 0, 0 };
- const int use_planewise_strategy =
- TF_ENABLE_PLANEWISE_STRATEGY && AOMMIN(frame_height, frame_width) >= 480;
// Perform temporal filtering block by block.
for (int mb_row = 0; mb_row < mb_rows; mb_row++) {
av1_set_mv_row_limits(&cpi->common.mi_params, &mb->mv_limits,
@@ -1019,8 +1015,7 @@
// Build predictor.
int use_subblock = tf_get_filter_weight(
- block_mse, subblock_mses, use_planewise_strategy, is_second_arf,
- subblock_filter_weights);
+ block_mse, subblock_mses, is_second_arf, subblock_filter_weights);
tf_build_predictor(frames[frame], mbd, block_size, mb_row, mb_col,
num_planes, scale, use_subblock, subblock_mvs, pred);
@@ -1038,9 +1033,8 @@
cpi->common.seq_params.bit_depth);
av1_apply_temporal_filter_others(
frame_to_filter, mbd, block_size, mb_row, mb_col, num_planes,
- use_planewise_strategy, strength, use_subblock,
- subblock_filter_weights, noise_levels, block_mse, subblock_mses,
- q_factor, pred, accum, count);
+ strength, use_subblock, subblock_filter_weights, noise_levels,
+ block_mse, subblock_mses, q_factor, pred, accum, count);
}
}