Exemplo n.º 1
0
// dump accumulated statistics and reset accumulated values
const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
  int number_of_frames, number_of_keyframes, encode_frame_count;
  int i;
  uint32_t bytes_total = 0;
  SvcInternal *const si = get_svc_internal(svc_ctx);
  if (svc_ctx == NULL || si == NULL) return NULL;

  svc_log_reset(svc_ctx);

  encode_frame_count = si->encode_frame_count;
  if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx);

  svc_log(svc_ctx, SVC_LOG_INFO, "\n");
  number_of_keyframes = encode_frame_count / si->kf_dist + 1;
  for (i = 0; i < si->layers; ++i) {
    number_of_frames = encode_frame_count;

    if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
        (i == 1 || i == 3)) {
      number_of_frames -= number_of_keyframes;
    }
    svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d PSNR=[%2.3f], Bytes=[%u]\n", i,
            (double)si->psnr_in_layer[i] / number_of_frames,
            si->bytes_in_layer[i]);
    bytes_total += si->bytes_in_layer[i];
    si->psnr_in_layer[i] = 0;
    si->bytes_in_layer[i] = 0;
  }

  // only display statistics once
  si->encode_frame_count = 0;

  svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
  return vpx_svc_get_message(svc_ctx);
}
Exemplo n.º 2
0
// dump accumulated statistics and reset accumulated values
const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
  int number_of_frames;
  int i, j;
  uint32_t bytes_total = 0;
  double scale[COMPONENTS];
  double psnr[COMPONENTS];
  double mse[COMPONENTS];
  double y_scale;

  SvcInternal *const si = get_svc_internal(svc_ctx);
  if (svc_ctx == NULL || si == NULL) return NULL;

  svc_log_reset(svc_ctx);

  number_of_frames = si->psnr_pkt_received;
  if (number_of_frames <= 0) return vpx_svc_get_message(svc_ctx);

  svc_log(svc_ctx, SVC_LOG_INFO, "\n");
  for (i = 0; i < svc_ctx->spatial_layers; ++i) {

    svc_log(svc_ctx, SVC_LOG_INFO,
            "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
            i, (double)si->psnr_sum[i][0] / number_of_frames,
            (double)si->psnr_sum[i][1] / number_of_frames,
            (double)si->psnr_sum[i][2] / number_of_frames,
            (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]);
    // the following psnr calculation is deduced from ffmpeg.c#print_report
    y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames;
    scale[1] = y_scale;
    scale[2] = scale[3] = y_scale / 4;  // U or V
    scale[0] = y_scale * 1.5;           // total

    for (j = 0; j < COMPONENTS; j++) {
      psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]);
      mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j];
    }
    svc_log(svc_ctx, SVC_LOG_INFO,
            "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0],
            psnr[1], psnr[2], psnr[3]);
    svc_log(svc_ctx, SVC_LOG_INFO,
            "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0],
            mse[1], mse[2], mse[3]);

    bytes_total += si->bytes_sum[i];
    // clear sums for next time
    si->bytes_sum[i] = 0;
    for (j = 0; j < COMPONENTS; ++j) {
      si->psnr_sum[i][j] = 0;
      si->sse_sum[i][j] = 0;
    }
  }

  // only display statistics once
  si->psnr_pkt_received = 0;

  svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
  return vpx_svc_get_message(svc_ctx);
}
Exemplo n.º 3
0
static void set_svc_parameters(SvcContext *svc_ctx,
                               vpx_codec_ctx_t *codec_ctx) {
  int layer;
  vpx_svc_parameters_t svc_params;
  SvcInternal *const si = get_svc_internal(svc_ctx);

  memset(&svc_params, 0, sizeof(svc_params));
  svc_params.temporal_layer = 0;
  svc_params.spatial_layer = si->layer;

  layer = si->layer;
  if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
                                                   &svc_params.width,
                                                   &svc_params.height)) {
    svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
  }

  if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) {
    svc_params.min_quantizer = si->quantizer[layer];
    svc_params.max_quantizer = si->quantizer[layer];
  } else {
    svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer;
    svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer;
  }

  vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
}
Exemplo n.º 4
0
static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
                                              const char *quantizer_values) {
  char *input_string;
  char *token;
  const char *delim = ",";
  char *save_ptr;
  int found = 0;
  int i, q;
  int res = VPX_CODEC_OK;
  SvcInternal *const si = get_svc_internal(svc_ctx);

  if (quantizer_values == NULL || strlen(quantizer_values) == 0) {
    input_string = strdup(DEFAULT_QUANTIZER_VALUES);
  } else {
    input_string = strdup(quantizer_values);
  }

  token = strtok_r(input_string, delim, &save_ptr);
  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
    if (token != NULL) {
      q = atoi(token);
      if (q <= 0 || q > 100) {
        svc_log(svc_ctx, SVC_LOG_ERROR,
                "svc-quantizer-values: invalid value %s\n", token);
        res = VPX_CODEC_INVALID_PARAM;
        break;
      }
      token = strtok_r(NULL, delim, &save_ptr);
      found = i + 1;
    } else {
      q = 0;
    }
    si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q;
  }
  if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
    svc_log(svc_ctx, SVC_LOG_ERROR,
            "svc: quantizers: %d values required, but only %d specified\n",
            svc_ctx->spatial_layers, found);
    res = VPX_CODEC_INVALID_PARAM;
  }
  free(input_string);
  return res;
}
Exemplo n.º 5
0
static vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx,
                                           const char *scale_factors) {
  char *input_string;
  char *token;
  const char *delim = ",";
  char *save_ptr;
  int found = 0;
  int i;
  int64_t num, den;
  int res = VPX_CODEC_OK;
  SvcInternal *const si = get_svc_internal(svc_ctx);

  if (scale_factors == NULL || strlen(scale_factors) == 0) {
    input_string = strdup(DEFAULT_SCALE_FACTORS);
  } else {
    input_string = strdup(scale_factors);
  }
  token = strtok_r(input_string, delim, &save_ptr);
  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
    num = den = 0;
    if (token != NULL) {
      num = strtol(token, &token, 10);
      if (num <= 0) {
        log_invalid_scale_factor(svc_ctx, token);
        res = VPX_CODEC_INVALID_PARAM;
        break;
      }
      if (*token++ != '/') {
        log_invalid_scale_factor(svc_ctx, token);
        res = VPX_CODEC_INVALID_PARAM;
        break;
      }
      den = strtol(token, &token, 10);
      if (den <= 0) {
        log_invalid_scale_factor(svc_ctx, token);
        res = VPX_CODEC_INVALID_PARAM;
        break;
      }
      token = strtok_r(NULL, delim, &save_ptr);
      found = i + 1;
    }
    si->scaling_factor_num[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
        (int)num;
    si->scaling_factor_den[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
        (int)den;
  }
  if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
    svc_log(svc_ctx, SVC_LOG_ERROR,
            "svc: scale-factors: %d values required, but only %d specified\n",
            svc_ctx->spatial_layers, found);
    res = VPX_CODEC_INVALID_PARAM;
  }
  free(input_string);
  return res;
}
Exemplo n.º 6
0
/**
 * 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;
  int res = VPX_CODEC_OK;

  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("encoding-mode", option_name) == 0) {
      res = set_option_encoding_mode(svc_ctx, option_value);
      if (res != VPX_CODEC_OK) break;
    } else if (strcmp("layers", option_name) == 0) {
      svc_ctx->spatial_layers = atoi(option_value);
    } else if (strcmp("scale-factors", option_name) == 0) {
      res = parse_scale_factors(svc_ctx, option_value);
      if (res != VPX_CODEC_OK) break;
    } else if (strcmp("quantizers", option_name) == 0) {
      res = parse_quantizer_values(svc_ctx, option_value);
      if (res != VPX_CODEC_OK) break;
    } 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);
  return res;
}
Exemplo n.º 7
0
static vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx,
                                                const char *value_str) {
  if (strcmp(value_str, "i") == 0) {
    svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I;
  } else if (strcmp(value_str, "alt-ip") == 0) {
    svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP;
  } else if (strcmp(value_str, "ip") == 0) {
    svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP;
  } else if (strcmp(value_str, "gf") == 0) {
    svc_ctx->encoding_mode = USE_GOLDEN_FRAME;
  } else {
    svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str);
    return VPX_CODEC_INVALID_PARAM;
  }
  return VPX_CODEC_OK;
}
Exemplo n.º 8
0
static vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx,
                                                       LAYER_OPTION_TYPE type,
                                                       const char *input,
                                                       int *option0,
                                                       int *option1) {
  int i;
  vpx_codec_err_t res = VPX_CODEC_OK;
  char *input_string;
  char *token;
  const char *delim = ",";
  char *save_ptr;
  int num_layers = svc_ctx->spatial_layers;
  if (type == BITRATE)
    num_layers = svc_ctx->spatial_layers * svc_ctx->temporal_layers;

  if (input == NULL || option0 == NULL ||
      (option1 == NULL && type == SCALE_FACTOR))
    return VPX_CODEC_INVALID_PARAM;

  input_string = strdup(input);
  token = strtok_r(input_string, delim, &save_ptr);
  for (i = 0; i < num_layers; ++i) {
    if (token != NULL) {
      res = extract_option(type, token, option0 + i, option1 + i);
      if (res != VPX_CODEC_OK) break;
      token = strtok_r(NULL, delim, &save_ptr);
    } else {
      break;
    }
  }
  if (res == VPX_CODEC_OK && i != num_layers) {
    svc_log(svc_ctx, SVC_LOG_ERROR,
            "svc: layer params type: %d    %d values required, "
            "but only %d specified\n",
            type, num_layers, i);
    res = VPX_CODEC_INVALID_PARAM;
  }
  free(input_string);
  return res;
}
Exemplo n.º 9
0
/**
 * 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;
}
Exemplo n.º 10
0
/**
 * Encode a frame into multiple layers
 * Create a superframe containing the individual layers
 */
vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
                               struct vpx_image *rawimg, vpx_codec_pts_t pts,
                               int64_t duration, int deadline) {
  vpx_codec_err_t res;
  vpx_codec_iter_t iter;
  const vpx_codec_cx_pkt_t *cx_pkt;
  struct LayerData *cx_layer_list = NULL;
  struct LayerData *layer_data;
  struct Superframe superframe;
  SvcInternal *const si = get_svc_internal(svc_ctx);
  if (svc_ctx == NULL || codec_ctx == NULL || rawimg == NULL || si == NULL) {
    return VPX_CODEC_INVALID_PARAM;
  }

  memset(&superframe, 0, sizeof(superframe));
  svc_log_reset(svc_ctx);

  si->layers = svc_ctx->spatial_layers;
  if (si->frame_within_gop >= si->kf_dist ||
      si->encode_frame_count == 0) {
    si->frame_within_gop = 0;
  }
  si->is_keyframe = (si->frame_within_gop == 0);
  si->frame_size = 0;

  svc_log(svc_ctx, SVC_LOG_DEBUG,
          "vpx_svc_encode  layers: %d, frame_count: %d, frame_within_gop: %d\n",
          si->layers, si->encode_frame_count, si->frame_within_gop);

  // encode each layer
  for (si->layer = 0; si->layer < si->layers; ++si->layer) {
    if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
        si->is_keyframe && (si->layer == 1 || si->layer == 3)) {
      svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer);
      continue;
    }
    calculate_enc_frame_flags(svc_ctx);

    set_svc_parameters(svc_ctx, codec_ctx);

    res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration,
                           si->enc_frame_flags, deadline);
    if (res != VPX_CODEC_OK) {
      return res;
    }
    // save compressed data
    iter = NULL;
    while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
      switch (cx_pkt->kind) {
        case VPX_CODEC_CX_FRAME_PKT: {
          const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz);
          si->bytes_in_layer[si->layer] += frame_pkt_size;
          svc_log(svc_ctx, SVC_LOG_DEBUG,
                  "SVC frame: %d, layer: %d, size: %u\n",
                  si->encode_frame_count, si->layer, frame_pkt_size);
          layer_data =
              ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size);
          if (layer_data == NULL) {
            svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n");
            return 0;
          }
          ld_list_add(&cx_layer_list, layer_data);

          // save layer size in superframe index
          superframe.sizes[superframe.count++] = frame_pkt_size;
          superframe.magnitude |= frame_pkt_size;
          break;
        }
        case VPX_CODEC_PSNR_PKT: {
          svc_log(svc_ctx, SVC_LOG_DEBUG,
                  "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
                  "%2.3f  %2.3f  %2.3f  %2.3f \n",
                  si->encode_frame_count, si->layer,
                  cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1],
                  cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]);
          si->psnr_in_layer[si->layer] += cx_pkt->data.psnr.psnr[0];
          break;
        }
        default: {
          break;
        }
      }
    }
  }
  // add superframe index to layer data list
  sf_create_index(&superframe);
  layer_data = ld_create(superframe.buffer, superframe.index_size);
  ld_list_add(&cx_layer_list, layer_data);

  // get accumulated size of layer data
  si->frame_size = ld_list_get_buffer_size(cx_layer_list);
  if (si->frame_size == 0) return VPX_CODEC_ERROR;

  // all layers encoded, create single buffer with concatenated layers
  if (si->frame_size > si->buffer_size) {
    free(si->buffer);
    si->buffer = malloc(si->frame_size);
    if (si->buffer == NULL) {
      ld_list_free(cx_layer_list);
      return VPX_CODEC_MEM_ERROR;
    }
    si->buffer_size = si->frame_size;
  }
  // copy layer data into packet
  ld_list_copy_to_buffer(cx_layer_list, si->buffer);

  ld_list_free(cx_layer_list);

  svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, pts: %d\n",
          si->encode_frame_count, si->is_keyframe, (int)si->frame_size,
          (int)pts);
  ++si->frame_within_gop;
  ++si->encode_frame_count;

  return VPX_CODEC_OK;
}
Exemplo n.º 11
0
static void set_svc_parameters(SvcContext *svc_ctx,
                               vpx_codec_ctx_t *codec_ctx) {
  int layer, layer_index;
  vpx_svc_parameters_t svc_params;
  SvcInternal *const si = get_svc_internal(svc_ctx);

  memset(&svc_params, 0, sizeof(svc_params));
  svc_params.layer = si->layer;
  svc_params.flags = si->enc_frame_flags;

  layer = si->layer;
  if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
      si->frame_within_gop == 0) {
    // layers 1 & 3 don't exist in this mode, use the higher one
    if (layer == 0 || layer == 2) {
      layer += 1;
    }
  }
  if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
                                                   &svc_params.width,
                                                   &svc_params.height)) {
    svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
  }
  layer_index = layer + VPX_SS_MAX_LAYERS - si->layers;
  svc_params.min_quantizer = si->quantizer[layer_index];
  svc_params.max_quantizer = si->quantizer[layer_index];
  svc_params.distance_from_i_frame = si->frame_within_gop;

  // Use buffer i for layer i LST
  svc_params.lst_fb_idx = si->layer;

  // Use buffer i-1 for layer i Alt (Inter-layer prediction)
  if (si->layer != 0) {
    const int use_higher_layer =
        svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
        si->frame_within_gop == 0;
    svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1;
  }

  if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) {
    svc_params.gld_fb_idx = si->layer + 1;
  } else {
    if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES)
      svc_params.gld_fb_idx = svc_params.lst_fb_idx;
    else
      svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer;
  }

  svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n",
          si->encode_frame_count, si->layer, svc_params.width,
          svc_params.height, svc_params.min_quantizer);

  if (svc_params.flags == VPX_EFLAG_FORCE_KF) {
    svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n");
  } else {
    svc_log(
        svc_ctx, SVC_LOG_DEBUG, "Using:    LST/GLD/ALT [%2d|%2d|%2d]\n",
        svc_params.flags & VP8_EFLAG_NO_REF_LAST ? -1 : svc_params.lst_fb_idx,
        svc_params.flags & VP8_EFLAG_NO_REF_GF ? -1 : svc_params.gld_fb_idx,
        svc_params.flags & VP8_EFLAG_NO_REF_ARF ? -1 : svc_params.alt_fb_idx);
    svc_log(
        svc_ctx, SVC_LOG_DEBUG, "Updating: LST/GLD/ALT [%2d|%2d|%2d]\n",
        svc_params.flags & VP8_EFLAG_NO_UPD_LAST ? -1 : svc_params.lst_fb_idx,
        svc_params.flags & VP8_EFLAG_NO_UPD_GF ? -1 : svc_params.gld_fb_idx,
        svc_params.flags & VP8_EFLAG_NO_UPD_ARF ? -1 : svc_params.alt_fb_idx);
  }

  vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
}
Exemplo n.º 12
0
static void calculate_enc_frame_flags(SvcContext *svc_ctx) {
  vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF;
  SvcInternal *const si = get_svc_internal(svc_ctx);
  const int is_keyframe = (si->frame_within_gop == 0);

  // keyframe layer zero is identical for all modes
  if (is_keyframe && si->layer == 0) {
    si->enc_frame_flags = VPX_EFLAG_FORCE_KF;
    return;
  }

  switch (svc_ctx->encoding_mode) {
    case ALT_INTER_LAYER_PREDICTION_IP:
      if (si->layer == 0) {
        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
      } else if (is_keyframe) {
        if (si->layer == si->layers - 1) {
          flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
        } else {
          flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
        }
      } else {
        flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
      }
      break;
    case INTER_LAYER_PREDICTION_I:
      if (si->layer == 0) {
        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
      } else if (is_keyframe) {
        flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
      } else {
        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
      }
      break;
    case INTER_LAYER_PREDICTION_IP:
      if (si->layer == 0) {
        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
      } else if (is_keyframe) {
        flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
      } else {
        flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
      }
      break;
    case USE_GOLDEN_FRAME:
      if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) {
        if (si->layer == 0) {
          flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST);
        } else if (is_keyframe) {
          flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
        } else {
          flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST);
        }
      } else {
        if (si->layer == 0) {
          flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
        } else if (is_keyframe) {
          flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
        } else {
          flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
        }
      }
      break;
    default:
      svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n",
              svc_ctx->encoding_mode);
      break;
  }
  si->enc_frame_flags = flags;
}
Exemplo n.º 13
0
static void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) {
  svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n",
          value);
}
Exemplo n.º 14
0
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, sl, tl;
  SvcInternal_t *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;

  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;
  }

  // Note: temporal_layering_mode only applies to one-pass CBR
  // si->svc_params.temporal_layering_mode = svc_ctx->temporal_layering_mode;
  if (svc_ctx->temporal_layering_mode == 3) {
    svc_ctx->temporal_layers = 3;
  } else if (svc_ctx->temporal_layering_mode == 2 ||
             svc_ctx->temporal_layering_mode == 1) {
    svc_ctx->temporal_layers = 2;
  }

  for (sl = 0; sl < VPX_SS_MAX_LAYERS; ++sl) {
    si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM[sl];
    si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN[sl];
    si->svc_params.speed_per_layer[sl] = svc_ctx->speed;
  }
  if (enc_cfg->rc_end_usage == VPX_CBR && enc_cfg->g_pass == VPX_RC_ONE_PASS &&
      svc_ctx->spatial_layers <= 3) {
    for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
      int sl2 = (svc_ctx->spatial_layers == 2) ? sl + 1 : sl;
      si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM_2x[sl2];
      si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN_2x[sl2];
    }
    if (svc_ctx->spatial_layers == 1) {
      si->svc_params.scaling_factor_num[0] = 1;
      si->svc_params.scaling_factor_den[0] = 1;
    }
  }
  for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
    for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
      i = sl * svc_ctx->temporal_layers + tl;
      si->svc_params.max_quantizers[i] = MAX_QUANTIZER;
      si->svc_params.min_quantizers[i] = 0;
      if (enc_cfg->rc_end_usage == VPX_CBR &&
          enc_cfg->g_pass == VPX_RC_ONE_PASS) {
        si->svc_params.max_quantizers[i] = 56;
        si->svc_params.min_quantizers[i] = 2;
      }
    }
  }

  // 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;

  if (svc_ctx->temporal_layers * svc_ctx->spatial_layers > VPX_MAX_LAYERS) {
    svc_log(svc_ctx, SVC_LOG_ERROR,
            "spatial layers * temporal layers exceeds the maximum number of "
            "allowed layers of %d\n",
            svc_ctx->spatial_layers * svc_ctx->temporal_layers,
            (int)VPX_MAX_LAYERS);
    return VPX_CODEC_INVALID_PARAM;
  }
  res = assign_layer_bitrates(svc_ctx, enc_cfg);
  if (res != VPX_CODEC_OK) {
    svc_log(svc_ctx, SVC_LOG_ERROR,
            "layer bitrates incorrect: \n"
            "1) spatial layer bitrates should sum up to target \n"
            "2) temporal layer bitrates should be increasing within \n"
            "a spatial layer \n");
    return VPX_CODEC_INVALID_PARAM;
  }

