diff options
author | Marco Paniconi <marpan@google.com> | 2015-09-17 22:29:07 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-09-17 22:29:07 +0000 |
commit | e12ec3615c0a94ec03d62154bc5d8c2199e4e6ff (patch) | |
tree | bdafc1225aa5a93e78a1056c8eac99b94b3c30cd | |
parent | 9d8decc16274b4c2ed1b7c0636b7666a1c57f3d0 (diff) | |
parent | 730cdefd3ec5cf196b3ef95c63c99c86fdf22f7a (diff) | |
download | libvpx-e12ec3615c0a94ec03d62154bc5d8c2199e4e6ff.tar libvpx-e12ec3615c0a94ec03d62154bc5d8c2199e4e6ff.tar.gz libvpx-e12ec3615c0a94ec03d62154bc5d8c2199e4e6ff.tar.bz2 libvpx-e12ec3615c0a94ec03d62154bc5d8c2199e4e6ff.zip |
Merge "Add SVC codec control to set frame flags and buffer indices."
-rw-r--r-- | examples/vp9_spatial_svc_encoder.c | 78 | ||||
-rw-r--r-- | vp9/encoder/vp9_svc_layercontext.c | 22 | ||||
-rw-r--r-- | vp9/encoder/vp9_svc_layercontext.h | 6 | ||||
-rw-r--r-- | vp9/vp9_cx_iface.c | 15 | ||||
-rw-r--r-- | vpx/src/svc_encodeframe.c | 6 | ||||
-rw-r--r-- | vpx/vp8cx.h | 25 |
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" |