From eb53c69ece6b97f65afed81fd4c2ef9624501ea7 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 8 Sep 2015 08:47:42 -0700 Subject: [PATCH] Add cyclic refresh parameters to svc-layer context. For 1 pass CBR spatial-SVC: Add cyclic refresh parameters to the svc-layer context. This allows cyclic refresh (aq-mode=3) to be applied to the whole super-frame (all spatial layers). This gives a performance improvement for spatial layer encoding. Addd the aq_mode mode on/off setting as command line option. Change-Id: Ib9c3b5ba3cb7851bfb8c37d4f911664bef38e165 --- examples/vp9_spatial_svc_encoder.c | 8 +++-- vp9/encoder/vp9_aq_cyclicrefresh.c | 9 ++++-- vp9/encoder/vp9_encoder.c | 2 ++ vp9/encoder/vp9_ratectrl.c | 3 +- vp9/encoder/vp9_svc_layercontext.c | 66 ++++++++++++++++++++++++++++++++++++++ vp9/encoder/vp9_svc_layercontext.h | 6 ++++ vpx/svc_context.h | 1 + 7 files changed, 88 insertions(+), 7 deletions(-) diff --git a/examples/vp9_spatial_svc_encoder.c b/examples/vp9_spatial_svc_encoder.c index af8aa86..9f41911 100644 --- a/examples/vp9_spatial_svc_encoder.c +++ b/examples/vp9_spatial_svc_encoder.c @@ -80,6 +80,8 @@ static const arg_def_t rc_end_usage_arg = ARG_DEF(NULL, "rc-end-usage", 1, "0 - 3: VBR, CBR, CQ, Q"); static const arg_def_t speed_arg = ARG_DEF("sp", "speed", 1, "speed configuration"); +static const arg_def_t aqmode_arg = + ARG_DEF("aq", "aqmode", 1, "aq-mode off/on"); #if CONFIG_VP9_HIGHBITDEPTH static const struct arg_enum_list bitdepth_enum[] = { @@ -101,7 +103,7 @@ static const arg_def_t *svc_args[] = { &kf_dist_arg, &scale_factors_arg, &passes_arg, &pass_arg, &fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg, &max_bitrate_arg, &temporal_layers_arg, &temporal_layering_mode_arg, - &lag_in_frame_arg, &threads_arg, + &lag_in_frame_arg, &threads_arg, &aqmode_arg, #if OUTPUT_RC_STATS &output_rc_stats_arg, #endif @@ -221,6 +223,8 @@ static void parse_command_line(int argc, const char **argv_, #endif } else if (arg_match(&arg, &speed_arg, argi)) { svc_ctx->speed = arg_parse_uint(&arg); + } else if (arg_match(&arg, &aqmode_arg, argi)) { + svc_ctx->aqmode = arg_parse_uint(&arg); } else if (arg_match(&arg, &threads_arg, argi)) { svc_ctx->threads = arg_parse_uint(&arg); } else if (arg_match(&arg, &temporal_layering_mode_arg, argi)) { @@ -635,7 +639,7 @@ int main(int argc, const char **argv) { vpx_codec_control(&codec, VP8E_SET_CPUUSED, svc_ctx.speed); if (svc_ctx.threads) vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (svc_ctx.threads >> 1)); - if (svc_ctx.speed >= 5) + if (svc_ctx.speed >= 5 && svc_ctx.aqmode == 1) vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3); diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.c b/vp9/encoder/vp9_aq_cyclicrefresh.c index 625c3d0..e17b397 100644 --- a/vp9/encoder/vp9_aq_cyclicrefresh.c +++ b/vp9/encoder/vp9_aq_cyclicrefresh.c @@ -449,6 +449,10 @@ void vp9_cyclic_refresh_update_parameters(VP9_COMP *const cpi) { cr->motion_thresh = 32; cr->rate_boost_fac = 17; } + if (cpi->svc.spatial_layer_id > 0) { + cr->motion_thresh = 4; + cr->rate_boost_fac = 12; + } } // Setup cyclic background refresh: set delta q and segmentation map. @@ -460,11 +464,10 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) { const int apply_cyclic_refresh = apply_cyclic_refresh_bitrate(cm, rc); if (cm->current_video_frame == 0) cr->low_content_avg = 0.0; - // Don't apply refresh on key frame or enhancement layer frames. + // Don't apply refresh on key frame or temporal enhancement layer frames. if (!apply_cyclic_refresh || (cm->frame_type == KEY_FRAME) || - (cpi->svc.temporal_layer_id > 0) || - (cpi->svc.spatial_layer_id > 0)) { + (cpi->svc.temporal_layer_id > 0)) { // Set segmentation map to 0 and disable. unsigned char *const seg_map = cpi->segmentation_map; memset(seg_map, 0, cm->mi_rows * cm->mi_cols); diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 39b4c29..8e83903 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -412,6 +412,8 @@ static void dealloc_compressor_data(VP9_COMP *cpi) { vpx_free_frame_buffer(&cpi->svc.empty_frame.img); memset(&cpi->svc.empty_frame, 0, sizeof(cpi->svc.empty_frame)); + + vp9_free_svc_cyclic_refresh(cpi); } static void save_coding_context(VP9_COMP *cpi) { diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index f7d0ac6..973cde8 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -533,8 +533,7 @@ int vp9_rc_regulate_q(const VP9_COMP *cpi, int target_bits_per_frame, do { if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled && - cpi->svc.temporal_layer_id == 0 && - cpi->svc.spatial_layer_id == 0) { + cpi->svc.temporal_layer_id == 0) { bits_per_mb_at_this_q = (int)vp9_cyclic_refresh_rc_bits_per_mb(cpi, i, correction_factor); } else { diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index a6c5373..89e3133 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -10,6 +10,7 @@ #include +#include "vp9/encoder/vp9_aq_cyclicrefresh.h" #include "vp9/encoder/vp9_encoder.h" #include "vp9/encoder/vp9_svc_layercontext.h" #include "vp9/encoder/vp9_extend.h" @@ -22,6 +23,8 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { SVC *const svc = &cpi->svc; const VP9EncoderConfig *const oxcf = &cpi->oxcf; + int mi_rows = cpi->common.mi_rows; + int mi_cols = cpi->common.mi_cols; int sl, tl; int alt_ref_idx = svc->number_spatial_layers; @@ -52,6 +55,7 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { int layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers); LAYER_CONTEXT *const lc = &svc->layer_context[layer]; RATE_CONTROL *const lrc = &lc->rc; + size_t last_coded_q_map_size; int i; lc->current_video_frame_in_layer = 0; lc->layer_size = 0; @@ -94,6 +98,22 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { lrc->buffer_level = oxcf->starting_buffer_level_ms * lc->target_bandwidth / 1000; lrc->bits_off_target = lrc->buffer_level; + + // Initialize the cyclic refresh parameters. If spatial layers are used + // (i.e., ss_number_layers > 1), these need to be updated per spatial + // layer. + // Cyclic refresh is only applied on base temporal layer. + if (oxcf->ss_number_layers > 1 && + tl == 0) { + lc->sb_index = 0; + lc->map = vpx_malloc(mi_rows * mi_cols * sizeof(signed char)); + memset(lc->map, 0, mi_rows * mi_cols); + last_coded_q_map_size = + mi_rows * mi_cols * sizeof(uint8_t); + lc->last_coded_q_map = vpx_malloc(last_coded_q_map_size); + assert(MAXQ <= 255); + memset(lc->last_coded_q_map, MAXQ, last_coded_q_map_size); + } } } @@ -257,6 +277,21 @@ void vp9_restore_layer_context(VP9_COMP *const cpi) { cpi->rc.frames_since_key = old_frame_since_key; cpi->rc.frames_to_key = old_frame_to_key; } + + // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers, + // for the base temporal layer. + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + cpi->svc.number_spatial_layers > 1 && + cpi->svc.temporal_layer_id == 0) { + CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; + signed char *temp = cr->map; + uint8_t *temp2 = cr->last_coded_q_map; + cr->map = lc->map; + lc->map = temp; + cr->last_coded_q_map = lc->last_coded_q_map; + lc->last_coded_q_map = temp2; + cr->sb_index = lc->sb_index; + } } void vp9_save_layer_context(VP9_COMP *const cpi) { @@ -267,6 +302,21 @@ void vp9_save_layer_context(VP9_COMP *const cpi) { lc->twopass = cpi->twopass; lc->target_bandwidth = (int)oxcf->target_bandwidth; lc->alt_ref_source = cpi->alt_ref_source; + + // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers, + // for the base temporal layer. + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + cpi->svc.number_spatial_layers > 1 && + cpi->svc.temporal_layer_id == 0) { + CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; + signed char *temp = lc->map; + uint8_t *temp2 = lc->last_coded_q_map; + lc->map = cr->map; + cr->map = temp; + lc->last_coded_q_map = cr->last_coded_q_map; + cr->last_coded_q_map = temp2; + lc->sb_index = cr->sb_index; + } } void vp9_init_second_pass_spatial_svc(VP9_COMP *cpi) { @@ -642,3 +692,19 @@ struct lookahead_entry *vp9_svc_lookahead_pop(VP9_COMP *const cpi, } return buf; } + +void vp9_free_svc_cyclic_refresh(VP9_COMP *const cpi) { + int sl, tl; + SVC *const svc = &cpi->svc; + const VP9EncoderConfig *const oxcf = &cpi->oxcf; + for (sl = 0; sl < oxcf->ss_number_layers; ++sl) { + for (tl = 0; tl < oxcf->ts_number_layers; ++tl) { + int layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers); + LAYER_CONTEXT *const lc = &svc->layer_context[layer]; + if (lc->map) + vpx_free(lc->map); + if (lc->last_coded_q_map) + vpx_free(lc->last_coded_q_map); + } + } +} diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index b6a5ea5..168edbf 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -41,6 +41,10 @@ typedef struct { int has_alt_frame; size_t layer_size; struct vpx_psnr_pkt psnr_pkt; + // Cyclic refresh parameters (aq-mode=3), that need to be updated per-frame. + int sb_index; + signed char *map; + uint8_t *last_coded_q_map; } LAYER_CONTEXT; typedef struct { @@ -115,6 +119,8 @@ int vp9_svc_start_frame(struct VP9_COMP *const cpi); int vp9_one_pass_cbr_svc_start_layer(struct VP9_COMP *const cpi); +void vp9_free_svc_cyclic_refresh(struct VP9_COMP *const cpi); + #ifdef __cplusplus } // extern "C" #endif diff --git a/vpx/svc_context.h b/vpx/svc_context.h index a09651c..432c3c7 100644 --- a/vpx/svc_context.h +++ b/vpx/svc_context.h @@ -40,6 +40,7 @@ typedef struct { int output_rc_stat; // for outputting rc stats int speed; // speed setting for codec int threads; + int aqmode; // turns on aq-mdoe=3 (cyclic_refresh): 0=off, 1=on. // private storage for vpx_svc_encode void *internal; } SvcContext; -- 2.7.4