#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);
    }
  }

  if (svc_ctx->threads) enc_cfg->g_threads = svc_ctx->threads;

  // Modify encoder configuration
  enc_cfg->ss_number_layers = svc_ctx->spatial_layers;
  enc_cfg->ts_number_layers = svc_ctx->temporal_layers;

  if (enc_cfg->rc_end_usage == VPX_CBR) {
    enc_cfg->rc_resize_allowed = 0;
    enc_cfg->rc_min_quantizer = 2;
    enc_cfg->rc_max_quantizer = 56;
    enc_cfg->rc_undershoot_pct = 50;
    enc_cfg->rc_overshoot_pct = 50;
    enc_cfg->rc_buf_initial_sz = 500;
    enc_cfg->rc_buf_optimal_sz = 600;
    enc_cfg->rc_buf_sz = 1000;
    enc_cfg->rc_dropframe_thresh = 0;
  }

  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;
  }
  if (svc_ctx->spatial_layers > 1 || svc_ctx->temporal_layers > 1) {
    vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
    vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params);
  }
  return VPX_CODEC_OK;
}
Exemplo n.º 15
0
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) {
  int max_intra_size_pct;
  vpx_codec_err_t res;
  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;
  }
  // use SvcInternal value for number of layers to enable forcing single layer
  // for first frame
  si->layers = svc_ctx->spatial_layers;

  res = parse_quantizer_values(svc_ctx, si->quantizers);
  if (res != VPX_CODEC_OK) return res;

  res = parse_scale_factors(svc_ctx, si->scale_factors);
  if (res != VPX_CODEC_OK) return res;

  // parse aggregate command line options
  res = parse_options(svc_ctx, si->options);
  if (res != VPX_CODEC_OK) return res;

  // modify encoder configuration
  enc_cfg->ss_number_layers = si->layers;
  enc_cfg->kf_mode = VPX_KF_DISABLED;
  enc_cfg->g_pass = VPX_RC_ONE_PASS;
  // Lag in frames not currently supported
  enc_cfg->g_lag_in_frames = 0;

  // TODO(ivanmaltz): determine if these values need to be set explicitly for
  // svc, or if the normal default/override mechanism can be used
  enc_cfg->rc_dropframe_thresh = 0;
  enc_cfg->rc_end_usage = VPX_CBR;
  enc_cfg->rc_resize_allowed = 0;
  enc_cfg->rc_min_quantizer = 33;
  enc_cfg->rc_max_quantizer = 33;
  enc_cfg->rc_undershoot_pct = 100;
  enc_cfg->rc_overshoot_pct = 15;
  enc_cfg->rc_buf_initial_sz = 500;
  enc_cfg->rc_buf_optimal_sz = 600;
  enc_cfg->rc_buf_sz = 1000;
  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);
  vpx_codec_control(codec_ctx, VP8E_SET_CPUUSED, 1);
  vpx_codec_control(codec_ctx, VP8E_SET_STATIC_THRESHOLD, 1);
  vpx_codec_control(codec_ctx, VP8E_SET_NOISE_SENSITIVITY, 1);
  vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1);

  max_intra_size_pct =
      (int)(((double)enc_cfg->rc_buf_optimal_sz * 0.5) *
            ((double)enc_cfg->g_timebase.den / enc_cfg->g_timebase.num) / 10.0);
  vpx_codec_control(codec_ctx, VP8E_SET_MAX_INTRA_BITRATE_PCT,
                    max_intra_size_pct);
  return VPX_CODEC_OK;
}
Exemplo n.º 16
0
/**
 * Encode a frame into multiple layers
 * Create a superframe containing the individual layers
 */
vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
                               struct vpx_image *rawimg, vpx_codec_pts_t pts,
                               int64_t duration, int deadline) {
  vpx_codec_err_t res;
  vpx_codec_iter_t iter;
  const vpx_codec_cx_pkt_t *cx_pkt;
  SvcInternal_t *const si = get_svc_internal(svc_ctx);
  if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
    return VPX_CODEC_INVALID_PARAM;
  }

  svc_log_reset(svc_ctx);

  res =
      vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, deadline);
  if (res != VPX_CODEC_OK) {
    return res;
  }
  // save compressed data
  iter = NULL;
  while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
    switch (cx_pkt->kind) {
#if CONFIG_SPATIAL_SVC && defined(VPX_TEST_SPATIAL_SVC)
      case VPX_CODEC_SPATIAL_SVC_LAYER_PSNR: {
        int i;
        for (i = 0; i < svc_ctx->spatial_layers; ++i) {
          int j;
          svc_log(svc_ctx, SVC_LOG_DEBUG,
                  "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
                  "%2.3f  %2.3f  %2.3f  %2.3f \n",
                  si->psnr_pkt_received, i, cx_pkt->data.layer_psnr[i].psnr[0],
                  cx_pkt->data.layer_psnr[i].psnr[1],
                  cx_pkt->data.layer_psnr[i].psnr[2],
                  cx_pkt->data.layer_psnr[i].psnr[3]);
          svc_log(svc_ctx, SVC_LOG_DEBUG,
                  "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): "
                  "%2.3f  %2.3f  %2.3f  %2.3f \n",
                  si->psnr_pkt_received, i, cx_pkt->data.layer_psnr[i].sse[0],
                  cx_pkt->data.layer_psnr[i].sse[1],
                  cx_pkt->data.layer_psnr[i].sse[2],
                  cx_pkt->data.layer_psnr[i].sse[3]);

          for (j = 0; j < COMPONENTS; ++j) {
            si->psnr_sum[i][j] += cx_pkt->data.layer_psnr[i].psnr[j];
            si->sse_sum[i][j] += cx_pkt->data.layer_psnr[i].sse[j];
          }
        }
        ++si->psnr_pkt_received;
        break;
      }
      case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: {
        int i;
        for (i = 0; i < svc_ctx->spatial_layers; ++i)
          si->bytes_sum[i] += cx_pkt->data.layer_sizes[i];
        break;
      }
#endif
      case VPX_CODEC_PSNR_PKT: {
#if CONFIG_SPATIAL_SVC && defined(VPX_TEST_SPATIAL_SVC)
        int j;
        svc_log(svc_ctx, SVC_LOG_DEBUG,
                "frame: %d, layer: %d, PSNR(Total/Y/U/V): "
                "%2.3f  %2.3f  %2.3f  %2.3f \n",
                si->psnr_pkt_received, 0, cx_pkt->data.layer_psnr[0].psnr[0],
                cx_pkt->data.layer_psnr[0].psnr[1],
                cx_pkt->data.layer_psnr[0].psnr[2],
                cx_pkt->data.layer_psnr[0].psnr[3]);
        for (j = 0; j < COMPONENTS; ++j) {
          si->psnr_sum[0][j] += cx_pkt->data.layer_psnr[0].psnr[j];
          si->sse_sum[0][j] += cx_pkt->data.layer_psnr[0].sse[j];
        }
#endif
      }
        ++si->psnr_pkt_received;
        break;
      default: { break; }
    }
  }

  return VPX_CODEC_OK;
}
Exemplo n.º 17
0
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;
}