summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco <marpan@chromium.org>2015-09-02 11:34:00 -0700
committerMarco <marpan@chromium.org>2015-09-17 09:37:15 -0700
commit730cdefd3ec5cf196b3ef95c63c99c86fdf22f7a (patch)
treedf97ccc871f0bd8d268d5e2a04b04f23bc4cc4bd
parent50f944272cedc7b150963f5e9492f2ba99244634 (diff)
downloadlibvpx-730cdefd3ec5cf196b3ef95c63c99c86fdf22f7a.tar
libvpx-730cdefd3ec5cf196b3ef95c63c99c86fdf22f7a.tar.gz
libvpx-730cdefd3ec5cf196b3ef95c63c99c86fdf22f7a.tar.bz2
libvpx-730cdefd3ec5cf196b3ef95c63c99c86fdf22f7a.zip
Add SVC codec control to set frame flags and buffer indices.
Add SVC codec control to set the frame flags and buffer indices for each spatial layer of the current (super)frame to be encoded. This allows the application to set (and change on the fly) the reference frame configuration for spatial layers. Added an example layer pattern (spatial and temporal layers) in vp9_spatial_svc_encoder for the bypass_mode using new control. Change-Id: I05f941897cae13fb9275b939d11f93941cb73bee
-rw-r--r--examples/vp9_spatial_svc_encoder.c78
-rw-r--r--vp9/encoder/vp9_svc_layercontext.c22
-rw-r--r--vp9/encoder/vp9_svc_layercontext.h6
-rw-r--r--vp9/vp9_cx_iface.c15
-rw-r--r--vpx/src/svc_encodeframe.c6
-rw-r--r--vpx/vp8cx.h25
6 files changed, 143 insertions, 9 deletions
diff --git a/examples/vp9_spatial_svc_encoder.c b/examples/vp9_spatial_svc_encoder.c
index 9f4191150..b26e98734 100644
--- a/examples/vp9_spatial_svc_encoder.c
+++ b/examples/vp9_spatial_svc_encoder.c
@@ -544,6 +544,59 @@ vpx_codec_err_t parse_superframe_index(const uint8_t *data,
}
#endif
+// Example pattern for spatial layers and 2 temporal layers used in the
+// bypass/flexible mode. The pattern corresponds to the pattern
+// VP9E_TEMPORAL_LAYERING_MODE_0101 (temporal_layering_mode == 2) used in
+// non-flexible mode.
+void set_frame_flags_bypass_mode(int sl, int tl, int num_spatial_layers,
+ int is_key_frame,
+ vpx_svc_ref_frame_config_t *ref_frame_config) {
+ for (sl = 0; sl < num_spatial_layers; ++sl) {
+ if (!tl) {
+ if (!sl) {
+ ref_frame_config->frame_flags[sl] = VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ } else {
+ if (is_key_frame) {
+ ref_frame_config->frame_flags[sl] = VP8_EFLAG_NO_REF_LAST |
+ VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ } else {
+ ref_frame_config->frame_flags[sl] = VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ }
+ }
+ } else if (tl == 1) {
+ if (!sl) {
+ ref_frame_config->frame_flags[sl] = VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_GF;
+ } else {
+ ref_frame_config->frame_flags[sl] = VP8_EFLAG_NO_REF_ARF |
+ VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_GF;
+ }
+ }
+ if (tl == 0) {
+ ref_frame_config->lst_fb_idx[sl] = sl;
+ if (sl)
+ ref_frame_config->gld_fb_idx[sl] = sl - 1;
+ else
+ ref_frame_config->gld_fb_idx[sl] = 0;
+ ref_frame_config->alt_fb_idx[sl] = 0;
+ } else if (tl == 1) {
+ ref_frame_config->lst_fb_idx[sl] = sl;
+ ref_frame_config->gld_fb_idx[sl] = num_spatial_layers + sl - 1;
+ ref_frame_config->alt_fb_idx[sl] = num_spatial_layers + sl;
+ }
+ }
+}
+
int main(int argc, const char **argv) {
AppInput app_input = {0};
VpxVideoWriter *writer = NULL;
@@ -564,6 +617,7 @@ int main(int argc, const char **argv) {
VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS] = {NULL};
struct RateControlStats rc;
vpx_svc_layer_id_t layer_id;
+ vpx_svc_ref_frame_config_t ref_frame_config;
int sl, tl;
double sum_bitrate = 0.0;
double sum_bitrate2 = 0.0;
@@ -653,6 +707,30 @@ int main(int argc, const char **argv) {
end_of_stream = 1;
}
+ // For BYPASS/FLEXIBLE mode, set the frame flags (reference and updates)
+ // and the buffer indices for each spatial layer of the current
+ // (super)frame to be encoded. The temporal layer_id for the current frame
+ // also needs to be set.
+ // TODO(marpan): Should rename the "VP9E_TEMPORAL_LAYERING_MODE_BYPASS"
+ // mode to "VP9E_LAYERING_MODE_BYPASS".
+ if (svc_ctx.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
+ // Example for 2 temporal layers.
+ if (frame_cnt % 2 == 0)
+ layer_id.temporal_layer_id = 0;
+ else
+ layer_id.temporal_layer_id = 1;
+ // Note that we only set the temporal layer_id, since we are calling
+ // the encode for the whole superframe. The encoder will internally loop
+ // over all the spatial layers for the current superframe.
+ vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id);
+ set_frame_flags_bypass_mode(sl, layer_id.temporal_layer_id,
+ svc_ctx.spatial_layers,
+ frame_cnt == 0,
+ &ref_frame_config);
+ vpx_codec_control(&codec, VP9E_SET_SVC_REF_FRAME_CONFIG,
+ &ref_frame_config);
+ }
+
vpx_usec_timer_start(&timer);
res = vpx_svc_encode(&svc_ctx, &codec, (end_of_stream ? NULL : &raw),
pts, frame_duration, svc_ctx.speed >= 5 ?
diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c
index 58d273f5c..64a4ebd7a 100644
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -541,13 +541,21 @@ int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) {
set_flags_and_fb_idx_for_temporal_mode2(cpi);
} else if (cpi->svc.temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
- // VP9E_TEMPORAL_LAYERING_MODE_BYPASS :
- // if the code goes here, it means the encoder will be relying on the
- // flags from outside for layering.
- // However, since when spatial+temporal layering is used, the buffer indices
- // cannot be derived automatically, the bypass mode will only work when the
- // number of spatial layers equals 1.
- assert(cpi->svc.number_spatial_layers == 1);
+ // 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
+ // layering.
+ // Note that the check (cpi->ext_refresh_frame_flags_pending == 0) is
+ // needed to support the case where the frame flags may be passed in via
+ // vpx_codec_encode(), which can be used for the temporal-only svc 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.ext_lst_fb_idx[sl];
+ cpi->gld_fb_idx = cpi->svc.ext_gld_fb_idx[sl];
+ cpi->alt_fb_idx = cpi->svc.ext_alt_fb_idx[sl];
+ }
}
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h
index 168edbf89..ae55c2fd3 100644
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -74,6 +74,12 @@ typedef struct {
// Indicates what sort of temporal layering is used.
// Currently, this only works for CBR mode.
VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode;
+ // Frame flags and buffer indexes for each spatial layer, set by the
+ // application (external settings).
+ int ext_frame_flags[VPX_MAX_LAYERS];
+ int ext_lst_fb_idx[VPX_MAX_LAYERS];
+ int ext_gld_fb_idx[VPX_MAX_LAYERS];
+ int ext_alt_fb_idx[VPX_MAX_LAYERS];
} SVC;
struct VP9_COMP;
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index fd65ed966..aea1a5fc2 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -1416,6 +1416,20 @@ static vpx_codec_err_t ctrl_set_svc_parameters(vpx_codec_alg_priv_t *ctx,
return VPX_CODEC_OK;
}
+static vpx_codec_err_t ctrl_set_svc_ref_frame_config(vpx_codec_alg_priv_t *ctx,
+ va_list args) {
+ VP9_COMP *const cpi = ctx->cpi;
+ vpx_svc_ref_frame_config_t *data = va_arg(args, vpx_svc_ref_frame_config_t *);
+ int sl;
+ for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
+ cpi->svc.ext_frame_flags[sl] = data->frame_flags[sl];
+ cpi->svc.ext_lst_fb_idx[sl] = data->lst_fb_idx[sl];
+ cpi->svc.ext_gld_fb_idx[sl] = data->gld_fb_idx[sl];
+ cpi->svc.ext_alt_fb_idx[sl] = data->alt_fb_idx[sl];
+ }
+ return VPX_CODEC_OK;
+}
+
static vpx_codec_err_t ctrl_register_cx_callback(vpx_codec_alg_priv_t *ctx,
va_list args) {
vpx_codec_priv_output_cx_pkt_cb_pair_t *cbp =
@@ -1487,6 +1501,7 @@ static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{VP9E_SET_NOISE_SENSITIVITY, ctrl_set_noise_sensitivity},
{VP9E_SET_MIN_GF_INTERVAL, ctrl_set_min_gf_interval},
{VP9E_SET_MAX_GF_INTERVAL, ctrl_set_max_gf_interval},
+ {VP9E_SET_SVC_REF_FRAME_CONFIG, ctrl_set_svc_ref_frame_config},
// Getters
{VP8E_GET_LAST_QUANTIZER, ctrl_get_quantizer},
diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c
index 78932d2ff..ff600830e 100644
--- a/vpx/src/svc_encodeframe.c
+++ b/vpx/src/svc_encodeframe.c
@@ -339,7 +339,8 @@ void assign_layer_bitrates(const SvcContext *svc_ctx,
(spatial_layer_target >> 1) + (spatial_layer_target >> 2);
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 2] =
spatial_layer_target;
- } else if (svc_ctx->temporal_layering_mode == 2) {
+ } else if (svc_ctx->temporal_layering_mode == 2 ||
+ svc_ctx->temporal_layering_mode == 1) {
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] =
spatial_layer_target * 2 / 3;
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] =
@@ -417,7 +418,8 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
// si->svc_params.temporal_layering_mode = svc_ctx->temporal_layering_mode;
if (svc_ctx->temporal_layering_mode == 3) {
svc_ctx->temporal_layers = 3;
- } else if (svc_ctx->temporal_layering_mode == 2) {
+ } else if (svc_ctx->temporal_layering_mode == 2 ||
+ svc_ctx->temporal_layering_mode == 1) {
svc_ctx->temporal_layers = 2;
}
diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h
index b7d85d89c..a437ac969 100644
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -556,6 +556,14 @@ enum vp8e_enc_control_id {
* Supported in codecs: VP9
*/
VP9E_SET_COLOR_RANGE,
+
+ /*!\brief Codec control function to set the frame flags and buffer indices
+ * for spatial layers. The frame flags and buffer indices are set using the
+ * struct #vpx_svc_ref_frame_config defined below.
+ *
+ * Supported in codecs: VP9
+ */
+ VP9E_SET_SVC_REF_FRAME_CONFIG,
};
/*!\brief vpx 1-D scaling mode
@@ -682,6 +690,21 @@ typedef struct vpx_svc_layer_id {
int temporal_layer_id; /**< Temporal layer id number. */
} vpx_svc_layer_id_t;
+/*!\brief vp9 svc frame flag parameters.
+ *
+ * This defines the frame flags and buffer indices for each spatial layer for
+ * svc encoding.
+ * This is used with the #VP9E_SET_SVC_REF_FRAME_CONFIG control to set frame
+ * flags and buffer indices for each spatial layer for the current (super)frame.
+ *
+ */
+typedef struct vpx_svc_ref_frame_config {
+ int frame_flags[VPX_TS_MAX_LAYERS]; /**< Frame flags. */
+ int lst_fb_idx[VPX_TS_MAX_LAYERS]; /**< Last buffer index. */
+ int gld_fb_idx[VPX_TS_MAX_LAYERS]; /**< Golden buffer index. */
+ int alt_fb_idx[VPX_TS_MAX_LAYERS]; /**< Altref buffer index. */
+} vpx_svc_ref_frame_config_t;
+
/*!\brief VP8 encoder control function parameter type
*
* Defines the data types that VP8E control functions take. Note that
@@ -773,6 +796,8 @@ VPX_CTRL_USE_TYPE(VP9E_GET_ACTIVEMAP, vpx_active_map_t *)
*/
#define VPX_CTRL_VP9E_SET_COLOR_RANGE
VPX_CTRL_USE_TYPE(VP9E_SET_COLOR_RANGE, int)
+
+VPX_CTRL_USE_TYPE(VP9E_SET_SVC_REF_FRAME_CONFIG, vpx_svc_ref_frame_config_t *)
/*! @} - end defgroup vp8_encoder */
#ifdef __cplusplus
} // extern "C"