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); } }