Only search compound modes with a good ref frame. A reference frame is good if, among the single reference modes, it was either the best frame or second best. STATS_CHANGED Lowres and midres test set indicate ~0.05 BD-rate drop for PSNR. Speed-up ranges from 1% to 15% and is highly dependent on target bitrate / speed setting. Biggest gains are when bitrate is high and --cpu-used=0. Change-Id: Ie290b721f5d952abdf61112c13fcc230a65cca02
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 08ff00d..224ee12 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c
@@ -12541,6 +12541,39 @@ return midx < 7 ? 2 : 0; } +static int compare_int64(const void *a, const void *b) { + int64_t a64 = *((int64_t *)a); + int64_t b64 = *((int64_t *)b); + if (a64 < b64) { + return -1; + } else if (a64 == b64) { + return 0; + } else { + return 1; + } +} + +// Find the 2nd best RD for a reference frame (among single reference modes) +// and store it in the 0-th element in ref_frame_rd. +static void find_top_2_ref(int64_t ref_frame_rd[REF_FRAMES]) { + assert(ref_frame_rd[0] == INT64_MAX); + int64_t ref_copy[REF_FRAMES - 1]; + memcpy(ref_copy, ref_frame_rd + 1, + sizeof(ref_frame_rd[0]) * (REF_FRAMES - 1)); + qsort(ref_copy, REF_FRAMES - 1, sizeof(int64_t), compare_int64); + int64_t second_best = ref_copy[1]; + ref_frame_rd[0] = second_best; +} + +// Check if either frame is one of the top two. +static INLINE bool in_top_2_ref(int64_t ref_frame_rd[REF_FRAMES], + MV_REFERENCE_FRAME frame1, + MV_REFERENCE_FRAME frame2) { + assert(frame2 > 0); + return ref_frame_rd[frame1] <= ref_frame_rd[0] || + ref_frame_rd[frame2] <= ref_frame_rd[0]; +} + void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *x, int mi_row, int mi_col, RD_STATS *rd_cost, BLOCK_SIZE bsize, @@ -12631,6 +12664,12 @@ CompoundTypeRdBuffers rd_buffers; alloc_compound_type_rd_buffers(cm, &rd_buffers); + // The best RD found for the reference frame, among single reference modes. + // Note that the 0-th element will contain a cut-off that is later used + // to determine if we should skip a compound mode. + int64_t ref_frame_rd[REF_FRAMES] = { INT64_MAX, INT64_MAX, INT64_MAX, + INT64_MAX, INT64_MAX, INT64_MAX, + INT64_MAX, INT64_MAX }; for (int midx = 0; midx < MAX_MODES; ++midx) { const int do_tx_search = do_tx_search_mode( do_tx_search_global, midx, sf->inter_mode_rd_model_estimation_adaptive); @@ -12640,6 +12679,18 @@ const MV_REFERENCE_FRAME second_ref_frame = mode_order->ref_frame[1]; const int comp_pred = second_ref_frame > INTRA_FRAME; + // After we done with single reference modes, find the 2nd best RD + // for a reference frame. Only search compound modes that have a reference + // frame at least as good as the 2nd best. + if (sf->prune_compound_using_single_ref && + midx == MAX_SINGLE_REF_MODES + 1) { + find_top_2_ref(ref_frame_rd); + } + if (sf->prune_compound_using_single_ref && midx > MAX_SINGLE_REF_MODES && + comp_pred && !in_top_2_ref(ref_frame_rd, ref_frame, second_ref_frame)) { + continue; + } + // Reach the first compound prediction mode if (sf->prune_comp_search_by_single_result > 0 && comp_pred && reach_first_comp_mode == 0) { @@ -12780,7 +12831,11 @@ } } - // Did this mode help.. i.e. is it the new best mode + if (sf->prune_compound_using_single_ref && midx <= MAX_SINGLE_REF_MODES && + this_rd < ref_frame_rd[ref_frame]) { + ref_frame_rd[ref_frame] = this_rd; + } + // Did this mode help, i.e., is it the new best mode if (this_rd < search_state.best_rd || x->skip) { int mode_excluded = 0; if (comp_pred) {
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c index 79674ae..5150b47 100644 --- a/av1/encoder/speed_features.c +++ b/av1/encoder/speed_features.c
@@ -210,6 +210,7 @@ // TODO(debargha): Test, tweak and turn on either 1 or 2 sf->inter_mode_rd_model_estimation = 1; sf->inter_mode_rd_model_estimation_adaptive = 0; + sf->prune_compound_using_single_ref = 1; sf->prune_mode_search_simple_translation = 1; sf->two_loop_comp_search = 0; @@ -432,6 +433,7 @@ // TODO(debargha): Test, tweak and turn on either 1 or 2 sf->inter_mode_rd_model_estimation = 0; sf->inter_mode_rd_model_estimation_adaptive = 0; + sf->prune_compound_using_single_ref = 0; sf->prune_mode_search_simple_translation = 1; sf->two_loop_comp_search = 0; @@ -777,6 +779,7 @@ sf->inter_mode_rd_model_estimation = 0; sf->inter_mode_rd_model_estimation_adaptive = 0; + sf->prune_compound_using_single_ref = 0; sf->prune_mode_search_simple_translation = 0; sf->obmc_full_pixel_search_level = 0;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h index 14d1be6..dbdf4a0 100644 --- a/av1/encoder/speed_features.h +++ b/av1/encoder/speed_features.h
@@ -716,6 +716,11 @@ // check intra prediction for non-RD mode. int check_intra_pred_nonrd; + + // Only search compound modes with at least one "good" reference frame. + // A reference frame is good if, after looking at its performance among + // the single reference modes, it is one of the two best performers. + int prune_compound_using_single_ref; } SPEED_FEATURES; struct AV1_COMP;