ref: eb53c69ece6b97f65afed81fd4c2ef9624501ea7
parent: 0e1b4fb9415818052b98554d35055aef1c1d6204
author: Marco <[email protected]>
date: Tue Sep 8 04:47:42 EDT 2015
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
--- a/examples/vp9_spatial_svc_encoder.c
+++ b/examples/vp9_spatial_svc_encoder.c
@@ -80,6 +80,8 @@
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 @@
&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 @@
#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 @@
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);
--- a/vp9/encoder/vp9_aq_cyclicrefresh.c
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.c
@@ -449,6 +449,10 @@
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 @@
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);
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -412,6 +412,8 @@
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) {
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -533,8 +533,7 @@
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 {
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -10,6 +10,7 @@
#include <math.h>
+#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 @@
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 @@
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 @@
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 @@
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) {
@@ -641,4 +691,20 @@
}
}
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);
+ }
+ }
}
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -41,6 +41,10 @@
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 {
@@ -114,6 +118,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"
--- a/vpx/svc_context.h
+++ b/vpx/svc_context.h
@@ -40,6 +40,7 @@
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;