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:
@@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user