diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 8ca05c1c0..5c304462a 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -294,6 +294,7 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, vp9_write_token(w, vp9_switchable_interp_tree, cm->fc.switchable_interp_prob[ctx], &switchable_interp_encodings[mbmi->interp_filter]); + ++cpi->interp_filter_selected[0][mbmi->interp_filter]; } else { assert(mbmi->interp_filter == cm->interp_filter); } diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 3210ab5c8..8464882ea 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -131,8 +131,10 @@ static void setup_frame(VP9_COMP *cpi) { if (!is_spatial_svc(cpi)) cpi->refresh_golden_frame = 1; cpi->refresh_alt_ref_frame = 1; + vp9_zero(cpi->interp_filter_selected); } else { cm->fc = cm->frame_contexts[cm->frame_context_idx]; + vp9_zero(cpi->interp_filter_selected[0]); } } @@ -1556,17 +1558,32 @@ void vp9_update_reference_frames(VP9_COMP *cpi) { ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[arf_idx], cm->new_fb_idx); + vpx_memcpy(cpi->interp_filter_selected[ALTREF_FRAME], + cpi->interp_filter_selected[0], + sizeof(cpi->interp_filter_selected[0])); } if (cpi->refresh_golden_frame) { ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx); + if (!cpi->rc.is_src_frame_alt_ref) + vpx_memcpy(cpi->interp_filter_selected[GOLDEN_FRAME], + cpi->interp_filter_selected[0], + sizeof(cpi->interp_filter_selected[0])); + else + vpx_memcpy(cpi->interp_filter_selected[GOLDEN_FRAME], + cpi->interp_filter_selected[ALTREF_FRAME], + sizeof(cpi->interp_filter_selected[ALTREF_FRAME])); } } if (cpi->refresh_last_frame) { ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[cpi->lst_fb_idx], cm->new_fb_idx); + if (!cpi->rc.is_src_frame_alt_ref) + vpx_memcpy(cpi->interp_filter_selected[LAST_FRAME], + cpi->interp_filter_selected[0], + sizeof(cpi->interp_filter_selected[0])); } #if CONFIG_VP9_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity > 0) { @@ -2057,6 +2074,33 @@ static void set_mv_search_params(VP9_COMP *cpi) { } } + +int setup_interp_filter_search_mask(VP9_COMP *cpi) { + INTERP_FILTER ifilter; + int ref_total[MAX_REF_FRAMES] = {0}; + MV_REFERENCE_FRAME ref; + int mask = 0; + if (cpi->common.last_frame_type == KEY_FRAME || + cpi->refresh_alt_ref_frame) + return mask; + for (ref = LAST_FRAME; ref <= ALTREF_FRAME; ++ref) + for (ifilter = EIGHTTAP; ifilter <= EIGHTTAP_SHARP; ++ifilter) + ref_total[ref] += cpi->interp_filter_selected[ref][ifilter]; + + for (ifilter = EIGHTTAP; ifilter <= EIGHTTAP_SHARP; ++ifilter) { + if ((ref_total[LAST_FRAME] && + cpi->interp_filter_selected[LAST_FRAME][ifilter] == 0) && + (ref_total[GOLDEN_FRAME] == 0 || + cpi->interp_filter_selected[GOLDEN_FRAME][ifilter] * 50 + < ref_total[GOLDEN_FRAME]) && + (ref_total[ALTREF_FRAME] == 0 || + cpi->interp_filter_selected[ALTREF_FRAME][ifilter] * 50 + < ref_total[ALTREF_FRAME])) + mask |= 1 << ifilter; + } + return mask; +} + static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size, uint8_t *dest, @@ -2096,6 +2140,12 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, set_mv_search_params(cpi); + if (cpi->oxcf.pass == 2 && + cpi->sf.adaptive_interp_filter_search) + cpi->sf.interp_filter_search_mask = + setup_interp_filter_search_mask(cpi); + + // Set various flags etc to special state if it is a key frame. if (frame_is_intra_only(cm)) { // Reset the loop filter deltas and segmentation map. @@ -2832,6 +2882,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, } } + if (cpi->b_calculate_ssimg) { double y, u, v, frame_all; frame_all = vp9_calc_ssimg(cpi->Source, cm->frame_to_show, &y, &u, &v); diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index b1b12a135..2dba67c54 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -285,6 +285,7 @@ typedef struct VP9_COMP { double framerate; vp9_coeff_count coef_counts[TX_SIZES][PLANE_TYPES]; + int interp_filter_selected[MAX_REF_FRAMES][SWITCHABLE]; struct vpx_codec_pkt_list *output_pkt_list; diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index e52620f81..5f1b0a515 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -2258,6 +2258,13 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, } else { int rate_sum = 0; int64_t dist_sum = 0; + if (i > 0 && cpi->sf.adaptive_interp_filter_search && + (cpi->sf.interp_filter_search_mask & (1 << i))) { + rate_sum = INT_MAX; + dist_sum = INT64_MAX; + continue; + } + if ((cm->interp_filter == SWITCHABLE && (!i || best_needs_copy)) || (cm->interp_filter != SWITCHABLE && diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 04d80ba5e..879c83c08 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -143,6 +143,7 @@ static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm, sf->mode_skip_start = 6; sf->intra_y_mode_mask[TX_32X32] = INTRA_DC; sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC; + sf->adaptive_interp_filter_search = 1; } if (speed >= 4) { @@ -381,6 +382,8 @@ void vp9_set_speed_features(VP9_COMP *cpi) { sf->force_frame_boost = 0; sf->max_delta_qindex = 0; sf->disable_filter_search_var_thresh = 0; + sf->adaptive_interp_filter_search = 0; + for (i = 0; i < TX_SIZES; i++) { sf->intra_y_mode_mask[i] = INTRA_ALL; sf->intra_uv_mode_mask[i] = INTRA_ALL; diff --git a/vp9/encoder/vp9_speed_features.h b/vp9/encoder/vp9_speed_features.h index bad956da5..e2e5c1e99 100644 --- a/vp9/encoder/vp9_speed_features.h +++ b/vp9/encoder/vp9_speed_features.h @@ -102,6 +102,12 @@ typedef enum { FLAG_SKIP_INTRA_LOWVAR = 1 << 5, } MODE_SEARCH_SKIP_LOGIC; +typedef enum { + FLAG_SKIP_EIGHTTAP = 1 << EIGHTTAP, + FLAG_SKIP_EIGHTTAP_SMOOTH = 1 << EIGHTTAP_SMOOTH, + FLAG_SKIP_EIGHTTAP_SHARP = 1 << EIGHTTAP_SHARP, +} INTERP_FILTER_MASK; + typedef enum { // Search partitions using RD/NONRD criterion SEARCH_PARTITION = 0, @@ -380,6 +386,12 @@ typedef struct SPEED_FEATURES { // Early termination in transform size search, which only applies while // tx_size_search_method is USE_FULL_RD. int tx_size_search_breakout; + + // adaptive interp_filter search to allow skip of certain filter types. + int adaptive_interp_filter_search; + + // mask for skip evaluation of certain interp_filter type. + INTERP_FILTER_MASK interp_filter_search_mask; } SPEED_FEATURES; struct VP9_COMP;