From c760c33b993c26376631474a54f2f04a58aaf8a2 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 7 Dec 2015 12:23:56 -0800 Subject: [PATCH] SVC 1 pass mode: Constrain inter mode search within superframe. Keep track of frame indexes for the references, and constrain inter mode search for reference with same temporal alignment. Improves speed by about ~15%, no noticeable loss in compression performance. Change-Id: I5c407a8acca921234060c4fcef4afd7d734201c8 --- vp9/encoder/vp9_encoder.c | 16 ++++++++++++++++ vp9/encoder/vp9_pickmode.c | 20 +++++++++++++++++++- vp9/encoder/vp9_svc_layercontext.c | 9 ++++++++- vp9/encoder/vp9_svc_layercontext.h | 3 +++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 72fa828..9c43518 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -2793,6 +2793,22 @@ void vp9_update_reference_frames(VP9_COMP *cpi) { cpi->resize_pending); } #endif + if (is_one_pass_cbr_svc(cpi)) { + // Keep track of frame index for each reference frame. + SVC *const svc = &cpi->svc; + if (cm->frame_type == KEY_FRAME) { + svc->ref_frame_index[cpi->lst_fb_idx] = svc->current_superframe; + svc->ref_frame_index[cpi->gld_fb_idx] = svc->current_superframe; + svc->ref_frame_index[cpi->alt_fb_idx] = svc->current_superframe; + } else { + if (cpi->refresh_last_frame) + svc->ref_frame_index[cpi->lst_fb_idx] = svc->current_superframe; + if (cpi->refresh_golden_frame) + svc->ref_frame_index[cpi->gld_fb_idx] = svc->current_superframe; + if (cpi->refresh_alt_ref_frame) + svc->ref_frame_index[cpi->alt_fb_idx] = svc->current_superframe; + } + } } static void loopfilter_frame(VP9_COMP *cpi, VP9_COMMON *cm) { diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 90650db..9b69ede 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -1094,6 +1094,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx) { VP9_COMMON *const cm = &cpi->common; SPEED_FEATURES *const sf = &cpi->sf; + const SVC *const svc = &cpi->svc; TileInfo *const tile_info = &tile_data->tile_info; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi; @@ -1143,6 +1144,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, int best_pred_sad = INT_MAX; int best_early_term = 0; int ref_frame_cost[MAX_REF_FRAMES]; + int svc_force_zero_mode[3] = {0}; #if CONFIG_VP9_TEMPORAL_DENOISING int64_t zero_last_cost_orig = INT64_MAX; #endif @@ -1196,6 +1198,17 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, } else { usable_ref_frame = GOLDEN_FRAME; } + + // If the reference is temporally aligned with current superframe + // (e.g., spatial reference within superframe), constrain the inter mode: + // for now only test zero motion. + if (cpi->use_svc && svc ->force_zero_mode_spatial_ref) { + if (svc->ref_frame_index[cpi->lst_fb_idx] == svc->current_superframe) + svc_force_zero_mode[LAST_FRAME - 1] = 1; + if (svc->ref_frame_index[cpi->gld_fb_idx] == svc->current_superframe) + svc_force_zero_mode[GOLDEN_FRAME - 1] = 1; + } + for (ref_frame = LAST_FRAME; ref_frame <= usable_ref_frame; ++ref_frame) { const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame); @@ -1248,8 +1261,13 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, continue; ref_frame = ref_mode_set[idx].ref_frame; - if (cpi->use_svc) + if (cpi->use_svc) { ref_frame = ref_mode_set_svc[idx].ref_frame; + if (svc_force_zero_mode[ref_frame - 1] && + frame_mv[this_mode][ref_frame].as_int != 0) + continue; + } + if (!(cpi->ref_frame_flags & flag_list[ref_frame])) continue; if (const_motion[ref_frame] && this_mode == NEARMV) diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index b0617c1..a4e7eb1 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -25,13 +25,17 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { const VP9EncoderConfig *const oxcf = &cpi->oxcf; int mi_rows = cpi->common.mi_rows; int mi_cols = cpi->common.mi_cols; - int sl, tl; + int sl, tl, i; int alt_ref_idx = svc->number_spatial_layers; svc->spatial_layer_id = 0; svc->temporal_layer_id = 0; svc->first_spatial_layer_to_encode = 0; svc->rc_drop_superframe = 0; + svc->force_zero_mode_spatial_ref = 0; + svc->current_superframe = 0; + for (i = 0; i < REF_FRAMES; ++i) + svc->ref_frame_index[i] = -1; if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) { if (vpx_realloc_frame_buffer(&cpi->svc.empty_frame.img, @@ -353,6 +357,8 @@ void vp9_inc_frame_in_layer(VP9_COMP *const cpi) { cpi->svc.number_temporal_layers]; ++lc->current_video_frame_in_layer; ++lc->frames_from_key_frame; + if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) + ++cpi->svc.current_superframe; } int vp9_is_upper_layer_key_frame(const VP9_COMP *const cpi) { @@ -542,6 +548,7 @@ static void set_flags_and_fb_idx_for_temporal_mode_noLayering( int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { int width = 0, height = 0; LAYER_CONTEXT *lc = NULL; + cpi->svc.force_zero_mode_spatial_ref = 1; if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) { set_flags_and_fb_idx_for_temporal_mode3(cpi); diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index 5dbf9b4..1f446d7 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -83,6 +83,9 @@ typedef struct { int ext_lst_fb_idx[VPX_MAX_LAYERS]; int ext_gld_fb_idx[VPX_MAX_LAYERS]; int ext_alt_fb_idx[VPX_MAX_LAYERS]; + int ref_frame_index[REF_FRAMES]; + int force_zero_mode_spatial_ref; + int current_superframe; } SVC; struct VP9_COMP; -- 2.7.4