From: Jerome Jiang Date: Wed, 25 Apr 2018 18:33:24 +0000 (-0700) Subject: VP9 SVC: Add new level to constrain inter-layer pred. X-Git-Tag: v1.8.0~719^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9cf725a4f482344d137247a9d09d7a499bbc80bf;p=libvpx VP9 SVC: Add new level to constrain inter-layer pred. Add another level (INTER_LAYER_PRED_ON_CONSTRAINED) to the inter-layer prediction control. This new level enforces the condition that a given spatial layer S can only do inter-layer prediction from the previous spatial layer (S - 1) from the same time/superframe. BUG=webm:1526 Change-Id: I0a1ec95b2c220c7b13a9a425d5fb0a8814c23c70 --- diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 8cabe5723..a936b0759 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -3732,28 +3732,9 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size, suppress_active_map(cpi); // For SVC on non-zero spatial layer: check for disabling inter-layer - // (spatial) prediction, if svc.disable_inter_layer_pred is set. - // if the previous spatial layer was dropped then disable the prediction from - // this (scaled) reference. - if (cpi->use_svc && cpi->svc.spatial_layer_id > 0) { - if ((cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF_NONKEY && - !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) || - cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF || - cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) { - MV_REFERENCE_FRAME ref_frame; - static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG, - VP9_ALT_FLAG }; - for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { - const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame); - if (yv12 != NULL && (cpi->ref_frame_flags & flag_list[ref_frame])) { - const struct scale_factors *const scale_fac = - &cm->frame_refs[ref_frame - 1].sf; - if (vp9_is_scaled(scale_fac)) - cpi->ref_frame_flags &= (~flag_list[ref_frame]); - } - } - } - } + // prediction. + if (cpi->use_svc && cpi->svc.spatial_layer_id > 0) + vp9_svc_constrain_inter_layer_pred(cpi); // Variance adaptive and in frame q adjustment experiments are mutually // exclusive. diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index e4caf9c70..c8196b718 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -825,3 +825,63 @@ void vp9_svc_check_reset_layer_rc_flag(VP9_COMP *const cpi) { } } } + +void vp9_svc_constrain_inter_layer_pred(VP9_COMP *const cpi) { + VP9_COMMON *const cm = &cpi->common; + // Check for disabling inter-layer (spatial) prediction, if + // svc.disable_inter_layer_pred is set. If the previous spatial layer was + // dropped then disable the prediction from this (scaled) reference. + if ((cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF_NONKEY && + !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) || + cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF || + cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) { + MV_REFERENCE_FRAME ref_frame; + static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG, + VP9_ALT_FLAG }; + for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame); + if (yv12 != NULL && (cpi->ref_frame_flags & flag_list[ref_frame])) { + const struct scale_factors *const scale_fac = + &cm->frame_refs[ref_frame - 1].sf; + if (vp9_is_scaled(scale_fac)) + cpi->ref_frame_flags &= (~flag_list[ref_frame]); + } + } + } + // Check for disabling inter-layer prediction if + // INTER_LAYER_PRED_ON_CONSTRAINED is enabled. + // If the reference for inter-layer prediction (the reference that is scaled) + // is not the previous spatial layer from the same superframe, then we + // disable inter-layer prediction. + if (cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_ON_CONSTRAINED) { + // We only use LAST and GOLDEN for prediction in real-time mode, so we + // check both here. + MV_REFERENCE_FRAME ref_frame; + for (ref_frame = LAST_FRAME; ref_frame <= GOLDEN_FRAME; ref_frame++) { + struct scale_factors *scale_fac = &cm->frame_refs[ref_frame - 1].sf; + if (vp9_is_scaled(scale_fac)) { + // If this reference was updated on the previous spatial layer of the + // current superframe, then we keep this reference (don't disable). + // Otherwise we disable the inter-layer prediction. + // This condition is verified by checking if the current frame buffer + // index is equal to any of the slots for the previous spatial layer, + // and if so, check if that slot was updated/refreshed. If that is the + // case, then this reference is valid for inter-layer prediction under + // the mode INTER_LAYER_PRED_ON_CONSTRAINED. + int fb_idx = + ref_frame == LAST_FRAME ? cpi->lst_fb_idx : cpi->gld_fb_idx; + int ref_flag = ref_frame == LAST_FRAME ? VP9_LAST_FLAG : VP9_GOLD_FLAG; + int sl = cpi->svc.spatial_layer_id; + int disable = 1; + if ((fb_idx == cpi->svc.lst_fb_idx[sl - 1] && + cpi->svc.update_last[sl - 1]) || + (fb_idx == cpi->svc.gld_fb_idx[sl - 1] && + cpi->svc.update_golden[sl - 1]) || + (fb_idx == cpi->svc.alt_fb_idx[sl - 1] && + cpi->svc.update_altref[sl - 1])) + disable = 0; + if (disable) cpi->ref_frame_flags &= (~ref_flag); + } + } + } +} diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index 48595302a..fb3127687 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -20,9 +20,16 @@ extern "C" { #endif typedef enum { + // Inter-layer prediction is on on all frames. INTER_LAYER_PRED_ON, + // Inter-layer prediction is off on all frames. INTER_LAYER_PRED_OFF, - INTER_LAYER_PRED_OFF_NONKEY + // Inter-layer prediction is off on non-key frames. + INTER_LAYER_PRED_OFF_NONKEY, + // Inter-layer prediction is on on all frames, but constrained such + // that any layer S (> 0) can only predict from previous spatial + // layer S-1, from the same superframe. + INTER_LAYER_PRED_ON_CONSTRAINED } INTER_LAYER_PRED; typedef struct { @@ -188,6 +195,8 @@ void vp9_svc_reset_key_frame(struct VP9_COMP *const cpi); void vp9_svc_check_reset_layer_rc_flag(struct VP9_COMP *const cpi); +void vp9_svc_constrain_inter_layer_pred(struct VP9_COMP *const cpi); + #ifdef __cplusplus } // extern "C" #endif