ref: f444e5743d7e156fea9db796c40759f45d20e9dd
parent: 60e1a1befc7532116897a630d5bc8b4c729d012e
parent: 9cf725a4f482344d137247a9d09d7a499bbc80bf
author: Marco Paniconi <marpan@google.com>
date: Fri Apr 27 00:55:22 EDT 2018
Merge "VP9 SVC: Add new level to constrain inter-layer pred."
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -3732,28 +3732,9 @@
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.
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -825,3 +825,63 @@
}
}
}
+
+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);
+ }
+ }
+ }
+}
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -20,9 +20,16 @@
#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 {
@@ -187,6 +194,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"