unsigned int tile_rows;
unsigned int arnr_max_frames;
unsigned int arnr_strength;
+ unsigned int min_gf_interval;
+ unsigned int max_gf_interval;
vp8e_tuning tuning;
unsigned int cq_level; // constrained quality level
unsigned int rc_max_intra_bitrate_pct;
vpx_bit_depth_t bit_depth;
vp9e_tune_content content;
vpx_color_space_t color_space;
+ int color_range;
};
static struct vp9_extracfg default_extra_cfg = {
0, // tile_rows
7, // arnr_max_frames
5, // arnr_strength
+ 0, // min_gf_interval; 0 -> default decision
+ 0, // max_gf_interval; 0 -> default decision
VP8_TUNE_PSNR, // tuning
10, // cq_level
0, // rc_max_intra_bitrate_pct
VPX_BITS_8, // Bit depth
VP9E_CONTENT_DEFAULT, // content
VPX_CS_UNKNOWN, // color space
+ 0, // color range
};
struct vpx_codec_alg_priv {
RANGE_CHECK_HI(cfg, rc_resize_up_thresh, 100);
RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_LAST_PASS);
+ RANGE_CHECK(extra_cfg, min_gf_interval, 0, (MAX_LAG_BUFFERS - 1));
+ RANGE_CHECK(extra_cfg, max_gf_interval, 0, (MAX_LAG_BUFFERS - 1));
+ if (extra_cfg->max_gf_interval > 0) {
+ RANGE_CHECK(extra_cfg, max_gf_interval, 2, (MAX_LAG_BUFFERS - 1));
+ }
+ if (extra_cfg->min_gf_interval > 0 && extra_cfg->max_gf_interval > 0) {
+ RANGE_CHECK(extra_cfg, max_gf_interval, extra_cfg->min_gf_interval,
+ (MAX_LAG_BUFFERS - 1));
+ }
if (cfg->rc_resize_allowed == 1) {
RANGE_CHECK(cfg, rc_scaled_width, 0, cfg->g_w);
RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
+ if (cfg->ss_number_layers * cfg->ts_number_layers > VPX_MAX_LAYERS)
+ ERROR("ss_number_layers * ts_number_layers is out of range");
if (cfg->ts_number_layers > 1) {
- unsigned int i;
- for (i = 1; i < cfg->ts_number_layers; ++i)
- if (cfg->ts_target_bitrate[i] < cfg->ts_target_bitrate[i - 1])
+ unsigned int sl, tl;
+ for (sl = 1; sl < cfg->ss_number_layers; ++sl) {
+ for (tl = 1; tl < cfg->ts_number_layers; ++tl) {
+ const int layer =
+ LAYER_IDS_TO_IDX(sl, tl, cfg->ts_number_layers);
+ if (cfg->layer_target_bitrate[layer] <
+ cfg->layer_target_bitrate[layer - 1])
ERROR("ts_target_bitrate entries are not increasing");
+ }
+ }
RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers - 1], 1, 1);
- for (i = cfg->ts_number_layers - 2; i > 0; --i)
- if (cfg->ts_rate_decimator[i - 1] != 2 * cfg->ts_rate_decimator[i])
+ for (tl = cfg->ts_number_layers - 2; tl > 0; --tl)
+ if (cfg->ts_rate_decimator[tl - 1] != 2 * cfg->ts_rate_decimator[tl])
ERROR("ts_rate_decimator factors are not powers of 2");
}
ERROR("Codec bit-depth 8 not supported in profile > 1");
}
RANGE_CHECK(extra_cfg, color_space, VPX_CS_UNKNOWN, VPX_CS_SRGB);
+ RANGE_CHECK(extra_cfg, color_range, 0, 2);
return VPX_CODEC_OK;
}
const vpx_codec_enc_cfg_t *cfg,
const struct vp9_extracfg *extra_cfg) {
const int is_vbr = cfg->rc_end_usage == VPX_VBR;
+ int sl, tl;
oxcf->profile = cfg->g_profile;
oxcf->max_threads = (int)cfg->g_threads;
oxcf->width = cfg->g_w;
#endif
oxcf->color_space = extra_cfg->color_space;
+ oxcf->color_range = extra_cfg->color_range;
oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
oxcf->arnr_strength = extra_cfg->arnr_strength;
+ oxcf->min_gf_interval = extra_cfg->min_gf_interval;
+ oxcf->max_gf_interval = extra_cfg->max_gf_interval;
oxcf->tuning = extra_cfg->tuning;
oxcf->content = extra_cfg->content;
oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost;
oxcf->ss_number_layers = cfg->ss_number_layers;
+ oxcf->ts_number_layers = cfg->ts_number_layers;
+ oxcf->temporal_layering_mode = (enum vp9e_temporal_layering_mode)
+ cfg->temporal_layering_mode;
- if (oxcf->ss_number_layers > 1) {
- int i;
- for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
- oxcf->ss_target_bitrate[i] = 1000 * cfg->ss_target_bitrate[i];
+ for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
#if CONFIG_SPATIAL_SVC
- oxcf->ss_enable_auto_arf[i] = cfg->ss_enable_auto_alt_ref[i];
+ oxcf->ss_enable_auto_arf[sl] = cfg->ss_enable_auto_alt_ref[sl];
#endif
+ for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
+ oxcf->layer_target_bitrate[sl * oxcf->ts_number_layers + tl] =
+ 1000 * cfg->layer_target_bitrate[sl * oxcf->ts_number_layers + tl];
}
- } else if (oxcf->ss_number_layers == 1) {
+ }
+ if (oxcf->ss_number_layers == 1 && oxcf->pass != 0) {
oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
#if CONFIG_SPATIAL_SVC
oxcf->ss_enable_auto_arf[0] = extra_cfg->enable_auto_alt_ref;
#endif
}
-
- oxcf->ts_number_layers = cfg->ts_number_layers;
-
if (oxcf->ts_number_layers > 1) {
- int i;
- for (i = 0; i < VPX_TS_MAX_LAYERS; ++i) {
- oxcf->ts_target_bitrate[i] = 1000 * cfg->ts_target_bitrate[i];
- oxcf->ts_rate_decimator[i] = cfg->ts_rate_decimator[i];
+ for (tl = 0; tl < VPX_TS_MAX_LAYERS; ++tl) {
+ oxcf->ts_rate_decimator[tl] = cfg->ts_rate_decimator[tl] ?
+ cfg->ts_rate_decimator[tl] : 1;
}
} else if (oxcf->ts_number_layers == 1) {
- oxcf->ts_target_bitrate[0] = (int)oxcf->target_bandwidth;
oxcf->ts_rate_decimator[0] = 1;
}
-
/*
printf("Current VP9 Settings: \n");
printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
return update_extra_cfg(ctx, &extra_cfg);
}
+static vpx_codec_err_t ctrl_set_min_gf_interval(vpx_codec_alg_priv_t *ctx,
+ va_list args) {
+ struct vp9_extracfg extra_cfg = ctx->extra_cfg;
+ extra_cfg.min_gf_interval = CAST(VP9E_SET_MIN_GF_INTERVAL, args);
+ return update_extra_cfg(ctx, &extra_cfg);
+}
+
+static vpx_codec_err_t ctrl_set_max_gf_interval(vpx_codec_alg_priv_t *ctx,
+ va_list args) {
+ struct vp9_extracfg extra_cfg = ctx->extra_cfg;
+ extra_cfg.max_gf_interval = CAST(VP9E_SET_MAX_GF_INTERVAL, args);
+ return update_extra_cfg(ctx, &extra_cfg);
+}
+
static vpx_codec_err_t ctrl_set_frame_periodic_boost(vpx_codec_alg_priv_t *ctx,
va_list args) {
struct vp9_extracfg extra_cfg = ctx->extra_cfg;
unsigned int lib_flags) {
vpx_codec_frame_flags_t flags = lib_flags << 16;
- if (lib_flags & FRAMEFLAGS_KEY
-#if CONFIG_SPATIAL_SVC
- || (is_two_pass_svc(cpi) && cpi->svc.layer_context[0].is_key_frame)
-#endif
- )
+ if (lib_flags & FRAMEFLAGS_KEY ||
+ (cpi->use_svc &&
+ cpi->svc.layer_context[cpi->svc.spatial_layer_id *
+ cpi->svc.number_temporal_layers +
+ cpi->svc.temporal_layer_id].is_key_frame)
+ )
flags |= VPX_FRAME_IS_KEY;
if (cpi->droppable)
vpx_codec_cx_pkt_t pkt;
#if CONFIG_SPATIAL_SVC
- if (is_two_pass_svc(cpi))
- cpi->svc.layer_context[cpi->svc.spatial_layer_id].layer_size += size;
+ if (cpi->use_svc)
+ cpi->svc.layer_context[cpi->svc.spatial_layer_id *
+ cpi->svc.number_temporal_layers].layer_size += size;
#endif
// Pack invisible frames with the next visible frame
- if (!cpi->common.show_frame
-#if CONFIG_SPATIAL_SVC
- || (is_two_pass_svc(cpi) &&
- cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
-#endif
+ if (!cpi->common.show_frame ||
+ (cpi->use_svc &&
+ cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
) {
if (ctx->pending_cx_data == 0)
ctx->pending_cx_data = cx_data;
pkt.data.frame.partition_id = -1;
if(ctx->output_cx_pkt_cb.output_cx_pkt)
- ctx->output_cx_pkt_cb.output_cx_pkt(&pkt, ctx->output_cx_pkt_cb.user_priv);
+ ctx->output_cx_pkt_cb.output_cx_pkt(&pkt,
+ ctx->output_cx_pkt_cb.user_priv);
else
vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
cx_data += size;
cx_data_sz -= size;
+#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION)
#if CONFIG_SPATIAL_SVC
- if (is_two_pass_svc(cpi) && !ctx->output_cx_pkt_cb.output_cx_pkt) {
+ if (cpi->use_svc && !ctx->output_cx_pkt_cb.output_cx_pkt) {
vpx_codec_cx_pkt_t pkt_sizes, pkt_psnr;
- int i;
+ int sl;
vp9_zero(pkt_sizes);
vp9_zero(pkt_psnr);
pkt_sizes.kind = VPX_CODEC_SPATIAL_SVC_LAYER_SIZES;
pkt_psnr.kind = VPX_CODEC_SPATIAL_SVC_LAYER_PSNR;
- for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
- LAYER_CONTEXT *lc = &cpi->svc.layer_context[i];
- pkt_sizes.data.layer_sizes[i] = lc->layer_size;
- pkt_psnr.data.layer_psnr[i] = lc->psnr_pkt;
+ for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
+ LAYER_CONTEXT *lc =
+ &cpi->svc.layer_context[sl * cpi->svc.number_temporal_layers];
+ pkt_sizes.data.layer_sizes[sl] = lc->layer_size;
+ pkt_psnr.data.layer_psnr[sl] = lc->psnr_pkt;
lc->layer_size = 0;
}
vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt_psnr);
}
#endif
+#endif
+ if (is_one_pass_cbr_svc(cpi) &&
+ (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1)) {
+ // Encoded all spatial layers; exit loop.
+ break;
+ }
}
}
}
static vpx_codec_err_t ctrl_set_svc(vpx_codec_alg_priv_t *ctx, va_list args) {
int data = va_arg(args, int);
const vpx_codec_enc_cfg_t *cfg = &ctx->cfg;
+ // Both one-pass and two-pass RC are supported now.
+ // User setting this has to make sure of the following.
+ // In two-pass setting: either (but not both)
+ // cfg->ss_number_layers > 1, or cfg->ts_number_layers > 1
+ // In one-pass setting:
+ // either or both cfg->ss_number_layers > 1, or cfg->ts_number_layers > 1
vp9_set_svc(ctx->cpi, data);
- // CBR or two pass mode for SVC with both temporal and spatial layers
- // not yet supported.
+
if (data == 1 &&
- (cfg->rc_end_usage == VPX_CBR ||
- cfg->g_pass == VPX_RC_FIRST_PASS ||
+ (cfg->g_pass == VPX_RC_FIRST_PASS ||
cfg->g_pass == VPX_RC_LAST_PASS) &&
- cfg->ss_number_layers > 1 &&
- cfg->ts_number_layers > 1) {
+ cfg->ss_number_layers > 1 &&
+ cfg->ts_number_layers > 1) {
return VPX_CODEC_INVALID_PARAM;
}
return VPX_CODEC_OK;
VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi;
SVC *const svc = &cpi->svc;
-#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
svc->spatial_layer_id = data->spatial_layer_id;
-#endif
svc->temporal_layer_id = data->temporal_layer_id;
// Checks on valid layer_id input.
if (svc->temporal_layer_id < 0 ||
VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi;
SVC *const svc = &cpi->svc;
-#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
data->spatial_layer_id = svc->spatial_layer_id;
-#endif
data->temporal_layer_id = svc->temporal_layer_id;
return VPX_CODEC_OK;
va_list args) {
VP9_COMP *const cpi = ctx->cpi;
vpx_svc_extra_cfg_t *const params = va_arg(args, vpx_svc_extra_cfg_t *);
- int i;
+ int sl, tl;
+
+ // Number of temporal layers and number of spatial layers have to be set
+ // properly before calling this control function.
+ for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
+ for (tl = 0; tl < cpi->svc.number_temporal_layers; ++tl) {
+ const int layer =
+ LAYER_IDS_TO_IDX(sl, tl, cpi->svc.number_temporal_layers);
+ LAYER_CONTEXT *lc =
+ &cpi->svc.layer_context[layer];
+ lc->max_q = params->max_quantizers[sl];
+ lc->min_q = params->min_quantizers[sl];
+ lc->scaling_factor_num = params->scaling_factor_num[sl];
+ lc->scaling_factor_den = params->scaling_factor_den[sl];
+ }
+ }
- for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
- LAYER_CONTEXT *lc = &cpi->svc.layer_context[i];
+ return VPX_CODEC_OK;
+}
- lc->max_q = params->max_quantizers[i];
- lc->min_q = params->min_quantizers[i];
- lc->scaling_factor_num = params->scaling_factor_num[i];
- lc->scaling_factor_den = params->scaling_factor_den[i];
+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;
}
return update_extra_cfg(ctx, &extra_cfg);
}
+static vpx_codec_err_t ctrl_set_color_range(vpx_codec_alg_priv_t *ctx,
+ va_list args) {
+ struct vp9_extracfg extra_cfg = ctx->extra_cfg;
+ extra_cfg.color_range = CAST(VP9E_SET_COLOR_RANGE, args);
+ return update_extra_cfg(ctx, &extra_cfg);
+}
+
static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{VP8_COPY_REFERENCE, ctrl_copy_reference},
{VP8E_UPD_ENTROPY, ctrl_update_entropy},
{VP9E_SET_AQ_MODE, ctrl_set_aq_mode},
{VP9E_SET_FRAME_PERIODIC_BOOST, ctrl_set_frame_periodic_boost},
{VP9E_SET_SVC, ctrl_set_svc},
-#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
{VP9E_SET_SVC_PARAMETERS, ctrl_set_svc_parameters},
{VP9E_REGISTER_CX_CALLBACK, ctrl_register_cx_callback},
-#endif
{VP9E_SET_SVC_LAYER_ID, ctrl_set_svc_layer_id},
{VP9E_SET_TUNE_CONTENT, ctrl_set_tune_content},
{VP9E_SET_COLOR_SPACE, ctrl_set_color_space},
+ {VP9E_SET_COLOR_RANGE, ctrl_set_color_range},
{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},
{VP8E_GET_LAST_QUANTIZER_64, ctrl_get_quantizer64},
{VP9_GET_REFERENCE, ctrl_get_reference},
-#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
{VP9E_GET_SVC_LAYER_ID, ctrl_get_svc_layer_id},
-#endif
{VP9E_GET_ACTIVEMAP, ctrl_get_active_map},
{ -1, NULL},
{0}, // ts_rate_decimator
0, // ts_periodicity
{0}, // ts_layer_id
+ {0}, // layer_taget_bitrate
+ 0 // temporal_layering_mode
}
},
};