From 49785d3d0298ffc77915315bf1d37b26936128d1 Mon Sep 17 00:00:00 2001 From: Marco Paniconi Date: Wed, 6 Jun 2018 12:14:59 -0700 Subject: [PATCH] vp9-svc: Add a buffer_idx is_used parameter for SVC. For the case where a second (long term) temoral reference is used in the SVC: this additional parameter is to make sure the buffer slot selected for this reference is available for usage, i.e., it is never used for any of the 3 references set for the fixed SVC patterns. And some code cleanup (replace cpi->svc). No change in behavior. Change-Id: Icba46edfbbefb94d5ea8e2d5c24cccd85a406ee6 --- vp9/encoder/vp9_ratectrl.c | 32 +++--- vp9/encoder/vp9_svc_layercontext.c | 150 +++++++++++++++-------------- vp9/encoder/vp9_svc_layercontext.h | 7 +- 3 files changed, 98 insertions(+), 91 deletions(-) diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 198f3fd56..968e181ee 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1837,24 +1837,23 @@ static int calc_iframe_target_size_one_pass_cbr(const VP9_COMP *cpi) { void vp9_rc_get_svc_params(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; + SVC *const svc = &cpi->svc; int target = rc->avg_frame_bandwidth; - int layer = - LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id, cpi->svc.temporal_layer_id, - cpi->svc.number_temporal_layers); + int layer = LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id, + svc->number_temporal_layers); // Periodic key frames is based on the super-frame counter // (svc.current_superframe), also only base spatial layer is key frame. if ((cm->current_video_frame == 0) || (cpi->frame_flags & FRAMEFLAGS_KEY) || (cpi->oxcf.auto_key && - (cpi->svc.current_superframe % cpi->oxcf.key_freq == 0) && - cpi->svc.spatial_layer_id == 0)) { + (svc->current_superframe % cpi->oxcf.key_freq == 0) && + svc->spatial_layer_id == 0)) { cm->frame_type = KEY_FRAME; rc->source_alt_ref_active = 0; if (is_one_pass_cbr_svc(cpi)) { if (cm->current_video_frame > 0) vp9_svc_reset_key_frame(cpi); - layer = LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id, - cpi->svc.temporal_layer_id, - cpi->svc.number_temporal_layers); - cpi->svc.layer_context[layer].is_key_frame = 1; + layer = LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id, + svc->number_temporal_layers); + svc->layer_context[layer].is_key_frame = 1; cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); // Assumption here is that LAST_FRAME is being updated for a keyframe. // Thus no change in update flags. @@ -1863,12 +1862,12 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { } else { cm->frame_type = INTER_FRAME; if (is_one_pass_cbr_svc(cpi)) { - LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer]; - if (cpi->svc.spatial_layer_id == cpi->svc.first_spatial_layer_to_encode) { + LAYER_CONTEXT *lc = &svc->layer_context[layer]; + if (svc->spatial_layer_id == svc->first_spatial_layer_to_encode) { lc->is_key_frame = 0; } else { lc->is_key_frame = - cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame; + svc->layer_context[svc->temporal_layer_id].is_key_frame; } target = calc_pframe_target_size_one_pass_cbr(cpi); } @@ -1876,13 +1875,12 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { // If long term termporal feature is enabled, set the period of the update. // The update/refresh of this reference frame is always on base temporal // layer frame. - if (cpi->svc.use_longterm_ref_current_layer && - cpi->svc.temporal_layer_id == 0) { - if (cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) { + if (svc->use_longterm_ref_current_layer && svc->temporal_layer_id == 0) { + 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. cpi->ext_refresh_alt_ref_frame = 1; - cpi->alt_fb_idx = cpi->svc.buffer_idx_longterm_ref; + cpi->alt_fb_idx = svc->buffer_longterm_ref.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 @@ -1894,7 +1892,7 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { cpi->ext_refresh_golden_frame = 1; rc->gfu_boost = DEFAULT_GF_BOOST; } - } else if (!cpi->svc.use_longterm_ref) { + } else if (!svc->use_longterm_ref) { rc->frames_till_gf_update_due = INT_MAX; rc->baseline_gf_interval = INT_MAX; } diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index 1582b7b99..f5baa7cdd 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -62,6 +62,9 @@ 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; + if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) { if (vpx_realloc_frame_buffer(&cpi->svc.empty_frame.img, SMALL_FRAME_WIDTH, SMALL_FRAME_HEIGHT, cpi->common.subsampling_x, @@ -673,24 +676,24 @@ void vp9_copy_flags_ref_update_idx(VP9_COMP *const cpi) { int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { int width = 0, height = 0; + SVC *const svc = &cpi->svc; LAYER_CONTEXT *lc = NULL; - cpi->svc.skip_enhancement_layer = 0; - if (cpi->svc.number_spatial_layers > 1) { - cpi->svc.use_base_mv = 1; - cpi->svc.use_partition_reuse = 1; + svc->skip_enhancement_layer = 0; + if (svc->number_spatial_layers > 1) { + svc->use_base_mv = 1; + svc->use_partition_reuse = 1; } - cpi->svc.force_zero_mode_spatial_ref = 1; - cpi->svc.mi_stride[cpi->svc.spatial_layer_id] = cpi->common.mi_stride; + svc->force_zero_mode_spatial_ref = 1; + svc->mi_stride[svc->spatial_layer_id] = cpi->common.mi_stride; - if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) { + if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) { set_flags_and_fb_idx_for_temporal_mode3(cpi); - } else if (cpi->svc.temporal_layering_mode == + } else if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING) { set_flags_and_fb_idx_for_temporal_mode_noLayering(cpi); - } else if (cpi->svc.temporal_layering_mode == - VP9E_TEMPORAL_LAYERING_MODE_0101) { + } else if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0101) { set_flags_and_fb_idx_for_temporal_mode2(cpi); - } else if (cpi->svc.temporal_layering_mode == + } else if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS) { // In the BYPASS/flexible mode, the encoder is relying on the application // to specify, for each spatial layer, the flags and buffer indices for the @@ -702,37 +705,41 @@ int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { // this case. if (cpi->ext_refresh_frame_flags_pending == 0) { int sl; - cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode; - sl = cpi->svc.spatial_layer_id; - vp9_apply_encoding_flags(cpi, cpi->svc.ext_frame_flags[sl]); - cpi->lst_fb_idx = cpi->svc.lst_fb_idx[sl]; - cpi->gld_fb_idx = cpi->svc.gld_fb_idx[sl]; - cpi->alt_fb_idx = cpi->svc.alt_fb_idx[sl]; + svc->spatial_layer_id = svc->spatial_layer_to_encode; + sl = svc->spatial_layer_id; + vp9_apply_encoding_flags(cpi, svc->ext_frame_flags[sl]); + cpi->lst_fb_idx = svc->lst_fb_idx[sl]; + cpi->gld_fb_idx = svc->gld_fb_idx[sl]; + cpi->alt_fb_idx = svc->alt_fb_idx[sl]; } } + 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; + // For the fixed (non-flexible/bypass) SVC mode: // If long term temporal reference is enabled at the sequence level // (use_longterm_ref == 1), and inter_layer is disabled (on inter-frames), // we can use golden as a second temporal reference // (since the spatial/inter-layer reference is disabled). - // To be safe we use fb_index 7 for this, since for 3-3 layer system slot 7 - // should be free/un-used. For now usage of this second temporal reference - // will only be used for highest spatial layer. - cpi->svc.use_longterm_ref_current_layer = 0; - cpi->svc.buffer_idx_longterm_ref = 7; - if (cpi->svc.use_longterm_ref && - cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS && - cpi->svc.disable_inter_layer_pred != INTER_LAYER_PRED_ON && - cpi->svc.number_spatial_layers <= 3 && - cpi->svc.number_temporal_layers <= 3 && - cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) { + // 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). + // For now usage of this second temporal reference will only be used for + // highest spatial layer. + svc->use_longterm_ref_current_layer = 0; + if (svc->use_longterm_ref && !svc->buffer_longterm_ref.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) { // Enable the second (long-term) temporal reference at the frame-level. - cpi->svc.use_longterm_ref_current_layer = 1; + svc->use_longterm_ref_current_layer = 1; // Only used for prediction for on non-key superframes. - if (!cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) { + 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 = cpi->svc.buffer_idx_longterm_ref; + cpi->gld_fb_idx = svc->buffer_longterm_ref.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; @@ -740,32 +747,31 @@ int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { } // Reset the drop flags for all spatial layers, on the base layer. - if (cpi->svc.spatial_layer_id == 0) { - vp9_zero(cpi->svc.drop_spatial_layer); - // TODO(jianj/marpan): Investigate why setting cpi->svc.lst/gld/alt_fb_idx + if (svc->spatial_layer_id == 0) { + vp9_zero(svc->drop_spatial_layer); + // TODO(jianj/marpan): Investigate why setting svc->lst/gld/alt_fb_idx // causes an issue with frame dropping and temporal layers, when the frame // flags are passed via the encode call (bypass mode). Issue is that we're // resetting ext_refresh_frame_flags_pending to 0 on frame drops. - if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) { - memset(&cpi->svc.lst_fb_idx, -1, sizeof(cpi->svc.lst_fb_idx)); - memset(&cpi->svc.gld_fb_idx, -1, sizeof(cpi->svc.lst_fb_idx)); - memset(&cpi->svc.alt_fb_idx, -1, sizeof(cpi->svc.lst_fb_idx)); + if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) { + memset(&svc->lst_fb_idx, -1, sizeof(svc->lst_fb_idx)); + memset(&svc->gld_fb_idx, -1, sizeof(svc->lst_fb_idx)); + memset(&svc->alt_fb_idx, -1, sizeof(svc->lst_fb_idx)); } - vp9_zero(cpi->svc.update_last); - vp9_zero(cpi->svc.update_golden); - vp9_zero(cpi->svc.update_altref); - vp9_zero(cpi->svc.reference_last); - vp9_zero(cpi->svc.reference_golden); - vp9_zero(cpi->svc.reference_altref); + vp9_zero(svc->update_last); + vp9_zero(svc->update_golden); + vp9_zero(svc->update_altref); + vp9_zero(svc->reference_last); + vp9_zero(svc->reference_golden); + vp9_zero(svc->reference_altref); } - lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id * - cpi->svc.number_temporal_layers + - cpi->svc.temporal_layer_id]; + lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers + + svc->temporal_layer_id]; // Setting the worst/best_quality via the encoder control: SET_SVC_PARAMETERS, // only for non-BYPASS mode for now. - if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) { + if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) { RATE_CONTROL *const lrc = &lc->rc; lrc->worst_quality = vp9_quantizer_to_qindex(lc->max_q); lrc->best_quality = vp9_quantizer_to_qindex(lc->min_q); @@ -777,60 +783,58 @@ int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { // Use Eightap_smooth for low resolutions. if (width * height <= 320 * 240) - cpi->svc.downsample_filter_type[cpi->svc.spatial_layer_id] = - EIGHTTAP_SMOOTH; + svc->downsample_filter_type[svc->spatial_layer_id] = EIGHTTAP_SMOOTH; // For scale factors > 0.75, set the phase to 0 (aligns decimated pixel // to source pixel). - lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id * - cpi->svc.number_temporal_layers + - cpi->svc.temporal_layer_id]; + lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers + + svc->temporal_layer_id]; if (lc->scaling_factor_num > (3 * lc->scaling_factor_den) >> 2) - cpi->svc.downsample_filter_phase[cpi->svc.spatial_layer_id] = 0; + svc->downsample_filter_phase[svc->spatial_layer_id] = 0; // The usage of use_base_mv or partition_reuse assumes down-scale of 2x2. // For now, turn off use of base motion vectors and partition reuse if the // spatial scale factors for any layers are not 2, // keep the case of 3 spatial layers with scale factor of 4x4 for base layer. // TODO(marpan): Fix this to allow for use_base_mv for scale factors != 2. - if (cpi->svc.number_spatial_layers > 1) { + if (svc->number_spatial_layers > 1) { int sl; - for (sl = 0; sl < cpi->svc.number_spatial_layers - 1; ++sl) { - lc = &cpi->svc.layer_context[sl * cpi->svc.number_temporal_layers + - cpi->svc.temporal_layer_id]; + for (sl = 0; sl < svc->number_spatial_layers - 1; ++sl) { + lc = &svc->layer_context[sl * svc->number_temporal_layers + + svc->temporal_layer_id]; if ((lc->scaling_factor_num != lc->scaling_factor_den >> 1) && !(lc->scaling_factor_num == lc->scaling_factor_den >> 2 && sl == 0 && - cpi->svc.number_spatial_layers == 3)) { - cpi->svc.use_base_mv = 0; - cpi->svc.use_partition_reuse = 0; + svc->number_spatial_layers == 3)) { + svc->use_base_mv = 0; + svc->use_partition_reuse = 0; break; } } // For non-zero spatial layers: if the previous spatial layer was dropped // disable the base_mv and partition_reuse features. - if (cpi->svc.spatial_layer_id > 0 && - cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) { - cpi->svc.use_base_mv = 0; - cpi->svc.use_partition_reuse = 0; + if (svc->spatial_layer_id > 0 && + svc->drop_spatial_layer[svc->spatial_layer_id - 1]) { + svc->use_base_mv = 0; + svc->use_partition_reuse = 0; } } - cpi->svc.non_reference_frame = 0; + svc->non_reference_frame = 0; if (cpi->common.frame_type != KEY_FRAME && !cpi->ext_refresh_last_frame && !cpi->ext_refresh_golden_frame && !cpi->ext_refresh_alt_ref_frame) { - cpi->svc.non_reference_frame = 1; + svc->non_reference_frame = 1; } - if (cpi->svc.spatial_layer_id == 0) cpi->svc.high_source_sad_superframe = 0; + if (svc->spatial_layer_id == 0) svc->high_source_sad_superframe = 0; - if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS && - cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] && - cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] != -1 && - !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) { + if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS && + svc->last_layer_dropped[svc->spatial_layer_id] && + svc->fb_idx_upd_tl0[svc->spatial_layer_id] != -1 && + !svc->layer_context[svc->temporal_layer_id].is_key_frame) { // For fixed/non-flexible mode, if the previous frame (same spatial layer // from previous superframe) was dropped, make sure the lst_fb_idx // for this frame corresponds to the buffer index updated on (last) encoded // TL0 frame (with same spatial layer). - cpi->lst_fb_idx = cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id]; + cpi->lst_fb_idx = svc->fb_idx_upd_tl0[svc->spatial_layer_id]; } if (vp9_set_size_literal(cpi, width, height) != 0) diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index f1a1df936..c766c2016 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -32,6 +32,11 @@ typedef enum { INTER_LAYER_PRED_ON_CONSTRAINED } INTER_LAYER_PRED; +typedef struct BUFFER_LONGTERM_REF { + int idx; + int is_used; +} BUFFER_LONGTERM_REF; + typedef struct { RATE_CONTROL rc; int target_bandwidth; @@ -101,7 +106,7 @@ typedef struct SVC { int use_longterm_ref; // Frame level flag to enable second (long term) temporal reference. int use_longterm_ref_current_layer; - int buffer_idx_longterm_ref; + BUFFER_LONGTERM_REF buffer_longterm_ref; int current_superframe; int non_reference_frame; int use_base_mv; -- 2.40.0