From 76cc69f884a5261880396a3d93664455a1dff3ff Mon Sep 17 00:00:00 2001 From: Marco Paniconi Date: Thu, 7 Jun 2018 10:52:09 -0700 Subject: [PATCH] vp9-svc: Allow second temporal reference for next highest layer. When inter-layer prediction is disabled on INTER frames, allow for next highest resolution to have second temporal reference. Current code allowed for only top/highest spatial layer. Change-Id: I102137273e3e4d57512a13d95e8ccb9c5b0a7b4b --- vp9/encoder/vp9_ratectrl.c | 5 ++++- vp9/encoder/vp9_svc_layercontext.c | 32 ++++++++++++++++++++---------- vp9/encoder/vp9_svc_layercontext.h | 3 ++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 968e181ee..e3d1b3713 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1879,8 +1879,11 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { if (svc->layer_context[svc->temporal_layer_id].is_key_frame) { // On key frame we update the buffer index used for long term reference. // Use the alt_ref since it is not used or updated on key frames. + int index = svc->spatial_layer_id; cpi->ext_refresh_alt_ref_frame = 1; - cpi->alt_fb_idx = svc->buffer_longterm_ref.idx; + if (svc->number_spatial_layers == 3) index = svc->spatial_layer_id - 1; + assert(index >= 0); + cpi->alt_fb_idx = svc->buffer_longterm_ref[index].idx; } else if (rc->frames_till_gf_update_due == 0) { // Set perdiod of next update. Make it a multiple of 10, as the cyclic // refresh is typically ~10%, and we'd like the update to happen after diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index a72083b61..c606125b2 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -62,8 +62,10 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { } svc->max_consec_drop = INT_MAX; - svc->buffer_longterm_ref.idx = 7; - svc->buffer_longterm_ref.is_used = 0; + svc->buffer_longterm_ref[1].idx = 7; + svc->buffer_longterm_ref[0].idx = 6; + svc->buffer_longterm_ref[1].is_used = 0; + svc->buffer_longterm_ref[0].is_used = 0; if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) { if (vpx_realloc_frame_buffer(&cpi->svc.empty_frame.img, SMALL_FRAME_WIDTH, @@ -714,10 +716,14 @@ int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { } } - if (cpi->lst_fb_idx == svc->buffer_longterm_ref.idx || - cpi->gld_fb_idx == svc->buffer_longterm_ref.idx || - cpi->alt_fb_idx == svc->buffer_longterm_ref.idx) - svc->buffer_longterm_ref.is_used = 1; + if (cpi->lst_fb_idx == svc->buffer_longterm_ref[0].idx || + cpi->gld_fb_idx == svc->buffer_longterm_ref[0].idx || + cpi->alt_fb_idx == svc->buffer_longterm_ref[0].idx) + svc->buffer_longterm_ref[0].is_used = 1; + if (cpi->lst_fb_idx == svc->buffer_longterm_ref[1].idx || + cpi->gld_fb_idx == svc->buffer_longterm_ref[1].idx || + cpi->alt_fb_idx == svc->buffer_longterm_ref[1].idx) + svc->buffer_longterm_ref[1].is_used = 1; // For the fixed (non-flexible/bypass) SVC mode: // If long term temporal reference is enabled at the sequence level @@ -725,21 +731,25 @@ int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { // we can use golden as a second temporal reference // (since the spatial/inter-layer reference is disabled). // We check that the fb_idx for this reference (buffer_longterm_ref.idx) is - // unused (slot 7 should be available for 3-3 layer system). + // unused (slot 7 and 6 should be available for 3-3 layer system). // For now usage of this second temporal reference will only be used for - // highest spatial layer. + // highest and next to highest spatial layer (i.e., top and middle layer for + // 3 spatial layers). svc->use_longterm_ref_current_layer = 0; - if (svc->use_longterm_ref && !svc->buffer_longterm_ref.is_used && + if (svc->use_longterm_ref && !svc->buffer_longterm_ref[0].is_used && + !svc->buffer_longterm_ref[1].is_used && svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS && svc->disable_inter_layer_pred != INTER_LAYER_PRED_ON && svc->number_spatial_layers <= 3 && svc->number_temporal_layers <= 3 && - svc->spatial_layer_id == svc->number_spatial_layers - 1) { + svc->spatial_layer_id >= svc->number_spatial_layers - 2) { // Enable the second (long-term) temporal reference at the frame-level. svc->use_longterm_ref_current_layer = 1; // Only used for prediction for on non-key superframes. if (!svc->layer_context[svc->temporal_layer_id].is_key_frame) { // Use golden for this reference which will be used for prediction. - cpi->gld_fb_idx = svc->buffer_longterm_ref.idx; + int index = svc->spatial_layer_id; + if (svc->number_spatial_layers == 3) index = svc->spatial_layer_id - 1; + cpi->gld_fb_idx = svc->buffer_longterm_ref[index].idx; // Enable prediction off LAST (last reference) and golden (which will // generally be further behind/long-term reference). cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG; diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index c766c2016..b7a4e2769 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -106,7 +106,8 @@ typedef struct SVC { int use_longterm_ref; // Frame level flag to enable second (long term) temporal reference. int use_longterm_ref_current_layer; - BUFFER_LONGTERM_REF buffer_longterm_ref; + // Allow second reference for at most 2 top highest resolution layers. + BUFFER_LONGTERM_REF buffer_longterm_ref[2]; int current_superframe; int non_reference_frame; int use_base_mv; -- 2.40.0