/** * Parse SVC encoding options * Format: encoding-mode=<svc_mode>,layers=<layer_count> * scale-factors=<n1>/<d1>,<n2>/<d2>,... * quantizers=<q1>,<q2>,... * svc_mode = [i|ip|alt_ip|gf] */ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { char *input_string; char *option_name; char *option_value; char *input_ptr = NULL; SvcInternal_t *const si = get_svc_internal(svc_ctx); vpx_codec_err_t res = VPX_CODEC_OK; int i, alt_ref_enabled = 0; if (options == NULL) return VPX_CODEC_OK; input_string = strdup(options); // parse option name option_name = strtok_r(input_string, "=", &input_ptr); while (option_name != NULL) { // parse option value option_value = strtok_r(NULL, " ", &input_ptr); if (option_value == NULL) { svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", option_name); res = VPX_CODEC_INVALID_PARAM; break; } if (strcmp("spatial-layers", option_name) == 0) { svc_ctx->spatial_layers = atoi(option_value); } else if (strcmp("temporal-layers", option_name) == 0) { svc_ctx->temporal_layers = atoi(option_value); } else if (strcmp("scale-factors", option_name) == 0) { res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value, si->svc_params.scaling_factor_num, si->svc_params.scaling_factor_den); if (res != VPX_CODEC_OK) break; } else if (strcmp("max-quantizers", option_name) == 0) { res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, si->svc_params.max_quantizers, NULL); if (res != VPX_CODEC_OK) break; } else if (strcmp("min-quantizers", option_name) == 0) { res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, si->svc_params.min_quantizers, NULL); if (res != VPX_CODEC_OK) break; } else if (strcmp("auto-alt-refs", option_name) == 0) { res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value, si->enable_auto_alt_ref, NULL); if (res != VPX_CODEC_OK) break; } else if (strcmp("bitrates", option_name) == 0) { res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value, si->bitrates, NULL); if (res != VPX_CODEC_OK) break; } else if (strcmp("multi-frame-contexts", option_name) == 0) { si->use_multiple_frame_contexts = atoi(option_value); } else { svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); res = VPX_CODEC_INVALID_PARAM; break; } option_name = strtok_r(NULL, "=", &input_ptr); } free(input_string); for (i = 0; i < svc_ctx->spatial_layers; ++i) { if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER || si->svc_params.max_quantizers[i] < 0 || si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] || si->svc_params.min_quantizers[i] < 0) res = VPX_CODEC_INVALID_PARAM; } if (si->use_multiple_frame_contexts && (svc_ctx->spatial_layers > 3 || svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4)) res = VPX_CODEC_INVALID_PARAM; for (i = 0; i < svc_ctx->spatial_layers; ++i) alt_ref_enabled += si->enable_auto_alt_ref[i]; if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) { svc_log(svc_ctx, SVC_LOG_ERROR, "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could" "enabled auto alt reference frame, but % layers are enabled\n", REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled); res = VPX_CODEC_INVALID_PARAM; } return res; }
vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, vpx_codec_iface_t *iface, vpx_codec_enc_cfg_t *enc_cfg) { vpx_codec_err_t res; int i; SvcInternal *const si = get_svc_internal(svc_ctx); if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL || enc_cfg == NULL) { return VPX_CODEC_INVALID_PARAM; } if (si == NULL) return VPX_CODEC_MEM_ERROR; si->codec_ctx = codec_ctx; si->width = enc_cfg->g_w; si->height = enc_cfg->g_h; if (enc_cfg->kf_max_dist < 2) { svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n", enc_cfg->kf_max_dist); return VPX_CODEC_INVALID_PARAM; } si->kf_dist = enc_cfg->kf_max_dist; if (svc_ctx->spatial_layers == 0) svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; if (svc_ctx->spatial_layers < 1 || svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", svc_ctx->spatial_layers); return VPX_CODEC_INVALID_PARAM; } for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) { si->quantizer[i] = DEFAULT_QUANTIZER_VALUES[i]; si->scaling_factor_num[i] = DEFAULT_SCALE_FACTORS_NUM[i]; si->scaling_factor_den[i] = DEFAULT_SCALE_FACTORS_DEN[i]; } if (strlen(si->quantizers) > 0) { res = parse_layer_options_from_string(svc_ctx, QUANTIZER, si->quantizers, si->quantizer, NULL); if (res != VPX_CODEC_OK) return res; } if (strlen(si->scale_factors) > 0) { res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, si->scale_factors, si->scaling_factor_num, si->scaling_factor_den); if (res != VPX_CODEC_OK) return res; } // Parse aggregate command line options. Options must start with // "layers=xx" then followed by other options res = parse_options(svc_ctx, si->options); if (res != VPX_CODEC_OK) return res; if (svc_ctx->spatial_layers < 1) svc_ctx->spatial_layers = 1; if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS; if (svc_ctx->temporal_layers < 1) svc_ctx->temporal_layers = 1; if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS) svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS; assign_layer_bitrates(svc_ctx, enc_cfg); #if CONFIG_SPATIAL_SVC for (i = 0; i < svc_ctx->spatial_layers; ++i) enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; #endif if (svc_ctx->temporal_layers > 1) { int i; for (i = 0; i < svc_ctx->temporal_layers; ++i) { enc_cfg->ts_target_bitrate[i] = enc_cfg->rc_target_bitrate / svc_ctx->temporal_layers; enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i); } } // modify encoder configuration enc_cfg->ss_number_layers = svc_ctx->spatial_layers; enc_cfg->ts_number_layers = svc_ctx->temporal_layers; if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) enc_cfg->g_error_resilient = 1; // Initialize codec res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); if (res != VPX_CODEC_OK) { svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); return res; } vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); return VPX_CODEC_OK; }