Extend encoder control for refreshing buffer slots.
Extend the existing control to allow for refreshing any of the
allowed buffer slots (the current AOM_EFLAGS_UPD_# flags only
allow for updating 3 buffers (last/golden/altref)). So this
change removes the need to set the AOM_EFLAG_NO_UPD_# encoder flags,
and allows user to also update any reference.
This allows for greater flexibility for RTC applications to
configure SVC/layered structures.
Change-Id: I38fc957943d968636df9434071da82db335a2c30
diff --git a/aom/aomcx.h b/aom/aomcx.h
index 59dbe02..91f0eb3 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -18,6 +18,7 @@
*/
#include "aom/aom.h"
#include "aom/aom_encoder.h"
+#include "av1/common/enums.h"
/*!\file
* \brief Provides definitions for using AOM or AV1 encoder algorithm within the
@@ -1127,9 +1128,10 @@
*/
AV1E_SET_SVC_PARAMS = 151,
- /*!\brief Codec control function to set SVC reference frame map.
+ /*!\brief Codec control function to set reference frame config:
+ * the ref_idx and the refresh flags for each buffer slot.
*/
- AV1E_SET_SVC_REF_IDX = 152
+ AV1E_SET_SVC_REF_FRAME_CONFIG = 152
};
/*!\brief aom 1-D scaling mode
@@ -1243,10 +1245,14 @@
int framerate_factor[AOM_MAX_TS_LAYERS];
} aom_svc_params_t;
-/*!brief Parameter type for SVC */
-typedef struct aom_svc_ref_idx {
- int ref_idx[8]; /**< Reference buffer slot */
-} aom_svc_ref_idx_t;
+/*!brief Parameters for setting ref frame config */
+typedef struct aom_svc_ref_frame_config {
+ // 7 references: LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2),
+ // GOLDEN_FRAME(3), BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
+ /*! Buffer slot index for each of 7 references. */
+ int ref_idx[INTER_REFS_PER_FRAME];
+ int refresh[REF_FRAMES]; /**< Refresh flag for each of the 8 slots. */
+} aom_svc_ref_frame_config_t;
/*!\cond */
/*!\brief Encoder control function parameter type
@@ -1592,8 +1598,8 @@
AOM_CTRL_USE_TYPE(AV1E_SET_SVC_PARAMS, aom_svc_params_t *)
#define AOME_CTRL_AV1E_SET_SVC_PARAMS
-AOM_CTRL_USE_TYPE(AV1E_SET_SVC_REF_IDX, aom_svc_ref_idx_t *)
-#define AOME_CTRL_AV1E_SET_SVC_REF_IDX
+AOM_CTRL_USE_TYPE(AV1E_SET_SVC_REF_FRAME_CONFIG, aom_svc_ref_frame_config_t *)
+#define AOME_CTRL_AV1E_SET_SVC_REF_FRAME_CONFIG
/*!\endcond */
/*! @} - end defgroup aom_encoder */
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index aa7b399..59a6d46 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -2182,13 +2182,16 @@
return AOM_CODEC_OK;
}
-static aom_codec_err_t ctrl_set_svc_ref_idx(aom_codec_alg_priv_t *ctx,
- va_list args) {
+static aom_codec_err_t ctrl_set_svc_ref_frame_config(aom_codec_alg_priv_t *ctx,
+ va_list args) {
AV1_COMP *const cpi = ctx->cpi;
- aom_svc_ref_idx_t *const data = va_arg(args, aom_svc_ref_idx_t *);
- cpi->svc.apply_external_ref_idx = 1;
+ aom_svc_ref_frame_config_t *const data =
+ va_arg(args, aom_svc_ref_frame_config_t *);
+ cpi->svc.external_ref_frame_config = 1;
for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; ++i)
cpi->svc.ref_idx[i] = data->ref_idx[i];
+ for (unsigned int i = 0; i < REF_FRAMES; ++i)
+ cpi->svc.refresh[i] = data->refresh[i];
return AOM_CODEC_OK;
}
@@ -2398,7 +2401,7 @@
{ AV1E_SET_MIN_CR, ctrl_set_min_cr },
{ AV1E_SET_SVC_LAYER_ID, ctrl_set_layer_id },
{ AV1E_SET_SVC_PARAMS, ctrl_set_svc_params },
- { AV1E_SET_SVC_REF_IDX, ctrl_set_svc_ref_idx },
+ { AV1E_SET_SVC_REF_FRAME_CONFIG, ctrl_set_svc_ref_frame_config },
// Getters
{ AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer },
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index e139c5b..2ba90a9 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -158,7 +158,9 @@
}
static INLINE int is_frame_droppable(const AV1_COMP *const cpi) {
- if (cpi->ext_refresh_frame_flags_pending)
+ if (cpi->svc.external_ref_frame_config)
+ return cpi->svc.non_reference_frame;
+ else if (cpi->ext_refresh_frame_flags_pending)
return !(cpi->ext_refresh_alt_ref_frame ||
cpi->ext_refresh_alt2_ref_frame ||
cpi->ext_refresh_bwd_ref_frame || cpi->ext_refresh_golden_frame ||
@@ -900,6 +902,13 @@
int refresh_mask = 0;
if (cpi->ext_refresh_frame_flags_pending) {
+ if (cpi->svc.external_ref_frame_config) {
+ for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) {
+ int ref_frame_map_idx = cpi->svc.ref_idx[i];
+ refresh_mask |= cpi->svc.refresh[i] << ref_frame_map_idx;
+ }
+ return refresh_mask;
+ }
// Unfortunately the encoder interface reflects the old refresh_*_frame
// flags so we have to replicate the old refresh_frame_flags logic here in
// order to preserve the behaviour of the flag overrides.
@@ -1363,7 +1372,7 @@
if (oxcf->pass == 0 || oxcf->pass == 2) {
if (!cpi->ext_refresh_frame_flags_pending) {
av1_get_ref_frames(cpi, &cpi->ref_buffer_stack);
- } else if (cpi->svc.apply_external_ref_idx) {
+ } else if (cpi->svc.external_ref_frame_config) {
for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++)
cm->remapped_ref_idx[i] = cpi->svc.ref_idx[i];
}
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 20368d8..ab30db7 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1191,7 +1191,8 @@
cpi->td.counts = &cpi->counts;
cpi->use_svc = 0;
- cpi->svc.apply_external_ref_idx = 0;
+ cpi->svc.external_ref_frame_config = 0;
+ cpi->svc.non_reference_frame = 0;
cm->number_spatial_layers = 1;
cm->number_temporal_layers = 1;
@@ -2588,7 +2589,8 @@
set_tile_info(cpi);
- cpi->ext_refresh_frame_flags_pending = 0;
+ if (!cpi->svc.external_ref_frame_config)
+ cpi->ext_refresh_frame_flags_pending = 0;
cpi->ext_refresh_frame_context_pending = 0;
highbd_set_var_fns(cpi);
@@ -6163,6 +6165,22 @@
return AOM_CODEC_OK;
}
+static void svc_set_updates_external_ref_frame_config(AV1_COMP *cpi) {
+ cpi->ext_refresh_frame_flags_pending = 1;
+ cpi->ext_refresh_last_frame = cpi->svc.refresh[cpi->svc.ref_idx[0]];
+ cpi->ext_refresh_golden_frame = cpi->svc.refresh[cpi->svc.ref_idx[3]];
+ cpi->ext_refresh_bwd_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[4]];
+ cpi->ext_refresh_alt2_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[5]];
+ cpi->ext_refresh_alt_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[6]];
+ cpi->svc.non_reference_frame = 1;
+ for (int i = 0; i < REF_FRAMES; i++) {
+ if (cpi->svc.refresh[i] == 1) {
+ cpi->svc.non_reference_frame = 0;
+ break;
+ }
+ }
+}
+
void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) {
// TODO(yunqingwang): For what references to use, external encoding flags
// should be consistent with internal reference frame selection. Need to
@@ -6220,7 +6238,10 @@
cpi->ext_refresh_alt2_ref_frame = (upd & AOM_ALT2_FLAG) != 0;
cpi->ext_refresh_frame_flags_pending = 1;
} else {
- cpi->ext_refresh_frame_flags_pending = 0;
+ if (cpi->svc.external_ref_frame_config)
+ svc_set_updates_external_ref_frame_config(cpi);
+ else
+ cpi->ext_refresh_frame_flags_pending = 0;
}
cpi->ext_use_ref_frame_mvs = cpi->oxcf.allow_ref_frame_mvs &
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 514d536..ecc1b8d 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -175,10 +175,12 @@
} LAYER_CONTEXT;
typedef struct SVC {
- int apply_external_ref_idx;
+ int external_ref_frame_config;
+ int non_reference_frame;
// Layer context used for rate control in one pass temporal CBR mode.
LAYER_CONTEXT layer_context[AOM_MAX_LAYERS];
int ref_idx[INTER_REFS_PER_FRAME];
+ int refresh[REF_FRAMES];
} SVC;
#define MAX_LENGTH_TPL_FRAME_STATS (27 + 9)
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index ae144c2..62ff8a0 100644
--- a/examples/svc_encoder_rtc.c
+++ b/examples/svc_encoder_rtc.c
@@ -238,16 +238,16 @@
// Layer pattern configuration.
static int set_layer_pattern(int layering_mode, int frame_cnt,
aom_svc_layer_id_t *layer_id,
- aom_svc_ref_idx_t *svc_ref_idx) {
+ aom_svc_ref_frame_config_t *ref_frame_config) {
int i;
// No spatial layers in this test.
layer_id->spatial_layer_id = 0;
- // Set the referende map buffer idx for the 6 references:
+ // Set the referende map buffer idx for the 7 references:
// LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
// BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
- for (i = 0; i < INTER_REFS_PER_FRAME; i++)
- svc_ref_idx->ref_idx[i] = (i < 3) ? 0 : i - 2;
- // We only use LAST and GF for prediction in RTC mode.
+ for (i = 0; i < INTER_REFS_PER_FRAME; i++) ref_frame_config->ref_idx[i] = i;
+ for (i = 0; i < REF_FRAMES; i++) ref_frame_config->refresh[i] = 0;
+ // Note only use LAST and GF for prediction in non-rd mode (speed 8).
int layer_flags = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
AOM_EFLAG_NO_REF_ARF2;
@@ -255,7 +255,7 @@
case 0:
// 1-layer: update LAST on every frame, reference LAST and GF.
layer_id->temporal_layer_id = 0;
- layer_flags |= AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
+ ref_frame_config->refresh[0] = 1;
break;
case 1:
// 2-layer.
@@ -264,12 +264,11 @@
if (frame_cnt % 2 == 0) {
layer_id->temporal_layer_id = 0;
// Update LAST on layer 0, reference LAST and GF.
- layer_flags |= AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
+ ref_frame_config->refresh[0] = 1;
} else {
layer_id->temporal_layer_id = 1;
// No updates on layer 1, only reference LAST (TL0).
- layer_flags |= AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
- AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
}
break;
case 2:
@@ -281,27 +280,24 @@
// Base layer.
layer_id->temporal_layer_id = 0;
// Update LAST on layer 0, reference LAST and GF.
- layer_flags |= AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
+ ref_frame_config->refresh[0] = 1;
} else if ((frame_cnt - 1) % 4 == 0) {
layer_id->temporal_layer_id = 2;
// First top layer: no updates, only reference LAST (TL0).
- layer_flags |= AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
- AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
} else if ((frame_cnt - 2) % 4 == 0) {
layer_id->temporal_layer_id = 1;
- // Middle layer (TL1): update ARF, only reference LAST (TL0).
- // Updating ARF corresponds to buffer slot 6.
- layer_flags |=
- AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_REF_GF;
+ // Middle layer (TL1): update LAST2, only reference LAST (TL0).
+ ref_frame_config->refresh[1] = 1;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
} else if ((frame_cnt - 3) % 4 == 0) {
layer_id->temporal_layer_id = 2;
// Second top layer: no updates, only reference LAST.
- // Set buffer idx for LAST to slot 6, since that was the slot
- // updated in previous frame. So LAST is TL1.
- layer_flags |= AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
- AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
- svc_ref_idx->ref_idx[0] = 4;
- svc_ref_idx->ref_idx[4] = 0;
+ // Set buffer idx for LAST to slot 1, since that was the slot
+ // updated in previous frame. So LAST is TL1 frame.
+ ref_frame_config->ref_idx[0] = 1;
+ ref_frame_config->ref_idx[1] = 0;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
}
break;
default: assert(0); die("Error: Unsupported temporal layering mode!\n");
@@ -329,7 +325,7 @@
int layering_mode = 0;
aom_svc_layer_id_t layer_id;
aom_svc_params_t svc_params;
- aom_svc_ref_idx_t svc_ref_idx;
+ aom_svc_ref_frame_config_t ref_frame_config;
const AvxInterface *encoder = NULL;
struct AvxInputContext input_ctx;
struct RateControlMetrics rc;
@@ -525,10 +521,10 @@
// Set the reference/update flags, layer_id, and reference_map
// buffer index.
- flags =
- set_layer_pattern(layering_mode, frame_cnt, &layer_id, &svc_ref_idx);
+ flags = set_layer_pattern(layering_mode, frame_cnt, &layer_id,
+ &ref_frame_config);
aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id);
- aom_codec_control(&codec, AV1E_SET_SVC_REF_IDX, &svc_ref_idx);
+ aom_codec_control(&codec, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config);
frame_avail = read_frame(&input_ctx, &raw);
if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id];