media/libvpx/vpx/src/svc_encodeframe.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libvpx/vpx/src/svc_encodeframe.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,983 @@
     1.4 +/*
     1.5 + *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
     1.6 + *
     1.7 + *  Use of this source code is governed by a BSD-style license
     1.8 + *  that can be found in the LICENSE file in the root of the source
     1.9 + *  tree. An additional intellectual property rights grant can be found
    1.10 + *  in the file PATENTS.  All contributing project authors may
    1.11 + *  be found in the AUTHORS file in the root of the source tree.
    1.12 + */
    1.13 +
    1.14 +/**
    1.15 + * @file
    1.16 + * VP9 SVC encoding support via libvpx
    1.17 + */
    1.18 +
    1.19 +#include <stdarg.h>
    1.20 +#include <stdio.h>
    1.21 +#include <stdlib.h>
    1.22 +#include <string.h>
    1.23 +#define VPX_DISABLE_CTRL_TYPECHECKS 1
    1.24 +#define VPX_CODEC_DISABLE_COMPAT 1
    1.25 +#include "vpx/svc_context.h"
    1.26 +#include "vpx/vp8cx.h"
    1.27 +#include "vpx/vpx_encoder.h"
    1.28 +
    1.29 +#ifdef __MINGW32__
    1.30 +#define strtok_r strtok_s
    1.31 +#ifndef MINGW_HAS_SECURE_API
    1.32 +// proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
    1.33 +_CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
    1.34 +#endif  /* MINGW_HAS_SECURE_API */
    1.35 +#endif  /* __MINGW32__ */
    1.36 +
    1.37 +#ifdef _MSC_VER
    1.38 +#define strdup _strdup
    1.39 +#define strtok_r strtok_s
    1.40 +#endif
    1.41 +
    1.42 +#define SVC_REFERENCE_FRAMES 8
    1.43 +#define SUPERFRAME_SLOTS (8)
    1.44 +#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
    1.45 +#define OPTION_BUFFER_SIZE 256
    1.46 +
    1.47 +static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27";
    1.48 +static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16";
    1.49 +
    1.50 +typedef struct SvcInternal {
    1.51 +  char options[OPTION_BUFFER_SIZE];        // set by vpx_svc_set_options
    1.52 +  char quantizers[OPTION_BUFFER_SIZE];     // set by vpx_svc_set_quantizers
    1.53 +  char scale_factors[OPTION_BUFFER_SIZE];  // set by vpx_svc_set_scale_factors
    1.54 +
    1.55 +  // values extracted from option, quantizers
    1.56 +  int scaling_factor_num[VPX_SS_MAX_LAYERS];
    1.57 +  int scaling_factor_den[VPX_SS_MAX_LAYERS];
    1.58 +  int quantizer[VPX_SS_MAX_LAYERS];
    1.59 +
    1.60 +  // accumulated statistics
    1.61 +  double psnr_in_layer[VPX_SS_MAX_LAYERS];
    1.62 +  uint32_t bytes_in_layer[VPX_SS_MAX_LAYERS];
    1.63 +
    1.64 +  // codec encoding values
    1.65 +  int width;    // width of highest layer
    1.66 +  int height;   // height of highest layer
    1.67 +  int kf_dist;  // distance between keyframes
    1.68 +
    1.69 +  // state variables
    1.70 +  int encode_frame_count;
    1.71 +  int frame_within_gop;
    1.72 +  vpx_enc_frame_flags_t enc_frame_flags;
    1.73 +  int layers;
    1.74 +  int layer;
    1.75 +  int is_keyframe;
    1.76 +
    1.77 +  size_t frame_size;
    1.78 +  size_t buffer_size;
    1.79 +  void *buffer;
    1.80 +
    1.81 +  char message_buffer[2048];
    1.82 +  vpx_codec_ctx_t *codec_ctx;
    1.83 +} SvcInternal;
    1.84 +
    1.85 +// Superframe is used to generate an index of individual frames (i.e., layers)
    1.86 +struct Superframe {
    1.87 +  int count;
    1.88 +  uint32_t sizes[SUPERFRAME_SLOTS];
    1.89 +  uint32_t magnitude;
    1.90 +  uint8_t buffer[SUPERFRAME_BUFFER_SIZE];
    1.91 +  size_t index_size;
    1.92 +};
    1.93 +
    1.94 +// One encoded frame layer
    1.95 +struct LayerData {
    1.96 +  void *buf;    // compressed data buffer
    1.97 +  size_t size;  // length of compressed data
    1.98 +  struct LayerData *next;
    1.99 +};
   1.100 +
   1.101 +// create LayerData from encoder output
   1.102 +static struct LayerData *ld_create(void *buf, size_t size) {
   1.103 +  struct LayerData *const layer_data = malloc(sizeof(*layer_data));
   1.104 +  if (layer_data == NULL) {
   1.105 +    return NULL;
   1.106 +  }
   1.107 +  layer_data->buf = malloc(size);
   1.108 +  if (layer_data->buf == NULL) {
   1.109 +    free(layer_data);
   1.110 +    return NULL;
   1.111 +  }
   1.112 +  memcpy(layer_data->buf, buf, size);
   1.113 +  layer_data->size = size;
   1.114 +  return layer_data;
   1.115 +}
   1.116 +
   1.117 +// free LayerData
   1.118 +static void ld_free(struct LayerData *layer_data) {
   1.119 +  if (layer_data) {
   1.120 +    if (layer_data->buf) {
   1.121 +      free(layer_data->buf);
   1.122 +      layer_data->buf = NULL;
   1.123 +    }
   1.124 +    free(layer_data);
   1.125 +  }
   1.126 +}
   1.127 +
   1.128 +// add layer data to list
   1.129 +static void ld_list_add(struct LayerData **list, struct LayerData *layer_data) {
   1.130 +  struct LayerData **p = list;
   1.131 +
   1.132 +  while (*p != NULL) p = &(*p)->next;
   1.133 +  *p = layer_data;
   1.134 +  layer_data->next = NULL;
   1.135 +}
   1.136 +
   1.137 +// get accumulated size of layer data
   1.138 +static size_t ld_list_get_buffer_size(struct LayerData *list) {
   1.139 +  struct LayerData *p;
   1.140 +  size_t size = 0;
   1.141 +
   1.142 +  for (p = list; p != NULL; p = p->next) {
   1.143 +    size += p->size;
   1.144 +  }
   1.145 +  return size;
   1.146 +}
   1.147 +
   1.148 +// copy layer data to buffer
   1.149 +static void ld_list_copy_to_buffer(struct LayerData *list, uint8_t *buffer) {
   1.150 +  struct LayerData *p;
   1.151 +
   1.152 +  for (p = list; p != NULL; p = p->next) {
   1.153 +    buffer[0] = 1;
   1.154 +    memcpy(buffer, p->buf, p->size);
   1.155 +    buffer += p->size;
   1.156 +  }
   1.157 +}
   1.158 +
   1.159 +// free layer data list
   1.160 +static void ld_list_free(struct LayerData *list) {
   1.161 +  struct LayerData *p = list;
   1.162 +
   1.163 +  while (p) {
   1.164 +    list = list->next;
   1.165 +    ld_free(p);
   1.166 +    p = list;
   1.167 +  }
   1.168 +}
   1.169 +
   1.170 +static void sf_create_index(struct Superframe *sf) {
   1.171 +  uint8_t marker = 0xc0;
   1.172 +  int i;
   1.173 +  uint32_t mag, mask;
   1.174 +  uint8_t *bufp;
   1.175 +
   1.176 +  if (sf->count == 0 || sf->count >= 8) return;
   1.177 +
   1.178 +  // Add the number of frames to the marker byte
   1.179 +  marker |= sf->count - 1;
   1.180 +
   1.181 +  // Choose the magnitude
   1.182 +  for (mag = 0, mask = 0xff; mag < 4; ++mag) {
   1.183 +    if (sf->magnitude < mask) break;
   1.184 +    mask <<= 8;
   1.185 +    mask |= 0xff;
   1.186 +  }
   1.187 +  marker |= mag << 3;
   1.188 +
   1.189 +  // Write the index
   1.190 +  sf->index_size = 2 + (mag + 1) * sf->count;
   1.191 +  bufp = sf->buffer;
   1.192 +
   1.193 +  *bufp++ = marker;
   1.194 +  for (i = 0; i < sf->count; ++i) {
   1.195 +    int this_sz = sf->sizes[i];
   1.196 +    uint32_t j;
   1.197 +
   1.198 +    for (j = 0; j <= mag; ++j) {
   1.199 +      *bufp++ = this_sz & 0xff;
   1.200 +      this_sz >>= 8;
   1.201 +    }
   1.202 +  }
   1.203 +  *bufp++ = marker;
   1.204 +}
   1.205 +
   1.206 +static SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
   1.207 +  if (svc_ctx == NULL) return NULL;
   1.208 +  if (svc_ctx->internal == NULL) {
   1.209 +    SvcInternal *const si = malloc(sizeof(*si));
   1.210 +    if (si != NULL) {
   1.211 +      memset(si, 0, sizeof(*si));
   1.212 +    }
   1.213 +    svc_ctx->internal = si;
   1.214 +  }
   1.215 +  return svc_ctx->internal;
   1.216 +}
   1.217 +
   1.218 +static const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) {
   1.219 +  if (svc_ctx == NULL) return NULL;
   1.220 +  return svc_ctx->internal;
   1.221 +}
   1.222 +
   1.223 +static void svc_log_reset(SvcContext *svc_ctx) {
   1.224 +  SvcInternal *const si = (SvcInternal *)svc_ctx->internal;
   1.225 +  si->message_buffer[0] = '\0';
   1.226 +}
   1.227 +
   1.228 +static int svc_log(SvcContext *svc_ctx, int level, const char *fmt, ...) {
   1.229 +  char buf[512];
   1.230 +  int retval = 0;
   1.231 +  va_list ap;
   1.232 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.233 +
   1.234 +  if (level > svc_ctx->log_level) {
   1.235 +    return retval;
   1.236 +  }
   1.237 +
   1.238 +  va_start(ap, fmt);
   1.239 +  retval = vsnprintf(buf, sizeof(buf), fmt, ap);
   1.240 +  va_end(ap);
   1.241 +
   1.242 +  if (svc_ctx->log_print) {
   1.243 +    printf("%s", buf);
   1.244 +  } else {
   1.245 +    strncat(si->message_buffer, buf,
   1.246 +            sizeof(si->message_buffer) - strlen(si->message_buffer) - 1);
   1.247 +  }
   1.248 +
   1.249 +  if (level == SVC_LOG_ERROR) {
   1.250 +    si->codec_ctx->err_detail = si->message_buffer;
   1.251 +  }
   1.252 +  return retval;
   1.253 +}
   1.254 +
   1.255 +static vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx,
   1.256 +                                                const char *value_str) {
   1.257 +  if (strcmp(value_str, "i") == 0) {
   1.258 +    svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I;
   1.259 +  } else if (strcmp(value_str, "alt-ip") == 0) {
   1.260 +    svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP;
   1.261 +  } else if (strcmp(value_str, "ip") == 0) {
   1.262 +    svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP;
   1.263 +  } else if (strcmp(value_str, "gf") == 0) {
   1.264 +    svc_ctx->encoding_mode = USE_GOLDEN_FRAME;
   1.265 +  } else {
   1.266 +    svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str);
   1.267 +    return VPX_CODEC_INVALID_PARAM;
   1.268 +  }
   1.269 +  return VPX_CODEC_OK;
   1.270 +}
   1.271 +
   1.272 +static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
   1.273 +                                              const char *quantizer_values) {
   1.274 +  char *input_string;
   1.275 +  char *token;
   1.276 +  const char *delim = ",";
   1.277 +  char *save_ptr;
   1.278 +  int found = 0;
   1.279 +  int i, q;
   1.280 +  int res = VPX_CODEC_OK;
   1.281 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.282 +
   1.283 +  if (quantizer_values == NULL || strlen(quantizer_values) == 0) {
   1.284 +    input_string = strdup(DEFAULT_QUANTIZER_VALUES);
   1.285 +  } else {
   1.286 +    input_string = strdup(quantizer_values);
   1.287 +  }
   1.288 +
   1.289 +  token = strtok_r(input_string, delim, &save_ptr);
   1.290 +  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
   1.291 +    if (token != NULL) {
   1.292 +      q = atoi(token);
   1.293 +      if (q <= 0 || q > 100) {
   1.294 +        svc_log(svc_ctx, SVC_LOG_ERROR,
   1.295 +                "svc-quantizer-values: invalid value %s\n", token);
   1.296 +        res = VPX_CODEC_INVALID_PARAM;
   1.297 +        break;
   1.298 +      }
   1.299 +      token = strtok_r(NULL, delim, &save_ptr);
   1.300 +      found = i + 1;
   1.301 +    } else {
   1.302 +      q = 0;
   1.303 +    }
   1.304 +    si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q;
   1.305 +  }
   1.306 +  if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
   1.307 +    svc_log(svc_ctx, SVC_LOG_ERROR,
   1.308 +            "svc: quantizers: %d values required, but only %d specified\n",
   1.309 +            svc_ctx->spatial_layers, found);
   1.310 +    res = VPX_CODEC_INVALID_PARAM;
   1.311 +  }
   1.312 +  free(input_string);
   1.313 +  return res;
   1.314 +}
   1.315 +
   1.316 +static void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) {
   1.317 +  svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n",
   1.318 +          value);
   1.319 +}
   1.320 +
   1.321 +static vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx,
   1.322 +                                           const char *scale_factors) {
   1.323 +  char *input_string;
   1.324 +  char *token;
   1.325 +  const char *delim = ",";
   1.326 +  char *save_ptr;
   1.327 +  int found = 0;
   1.328 +  int i;
   1.329 +  int64_t num, den;
   1.330 +  int res = VPX_CODEC_OK;
   1.331 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.332 +
   1.333 +  if (scale_factors == NULL || strlen(scale_factors) == 0) {
   1.334 +    input_string = strdup(DEFAULT_SCALE_FACTORS);
   1.335 +  } else {
   1.336 +    input_string = strdup(scale_factors);
   1.337 +  }
   1.338 +  token = strtok_r(input_string, delim, &save_ptr);
   1.339 +  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
   1.340 +    num = den = 0;
   1.341 +    if (token != NULL) {
   1.342 +      num = strtol(token, &token, 10);
   1.343 +      if (num <= 0) {
   1.344 +        log_invalid_scale_factor(svc_ctx, token);
   1.345 +        res = VPX_CODEC_INVALID_PARAM;
   1.346 +        break;
   1.347 +      }
   1.348 +      if (*token++ != '/') {
   1.349 +        log_invalid_scale_factor(svc_ctx, token);
   1.350 +        res = VPX_CODEC_INVALID_PARAM;
   1.351 +        break;
   1.352 +      }
   1.353 +      den = strtol(token, &token, 10);
   1.354 +      if (den <= 0) {
   1.355 +        log_invalid_scale_factor(svc_ctx, token);
   1.356 +        res = VPX_CODEC_INVALID_PARAM;
   1.357 +        break;
   1.358 +      }
   1.359 +      token = strtok_r(NULL, delim, &save_ptr);
   1.360 +      found = i + 1;
   1.361 +    }
   1.362 +    si->scaling_factor_num[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
   1.363 +        (int)num;
   1.364 +    si->scaling_factor_den[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
   1.365 +        (int)den;
   1.366 +  }
   1.367 +  if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
   1.368 +    svc_log(svc_ctx, SVC_LOG_ERROR,
   1.369 +            "svc: scale-factors: %d values required, but only %d specified\n",
   1.370 +            svc_ctx->spatial_layers, found);
   1.371 +    res = VPX_CODEC_INVALID_PARAM;
   1.372 +  }
   1.373 +  free(input_string);
   1.374 +  return res;
   1.375 +}
   1.376 +
   1.377 +/**
   1.378 + * Parse SVC encoding options
   1.379 + * Format: encoding-mode=<svc_mode>,layers=<layer_count>
   1.380 + *         scale-factors=<n1>/<d1>,<n2>/<d2>,...
   1.381 + *         quantizers=<q1>,<q2>,...
   1.382 + * svc_mode = [i|ip|alt_ip|gf]
   1.383 + */
   1.384 +static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
   1.385 +  char *input_string;
   1.386 +  char *option_name;
   1.387 +  char *option_value;
   1.388 +  char *input_ptr;
   1.389 +  int res = VPX_CODEC_OK;
   1.390 +
   1.391 +  if (options == NULL) return VPX_CODEC_OK;
   1.392 +  input_string = strdup(options);
   1.393 +
   1.394 +  // parse option name
   1.395 +  option_name = strtok_r(input_string, "=", &input_ptr);
   1.396 +  while (option_name != NULL) {
   1.397 +    // parse option value
   1.398 +    option_value = strtok_r(NULL, " ", &input_ptr);
   1.399 +    if (option_value == NULL) {
   1.400 +      svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
   1.401 +              option_name);
   1.402 +      res = VPX_CODEC_INVALID_PARAM;
   1.403 +      break;
   1.404 +    }
   1.405 +    if (strcmp("encoding-mode", option_name) == 0) {
   1.406 +      res = set_option_encoding_mode(svc_ctx, option_value);
   1.407 +      if (res != VPX_CODEC_OK) break;
   1.408 +    } else if (strcmp("layers", option_name) == 0) {
   1.409 +      svc_ctx->spatial_layers = atoi(option_value);
   1.410 +    } else if (strcmp("scale-factors", option_name) == 0) {
   1.411 +      res = parse_scale_factors(svc_ctx, option_value);
   1.412 +      if (res != VPX_CODEC_OK) break;
   1.413 +    } else if (strcmp("quantizers", option_name) == 0) {
   1.414 +      res = parse_quantizer_values(svc_ctx, option_value);
   1.415 +      if (res != VPX_CODEC_OK) break;
   1.416 +    } else {
   1.417 +      svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
   1.418 +      res = VPX_CODEC_INVALID_PARAM;
   1.419 +      break;
   1.420 +    }
   1.421 +    option_name = strtok_r(NULL, "=", &input_ptr);
   1.422 +  }
   1.423 +  free(input_string);
   1.424 +  return res;
   1.425 +}
   1.426 +
   1.427 +vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) {
   1.428 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.429 +  if (svc_ctx == NULL || options == NULL || si == NULL) {
   1.430 +    return VPX_CODEC_INVALID_PARAM;
   1.431 +  }
   1.432 +  strncpy(si->options, options, sizeof(si->options));
   1.433 +  si->options[sizeof(si->options) - 1] = '\0';
   1.434 +  return VPX_CODEC_OK;
   1.435 +}
   1.436 +
   1.437 +vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
   1.438 +                                       const char *quantizers) {
   1.439 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.440 +  if (svc_ctx == NULL || quantizers == NULL || si == NULL) {
   1.441 +    return VPX_CODEC_INVALID_PARAM;
   1.442 +  }
   1.443 +  strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
   1.444 +  si->quantizers[sizeof(si->quantizers) - 1] = '\0';
   1.445 +  return VPX_CODEC_OK;
   1.446 +}
   1.447 +
   1.448 +vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx,
   1.449 +                                          const char *scale_factors) {
   1.450 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.451 +  if (svc_ctx == NULL || scale_factors == NULL || si == NULL) {
   1.452 +    return VPX_CODEC_INVALID_PARAM;
   1.453 +  }
   1.454 +  strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors));
   1.455 +  si->scale_factors[sizeof(si->scale_factors) - 1] = '\0';
   1.456 +  return VPX_CODEC_OK;
   1.457 +}
   1.458 +
   1.459 +vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
   1.460 +                             vpx_codec_iface_t *iface,
   1.461 +                             vpx_codec_enc_cfg_t *enc_cfg) {
   1.462 +  int max_intra_size_pct;
   1.463 +  vpx_codec_err_t res;
   1.464 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.465 +  if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
   1.466 +      enc_cfg == NULL) {
   1.467 +    return VPX_CODEC_INVALID_PARAM;
   1.468 +  }
   1.469 +  if (si == NULL) return VPX_CODEC_MEM_ERROR;
   1.470 +
   1.471 +  si->codec_ctx = codec_ctx;
   1.472 +
   1.473 +  si->width = enc_cfg->g_w;
   1.474 +  si->height = enc_cfg->g_h;
   1.475 +
   1.476 +  if (enc_cfg->kf_max_dist < 2) {
   1.477 +    svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n",
   1.478 +            enc_cfg->kf_max_dist);
   1.479 +    return VPX_CODEC_INVALID_PARAM;
   1.480 +  }
   1.481 +  si->kf_dist = enc_cfg->kf_max_dist;
   1.482 +
   1.483 +  if (svc_ctx->spatial_layers == 0)
   1.484 +    svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS;
   1.485 +  if (svc_ctx->spatial_layers < 1 ||
   1.486 +      svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) {
   1.487 +    svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
   1.488 +            svc_ctx->spatial_layers);
   1.489 +    return VPX_CODEC_INVALID_PARAM;
   1.490 +  }
   1.491 +  // use SvcInternal value for number of layers to enable forcing single layer
   1.492 +  // for first frame
   1.493 +  si->layers = svc_ctx->spatial_layers;
   1.494 +
   1.495 +  res = parse_quantizer_values(svc_ctx, si->quantizers);
   1.496 +  if (res != VPX_CODEC_OK) return res;
   1.497 +
   1.498 +  res = parse_scale_factors(svc_ctx, si->scale_factors);
   1.499 +  if (res != VPX_CODEC_OK) return res;
   1.500 +
   1.501 +  // parse aggregate command line options
   1.502 +  res = parse_options(svc_ctx, si->options);
   1.503 +  if (res != VPX_CODEC_OK) return res;
   1.504 +
   1.505 +  // modify encoder configuration
   1.506 +  enc_cfg->ss_number_layers = si->layers;
   1.507 +  enc_cfg->kf_mode = VPX_KF_DISABLED;
   1.508 +  enc_cfg->g_pass = VPX_RC_ONE_PASS;
   1.509 +  // Lag in frames not currently supported
   1.510 +  enc_cfg->g_lag_in_frames = 0;
   1.511 +
   1.512 +  // TODO(ivanmaltz): determine if these values need to be set explicitly for
   1.513 +  // svc, or if the normal default/override mechanism can be used
   1.514 +  enc_cfg->rc_dropframe_thresh = 0;
   1.515 +  enc_cfg->rc_end_usage = VPX_CBR;
   1.516 +  enc_cfg->rc_resize_allowed = 0;
   1.517 +  enc_cfg->rc_min_quantizer = 33;
   1.518 +  enc_cfg->rc_max_quantizer = 33;
   1.519 +  enc_cfg->rc_undershoot_pct = 100;
   1.520 +  enc_cfg->rc_overshoot_pct = 15;
   1.521 +  enc_cfg->rc_buf_initial_sz = 500;
   1.522 +  enc_cfg->rc_buf_optimal_sz = 600;
   1.523 +  enc_cfg->rc_buf_sz = 1000;
   1.524 +  enc_cfg->g_error_resilient = 1;
   1.525 +
   1.526 +  // Initialize codec
   1.527 +  res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR);
   1.528 +  if (res != VPX_CODEC_OK) {
   1.529 +    svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n");
   1.530 +    return res;
   1.531 +  }
   1.532 +
   1.533 +  vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
   1.534 +  vpx_codec_control(codec_ctx, VP8E_SET_CPUUSED, 1);
   1.535 +  vpx_codec_control(codec_ctx, VP8E_SET_STATIC_THRESHOLD, 1);
   1.536 +  vpx_codec_control(codec_ctx, VP8E_SET_NOISE_SENSITIVITY, 1);
   1.537 +  vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1);
   1.538 +
   1.539 +  max_intra_size_pct =
   1.540 +      (int)(((double)enc_cfg->rc_buf_optimal_sz * 0.5) *
   1.541 +            ((double)enc_cfg->g_timebase.den / enc_cfg->g_timebase.num) / 10.0);
   1.542 +  vpx_codec_control(codec_ctx, VP8E_SET_MAX_INTRA_BITRATE_PCT,
   1.543 +                    max_intra_size_pct);
   1.544 +  return VPX_CODEC_OK;
   1.545 +}
   1.546 +
   1.547 +// SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h
   1.548 +
   1.549 +// encoder should reference the last frame
   1.550 +#define USE_LAST (1 << 0)
   1.551 +
   1.552 +// encoder should reference the alt ref frame
   1.553 +#define USE_ARF (1 << 1)
   1.554 +
   1.555 +// encoder should reference the golden frame
   1.556 +#define USE_GF (1 << 2)
   1.557 +
   1.558 +// encoder should copy current frame to the last frame buffer
   1.559 +#define UPDATE_LAST (1 << 3)
   1.560 +
   1.561 +// encoder should copy current frame to the alt ref frame buffer
   1.562 +#define UPDATE_ARF (1 << 4)
   1.563 +
   1.564 +// encoder should copy current frame to the golden frame
   1.565 +#define UPDATE_GF (1 << 5)
   1.566 +
   1.567 +static int map_vp8_flags(int svc_flags) {
   1.568 +  int flags = 0;
   1.569 +
   1.570 +  if (!(svc_flags & USE_LAST)) flags |= VP8_EFLAG_NO_REF_LAST;
   1.571 +  if (!(svc_flags & USE_ARF)) flags |= VP8_EFLAG_NO_REF_ARF;
   1.572 +  if (!(svc_flags & USE_GF)) flags |= VP8_EFLAG_NO_REF_GF;
   1.573 +
   1.574 +  if (svc_flags & UPDATE_LAST) {
   1.575 +    // last is updated automatically
   1.576 +  } else {
   1.577 +    flags |= VP8_EFLAG_NO_UPD_LAST;
   1.578 +  }
   1.579 +  if (svc_flags & UPDATE_ARF) {
   1.580 +    flags |= VP8_EFLAG_FORCE_ARF;
   1.581 +  } else {
   1.582 +    flags |= VP8_EFLAG_NO_UPD_ARF;
   1.583 +  }
   1.584 +  if (svc_flags & UPDATE_GF) {
   1.585 +    flags |= VP8_EFLAG_FORCE_GF;
   1.586 +  } else {
   1.587 +    flags |= VP8_EFLAG_NO_UPD_GF;
   1.588 +  }
   1.589 +  return flags;
   1.590 +}
   1.591 +
   1.592 +/**
   1.593 + * Helper to check if the current frame is the first, full resolution dummy.
   1.594 + */
   1.595 +static int vpx_svc_dummy_frame(SvcContext *svc_ctx) {
   1.596 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.597 +  return svc_ctx->first_frame_full_size == 1 && si->encode_frame_count == 0;
   1.598 +}
   1.599 +
   1.600 +static void calculate_enc_frame_flags(SvcContext *svc_ctx) {
   1.601 +  vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF;
   1.602 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.603 +  const int is_keyframe = (si->frame_within_gop == 0);
   1.604 +
   1.605 +  // keyframe layer zero is identical for all modes
   1.606 +  if ((is_keyframe && si->layer == 0) || vpx_svc_dummy_frame(svc_ctx)) {
   1.607 +    si->enc_frame_flags = VPX_EFLAG_FORCE_KF;
   1.608 +    return;
   1.609 +  }
   1.610 +
   1.611 +  switch (svc_ctx->encoding_mode) {
   1.612 +    case ALT_INTER_LAYER_PREDICTION_IP:
   1.613 +      if (si->layer == 0) {
   1.614 +        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
   1.615 +      } else if (is_keyframe) {
   1.616 +        if (si->layer == si->layers - 1) {
   1.617 +          flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
   1.618 +        } else {
   1.619 +          flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
   1.620 +        }
   1.621 +      } else {
   1.622 +        flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
   1.623 +      }
   1.624 +      break;
   1.625 +    case INTER_LAYER_PREDICTION_I:
   1.626 +      if (si->layer == 0) {
   1.627 +        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
   1.628 +      } else if (is_keyframe) {
   1.629 +        flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
   1.630 +      } else {
   1.631 +        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
   1.632 +      }
   1.633 +      break;
   1.634 +    case INTER_LAYER_PREDICTION_IP:
   1.635 +      if (si->layer == 0) {
   1.636 +        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
   1.637 +      } else if (is_keyframe) {
   1.638 +        flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
   1.639 +      } else {
   1.640 +        flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
   1.641 +      }
   1.642 +      break;
   1.643 +    case USE_GOLDEN_FRAME:
   1.644 +      if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) {
   1.645 +        if (si->layer == 0) {
   1.646 +          flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST);
   1.647 +        } else if (is_keyframe) {
   1.648 +          flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
   1.649 +        } else {
   1.650 +          flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST);
   1.651 +        }
   1.652 +      } else {
   1.653 +        if (si->layer == 0) {
   1.654 +          flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
   1.655 +        } else if (is_keyframe) {
   1.656 +          flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
   1.657 +        } else {
   1.658 +          flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
   1.659 +        }
   1.660 +      }
   1.661 +      break;
   1.662 +    default:
   1.663 +      svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n",
   1.664 +              svc_ctx->encoding_mode);
   1.665 +      break;
   1.666 +  }
   1.667 +  si->enc_frame_flags = flags;
   1.668 +}
   1.669 +
   1.670 +vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
   1.671 +                                             int layer,
   1.672 +                                             unsigned int *width,
   1.673 +                                             unsigned int *height) {
   1.674 +  int w, h, index, num, den;
   1.675 +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
   1.676 +
   1.677 +  if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL) {
   1.678 +    return VPX_CODEC_INVALID_PARAM;
   1.679 +  }
   1.680 +  if (layer < 0 || layer >= si->layers) return VPX_CODEC_INVALID_PARAM;
   1.681 +
   1.682 +  index = layer + VPX_SS_MAX_LAYERS - si->layers;
   1.683 +  num = si->scaling_factor_num[index];
   1.684 +  den = si->scaling_factor_den[index];
   1.685 +  if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM;
   1.686 +
   1.687 +  w = si->width * num / den;
   1.688 +  h = si->height * num / den;
   1.689 +
   1.690 +  // make height and width even to make chrome player happy
   1.691 +  w += w % 2;
   1.692 +  h += h % 2;
   1.693 +
   1.694 +  *width = w;
   1.695 +  *height = h;
   1.696 +
   1.697 +  return VPX_CODEC_OK;
   1.698 +}
   1.699 +
   1.700 +static void set_svc_parameters(SvcContext *svc_ctx,
   1.701 +                               vpx_codec_ctx_t *codec_ctx) {
   1.702 +  int layer, layer_index;
   1.703 +  vpx_svc_parameters_t svc_params;
   1.704 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.705 +
   1.706 +  memset(&svc_params, 0, sizeof(svc_params));
   1.707 +  svc_params.layer = si->layer;
   1.708 +  svc_params.flags = si->enc_frame_flags;
   1.709 +
   1.710 +  layer = si->layer;
   1.711 +  if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
   1.712 +      si->frame_within_gop == 0) {
   1.713 +    // layers 1 & 3 don't exist in this mode, use the higher one
   1.714 +    if (layer == 0 || layer == 2) {
   1.715 +      layer += 1;
   1.716 +    }
   1.717 +  }
   1.718 +  if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
   1.719 +                                                   &svc_params.width,
   1.720 +                                                   &svc_params.height)) {
   1.721 +    svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
   1.722 +  }
   1.723 +  layer_index = layer + VPX_SS_MAX_LAYERS - si->layers;
   1.724 +  svc_params.min_quantizer = si->quantizer[layer_index];
   1.725 +  svc_params.max_quantizer = si->quantizer[layer_index];
   1.726 +  svc_params.distance_from_i_frame = si->frame_within_gop;
   1.727 +
   1.728 +  // Use buffer i for layer i LST
   1.729 +  svc_params.lst_fb_idx = si->layer;
   1.730 +
   1.731 +  // Use buffer i-1 for layer i Alt (Inter-layer prediction)
   1.732 +  if (si->layer != 0) {
   1.733 +    const int use_higher_layer =
   1.734 +        svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
   1.735 +        si->frame_within_gop == 0;
   1.736 +    svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1;
   1.737 +  }
   1.738 +
   1.739 +  if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) {
   1.740 +    svc_params.gld_fb_idx = si->layer + 1;
   1.741 +  } else {
   1.742 +    if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES)
   1.743 +      svc_params.gld_fb_idx = svc_params.lst_fb_idx;
   1.744 +    else
   1.745 +      svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer;
   1.746 +  }
   1.747 +
   1.748 +  svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n",
   1.749 +          si->encode_frame_count, si->layer, svc_params.width,
   1.750 +          svc_params.height, svc_params.min_quantizer);
   1.751 +
   1.752 +  if (svc_params.flags == VPX_EFLAG_FORCE_KF) {
   1.753 +    svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n");
   1.754 +  } else {
   1.755 +    svc_log(
   1.756 +        svc_ctx, SVC_LOG_DEBUG, "Using:    LST/GLD/ALT [%2d|%2d|%2d]\n",
   1.757 +        svc_params.flags & VP8_EFLAG_NO_REF_LAST ? -1 : svc_params.lst_fb_idx,
   1.758 +        svc_params.flags & VP8_EFLAG_NO_REF_GF ? -1 : svc_params.gld_fb_idx,
   1.759 +        svc_params.flags & VP8_EFLAG_NO_REF_ARF ? -1 : svc_params.alt_fb_idx);
   1.760 +    svc_log(
   1.761 +        svc_ctx, SVC_LOG_DEBUG, "Updating: LST/GLD/ALT [%2d|%2d|%2d]\n",
   1.762 +        svc_params.flags & VP8_EFLAG_NO_UPD_LAST ? -1 : svc_params.lst_fb_idx,
   1.763 +        svc_params.flags & VP8_EFLAG_NO_UPD_GF ? -1 : svc_params.gld_fb_idx,
   1.764 +        svc_params.flags & VP8_EFLAG_NO_UPD_ARF ? -1 : svc_params.alt_fb_idx);
   1.765 +  }
   1.766 +
   1.767 +  vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
   1.768 +}
   1.769 +
   1.770 +/**
   1.771 + * Encode a frame into multiple layers
   1.772 + * Create a superframe containing the individual layers
   1.773 + */
   1.774 +vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
   1.775 +                               struct vpx_image *rawimg, vpx_codec_pts_t pts,
   1.776 +                               int64_t duration, int deadline) {
   1.777 +  vpx_codec_err_t res;
   1.778 +  vpx_codec_iter_t iter;
   1.779 +  const vpx_codec_cx_pkt_t *cx_pkt;
   1.780 +  struct LayerData *cx_layer_list = NULL;
   1.781 +  struct LayerData *layer_data;
   1.782 +  struct Superframe superframe;
   1.783 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.784 +  if (svc_ctx == NULL || codec_ctx == NULL || rawimg == NULL || si == NULL) {
   1.785 +    return VPX_CODEC_INVALID_PARAM;
   1.786 +  }
   1.787 +
   1.788 +  memset(&superframe, 0, sizeof(superframe));
   1.789 +  svc_log_reset(svc_ctx);
   1.790 +
   1.791 +  si->layers = vpx_svc_dummy_frame(svc_ctx) ? 1 : svc_ctx->spatial_layers;
   1.792 +  if (si->frame_within_gop >= si->kf_dist ||
   1.793 +      si->encode_frame_count == 0 ||
   1.794 +      (si->encode_frame_count == 1 && svc_ctx->first_frame_full_size == 1)) {
   1.795 +    si->frame_within_gop = 0;
   1.796 +  }
   1.797 +  si->is_keyframe = (si->frame_within_gop == 0);
   1.798 +  si->frame_size = 0;
   1.799 +
   1.800 +  svc_log(svc_ctx, SVC_LOG_DEBUG,
   1.801 +          "vpx_svc_encode  layers: %d, frame_count: %d, frame_within_gop: %d\n",
   1.802 +          si->layers, si->encode_frame_count, si->frame_within_gop);
   1.803 +
   1.804 +  // encode each layer
   1.805 +  for (si->layer = 0; si->layer < si->layers; ++si->layer) {
   1.806 +    if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
   1.807 +        si->is_keyframe && (si->layer == 1 || si->layer == 3)) {
   1.808 +      svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer);
   1.809 +      continue;
   1.810 +    }
   1.811 +    calculate_enc_frame_flags(svc_ctx);
   1.812 +
   1.813 +    if (vpx_svc_dummy_frame(svc_ctx)) {
   1.814 +      // do not set svc parameters, use normal encode
   1.815 +      svc_log(svc_ctx, SVC_LOG_DEBUG, "encoding full size first frame\n");
   1.816 +    } else {
   1.817 +      set_svc_parameters(svc_ctx, codec_ctx);
   1.818 +    }
   1.819 +    res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration,
   1.820 +                           si->enc_frame_flags, deadline);
   1.821 +    if (res != VPX_CODEC_OK) {
   1.822 +      return res;
   1.823 +    }
   1.824 +    // save compressed data
   1.825 +    iter = NULL;
   1.826 +    while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
   1.827 +      switch (cx_pkt->kind) {
   1.828 +        case VPX_CODEC_CX_FRAME_PKT: {
   1.829 +          const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz);
   1.830 +          if (!vpx_svc_dummy_frame(svc_ctx)) {
   1.831 +            si->bytes_in_layer[si->layer] += frame_pkt_size;
   1.832 +            svc_log(svc_ctx, SVC_LOG_DEBUG,
   1.833 +                    "SVC frame: %d, layer: %d, size: %u\n",
   1.834 +                    si->encode_frame_count, si->layer, frame_pkt_size);
   1.835 +          }
   1.836 +          layer_data =
   1.837 +              ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size);
   1.838 +          if (layer_data == NULL) {
   1.839 +            svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n");
   1.840 +            return 0;
   1.841 +          }
   1.842 +          ld_list_add(&cx_layer_list, layer_data);
   1.843 +
   1.844 +          // save layer size in superframe index
   1.845 +          superframe.sizes[superframe.count++] = frame_pkt_size;
   1.846 +          superframe.magnitude |= frame_pkt_size;
   1.847 +          break;
   1.848 +        }
   1.849 +        case VPX_CODEC_PSNR_PKT: {
   1.850 +          if (!vpx_svc_dummy_frame(svc_ctx)) {
   1.851 +            svc_log(svc_ctx, SVC_LOG_DEBUG,
   1.852 +                    "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
   1.853 +                    "%2.3f  %2.3f  %2.3f  %2.3f \n",
   1.854 +                    si->encode_frame_count, si->layer,
   1.855 +                    cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1],
   1.856 +                    cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]);
   1.857 +            si->psnr_in_layer[si->layer] += cx_pkt->data.psnr.psnr[0];
   1.858 +          }
   1.859 +          break;
   1.860 +        }
   1.861 +        default: {
   1.862 +          break;
   1.863 +        }
   1.864 +      }
   1.865 +    }
   1.866 +  }
   1.867 +  // add superframe index to layer data list
   1.868 +  if (!vpx_svc_dummy_frame(svc_ctx)) {
   1.869 +    sf_create_index(&superframe);
   1.870 +    layer_data = ld_create(superframe.buffer, superframe.index_size);
   1.871 +    ld_list_add(&cx_layer_list, layer_data);
   1.872 +  }
   1.873 +  // get accumulated size of layer data
   1.874 +  si->frame_size = ld_list_get_buffer_size(cx_layer_list);
   1.875 +  if (si->frame_size == 0) return VPX_CODEC_ERROR;
   1.876 +
   1.877 +  // all layers encoded, create single buffer with concatenated layers
   1.878 +  if (si->frame_size > si->buffer_size) {
   1.879 +    free(si->buffer);
   1.880 +    si->buffer = malloc(si->frame_size);
   1.881 +    if (si->buffer == NULL) {
   1.882 +      ld_list_free(cx_layer_list);
   1.883 +      return VPX_CODEC_MEM_ERROR;
   1.884 +    }
   1.885 +    si->buffer_size = si->frame_size;
   1.886 +  }
   1.887 +  // copy layer data into packet
   1.888 +  ld_list_copy_to_buffer(cx_layer_list, si->buffer);
   1.889 +
   1.890 +  ld_list_free(cx_layer_list);
   1.891 +
   1.892 +  svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, pts: %d\n",
   1.893 +          si->encode_frame_count, si->is_keyframe, (int)si->frame_size,
   1.894 +          (int)pts);
   1.895 +  ++si->frame_within_gop;
   1.896 +  ++si->encode_frame_count;
   1.897 +
   1.898 +  return VPX_CODEC_OK;
   1.899 +}
   1.900 +
   1.901 +const char *vpx_svc_get_message(const SvcContext *svc_ctx) {
   1.902 +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
   1.903 +  if (svc_ctx == NULL || si == NULL) return NULL;
   1.904 +  return si->message_buffer;
   1.905 +}
   1.906 +
   1.907 +void *vpx_svc_get_buffer(const SvcContext *svc_ctx) {
   1.908 +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
   1.909 +  if (svc_ctx == NULL || si == NULL) return NULL;
   1.910 +  return si->buffer;
   1.911 +}
   1.912 +
   1.913 +size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) {
   1.914 +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
   1.915 +  if (svc_ctx == NULL || si == NULL) return 0;
   1.916 +  return si->frame_size;
   1.917 +}
   1.918 +
   1.919 +int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) {
   1.920 +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
   1.921 +  if (svc_ctx == NULL || si == NULL) return 0;
   1.922 +  return si->encode_frame_count;
   1.923 +}
   1.924 +
   1.925 +int vpx_svc_is_keyframe(const SvcContext *svc_ctx) {
   1.926 +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
   1.927 +  if (svc_ctx == NULL || si == NULL) return 0;
   1.928 +  return si->is_keyframe;
   1.929 +}
   1.930 +
   1.931 +void vpx_svc_set_keyframe(SvcContext *svc_ctx) {
   1.932 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.933 +  if (svc_ctx == NULL || si == NULL) return;
   1.934 +  si->frame_within_gop = 0;
   1.935 +}
   1.936 +
   1.937 +// dump accumulated statistics and reset accumulated values
   1.938 +const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
   1.939 +  int number_of_frames, number_of_keyframes, encode_frame_count;
   1.940 +  int i;
   1.941 +  uint32_t bytes_total = 0;
   1.942 +  SvcInternal *const si = get_svc_internal(svc_ctx);
   1.943 +  if (svc_ctx == NULL || si == NULL) return NULL;
   1.944 +
   1.945 +  svc_log_reset(svc_ctx);
   1.946 +
   1.947 +  encode_frame_count = si->encode_frame_count;
   1.948 +  if (svc_ctx->first_frame_full_size) encode_frame_count--;
   1.949 +  if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx);
   1.950 +
   1.951 +  svc_log(svc_ctx, SVC_LOG_INFO, "\n");
   1.952 +  number_of_keyframes = encode_frame_count / si->kf_dist + 1;
   1.953 +  for (i = 0; i < si->layers; ++i) {
   1.954 +    number_of_frames = encode_frame_count;
   1.955 +
   1.956 +    if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
   1.957 +        (i == 1 || i == 3)) {
   1.958 +      number_of_frames -= number_of_keyframes;
   1.959 +    }
   1.960 +    svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d PSNR=[%2.3f], Bytes=[%u]\n", i,
   1.961 +            (double)si->psnr_in_layer[i] / number_of_frames,
   1.962 +            si->bytes_in_layer[i]);
   1.963 +    bytes_total += si->bytes_in_layer[i];
   1.964 +    si->psnr_in_layer[i] = 0;
   1.965 +    si->bytes_in_layer[i] = 0;
   1.966 +  }
   1.967 +
   1.968 +  // only display statistics once
   1.969 +  si->encode_frame_count = 0;
   1.970 +
   1.971 +  svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
   1.972 +  return vpx_svc_get_message(svc_ctx);
   1.973 +}
   1.974 +
   1.975 +void vpx_svc_release(SvcContext *svc_ctx) {
   1.976 +  SvcInternal *si;
   1.977 +  if (svc_ctx == NULL) return;
   1.978 +  // do not use get_svc_internal as it will unnecessarily allocate an
   1.979 +  // SvcInternal if it was not already allocated
   1.980 +  si = (SvcInternal *)svc_ctx->internal;
   1.981 +  if (si != NULL) {
   1.982 +    free(si->buffer);
   1.983 +    free(si);
   1.984 +    svc_ctx->internal = NULL;
   1.985 +  }
   1.986 +}

mercurial