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
This commit is contained in:
Marco
2015-09-08 08:47:42 -07:00
parent 0e1b4fb941
commit eb53c69ece
7 changed files with 88 additions and 7 deletions

View File

@@ -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"); ARG_DEF(NULL, "rc-end-usage", 1, "0 - 3: VBR, CBR, CQ, Q");
static const arg_def_t speed_arg = static const arg_def_t speed_arg =
ARG_DEF("sp", "speed", 1, "speed configuration"); 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 #if CONFIG_VP9_HIGHBITDEPTH
static const struct arg_enum_list bitdepth_enum[] = { 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, &kf_dist_arg, &scale_factors_arg, &passes_arg, &pass_arg,
&fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg, &fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg,
&max_bitrate_arg, &temporal_layers_arg, &temporal_layering_mode_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 #if OUTPUT_RC_STATS
&output_rc_stats_arg, &output_rc_stats_arg,
#endif #endif
@@ -221,6 +223,8 @@ static void parse_command_line(int argc, const char **argv_,
#endif #endif
} else if (arg_match(&arg, &speed_arg, argi)) { } else if (arg_match(&arg, &speed_arg, argi)) {
svc_ctx->speed = arg_parse_uint(&arg); 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)) { } else if (arg_match(&arg, &threads_arg, argi)) {
svc_ctx->threads = arg_parse_uint(&arg); svc_ctx->threads = arg_parse_uint(&arg);
} else if (arg_match(&arg, &temporal_layering_mode_arg, argi)) { } 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); vpx_codec_control(&codec, VP8E_SET_CPUUSED, svc_ctx.speed);
if (svc_ctx.threads) if (svc_ctx.threads)
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (svc_ctx.threads >> 1)); 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); vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);

View File

@@ -449,6 +449,10 @@ void vp9_cyclic_refresh_update_parameters(VP9_COMP *const cpi) {
cr->motion_thresh = 32; cr->motion_thresh = 32;
cr->rate_boost_fac = 17; 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. // 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); const int apply_cyclic_refresh = apply_cyclic_refresh_bitrate(cm, rc);
if (cm->current_video_frame == 0) if (cm->current_video_frame == 0)
cr->low_content_avg = 0.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 || if (!apply_cyclic_refresh ||
(cm->frame_type == KEY_FRAME) || (cm->frame_type == KEY_FRAME) ||
(cpi->svc.temporal_layer_id > 0) || (cpi->svc.temporal_layer_id > 0)) {
(cpi->svc.spatial_layer_id > 0)) {
// Set segmentation map to 0 and disable. // Set segmentation map to 0 and disable.
unsigned char *const seg_map = cpi->segmentation_map; unsigned char *const seg_map = cpi->segmentation_map;
memset(seg_map, 0, cm->mi_rows * cm->mi_cols); memset(seg_map, 0, cm->mi_rows * cm->mi_cols);

View File

@@ -412,6 +412,8 @@ static void dealloc_compressor_data(VP9_COMP *cpi) {
vpx_free_frame_buffer(&cpi->svc.empty_frame.img); vpx_free_frame_buffer(&cpi->svc.empty_frame.img);
memset(&cpi->svc.empty_frame, 0, sizeof(cpi->svc.empty_frame)); 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) { static void save_coding_context(VP9_COMP *cpi) {

View File

@@ -533,8 +533,7 @@ int vp9_rc_regulate_q(const VP9_COMP *cpi, int target_bits_per_frame,
do { do {
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ &&
cm->seg.enabled && cm->seg.enabled &&
cpi->svc.temporal_layer_id == 0 && cpi->svc.temporal_layer_id == 0) {
cpi->svc.spatial_layer_id == 0) {
bits_per_mb_at_this_q = bits_per_mb_at_this_q =
(int)vp9_cyclic_refresh_rc_bits_per_mb(cpi, i, correction_factor); (int)vp9_cyclic_refresh_rc_bits_per_mb(cpi, i, correction_factor);
} else { } else {

View File

@@ -10,6 +10,7 @@
#include <math.h> #include <math.h>
#include "vp9/encoder/vp9_aq_cyclicrefresh.h"
#include "vp9/encoder/vp9_encoder.h" #include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_svc_layercontext.h" #include "vp9/encoder/vp9_svc_layercontext.h"
#include "vp9/encoder/vp9_extend.h" #include "vp9/encoder/vp9_extend.h"
@@ -22,6 +23,8 @@
void vp9_init_layer_context(VP9_COMP *const cpi) { void vp9_init_layer_context(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc; SVC *const svc = &cpi->svc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf; const VP9EncoderConfig *const oxcf = &cpi->oxcf;
int mi_rows = cpi->common.mi_rows;
int mi_cols = cpi->common.mi_cols;
int sl, tl; int sl, tl;
int alt_ref_idx = svc->number_spatial_layers; 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); int layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers);
LAYER_CONTEXT *const lc = &svc->layer_context[layer]; LAYER_CONTEXT *const lc = &svc->layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc; RATE_CONTROL *const lrc = &lc->rc;
size_t last_coded_q_map_size;
int i; int i;
lc->current_video_frame_in_layer = 0; lc->current_video_frame_in_layer = 0;
lc->layer_size = 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 * lrc->buffer_level = oxcf->starting_buffer_level_ms *
lc->target_bandwidth / 1000; lc->target_bandwidth / 1000;
lrc->bits_off_target = lrc->buffer_level; 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_since_key = old_frame_since_key;
cpi->rc.frames_to_key = old_frame_to_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) { 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->twopass = cpi->twopass;
lc->target_bandwidth = (int)oxcf->target_bandwidth; lc->target_bandwidth = (int)oxcf->target_bandwidth;
lc->alt_ref_source = cpi->alt_ref_source; 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) { 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; 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);
}
}
}

View File

@@ -41,6 +41,10 @@ typedef struct {
int has_alt_frame; int has_alt_frame;
size_t layer_size; size_t layer_size;
struct vpx_psnr_pkt psnr_pkt; 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; } LAYER_CONTEXT;
typedef struct { 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); 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 #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@@ -40,6 +40,7 @@ typedef struct {
int output_rc_stat; // for outputting rc stats int output_rc_stat; // for outputting rc stats
int speed; // speed setting for codec int speed; // speed setting for codec
int threads; int threads;
int aqmode; // turns on aq-mdoe=3 (cyclic_refresh): 0=off, 1=on.
// private storage for vpx_svc_encode // private storage for vpx_svc_encode
void *internal; void *internal;
} SvcContext; } SvcContext;