| Index: source/libvpx/vpx/src/svc_encodeframe.c
 | 
| ===================================================================
 | 
| --- source/libvpx/vpx/src/svc_encodeframe.c	(revision 263011)
 | 
| +++ source/libvpx/vpx/src/svc_encodeframe.c	(working copy)
 | 
| @@ -13,6 +13,7 @@
 | 
|   * VP9 SVC encoding support via libvpx
 | 
|   */
 | 
|  
 | 
| +#include <assert.h>
 | 
|  #include <math.h>
 | 
|  #include <stdarg.h>
 | 
|  #include <stdio.h>
 | 
| @@ -81,6 +82,10 @@
 | 
|    size_t buffer_size;
 | 
|    void *buffer;
 | 
|  
 | 
| +  char *rc_stats_buf;
 | 
| +  size_t rc_stats_buf_size;
 | 
| +  size_t rc_stats_buf_used;
 | 
| +
 | 
|    char message_buffer[2048];
 | 
|    vpx_codec_ctx_t *codec_ctx;
 | 
|  } SvcInternal;
 | 
| @@ -519,9 +524,6 @@
 | 
|              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, 0);
 | 
|    if (res != VPX_CODEC_OK) return res;
 | 
| @@ -533,10 +535,13 @@
 | 
|    res = parse_scale_factors(svc_ctx, si->scale_factors);
 | 
|    if (res != VPX_CODEC_OK) return res;
 | 
|  
 | 
| -  // parse aggregate command line options
 | 
| +  // 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;
 | 
|  
 | 
| +  si->layers = svc_ctx->spatial_layers;
 | 
| +
 | 
|    // Assign target bitrate for each layer. We calculate the ratio
 | 
|    // from the resolution for now.
 | 
|    // TODO(Minghai): Optimize the mechanism of allocating bits after
 | 
| @@ -546,6 +551,7 @@
 | 
|      float total = 0;
 | 
|      float alloc_ratio[VPX_SS_MAX_LAYERS] = {0};
 | 
|  
 | 
| +    assert(si->layers <= VPX_SS_MAX_LAYERS);
 | 
|      for (i = 0; i < si->layers; ++i) {
 | 
|        int pos = i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers;
 | 
|        if (pos < VPX_SS_MAX_LAYERS && si->scaling_factor_den[pos] > 0) {
 | 
| @@ -569,7 +575,6 @@
 | 
|    enc_cfg->ss_number_layers = si->layers;
 | 
|    enc_cfg->ts_number_layers = 1;  // Temporal layers not used in this encoder.
 | 
|    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;
 | 
|  
 | 
| @@ -578,8 +583,12 @@
 | 
|    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;
 | 
| +
 | 
| +  if (enc_cfg->g_pass == VPX_RC_ONE_PASS) {
 | 
| +    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;
 | 
| @@ -779,12 +788,17 @@
 | 
|    }
 | 
|    layer_index = layer + VPX_SS_MAX_LAYERS - si->layers;
 | 
|  
 | 
| -  if (vpx_svc_is_keyframe(svc_ctx)) {
 | 
| -    svc_params.min_quantizer = si->quantizer_keyframe[layer_index];
 | 
| -    svc_params.max_quantizer = si->quantizer_keyframe[layer_index];
 | 
| +  if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) {
 | 
| +    if (vpx_svc_is_keyframe(svc_ctx)) {
 | 
| +      svc_params.min_quantizer = si->quantizer_keyframe[layer_index];
 | 
| +      svc_params.max_quantizer = si->quantizer_keyframe[layer_index];
 | 
| +    } else {
 | 
| +      svc_params.min_quantizer = si->quantizer[layer_index];
 | 
| +      svc_params.max_quantizer = si->quantizer[layer_index];
 | 
| +    }
 | 
|    } else {
 | 
| -    svc_params.min_quantizer = si->quantizer[layer_index];
 | 
| -    svc_params.max_quantizer = si->quantizer[layer_index];
 | 
| +    svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer;
 | 
| +    svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer;
 | 
|    }
 | 
|  
 | 
|    svc_params.distance_from_i_frame = si->frame_within_gop;
 | 
| @@ -845,12 +859,13 @@
 | 
|    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) {
 | 
| +  if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
 | 
|      return VPX_CODEC_INVALID_PARAM;
 | 
|    }
 | 
|  
 | 
|    memset(&superframe, 0, sizeof(superframe));
 | 
|    svc_log_reset(svc_ctx);
 | 
| +  si->rc_stats_buf_used = 0;
 | 
|  
 | 
|    si->layers = svc_ctx->spatial_layers;
 | 
|    if (si->frame_within_gop >= si->kf_dist ||
 | 
| @@ -860,9 +875,12 @@
 | 
|    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);
 | 
| +  if (rawimg != NULL) {
 | 
| +    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) {
 | 
| @@ -871,9 +889,11 @@
 | 
|        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);
 | 
| +    if (rawimg != NULL) {
 | 
| +      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);
 | 
| @@ -923,39 +943,63 @@
 | 
|            }
 | 
|            break;
 | 
|          }
 | 
| +        case VPX_CODEC_STATS_PKT: {
 | 
| +          size_t new_size = si->rc_stats_buf_used +
 | 
| +              cx_pkt->data.twopass_stats.sz;
 | 
| +
 | 
| +          if (new_size > si->rc_stats_buf_size) {
 | 
| +            char *p = (char*)realloc(si->rc_stats_buf, new_size);
 | 
| +            if (p == NULL) {
 | 
| +              svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating stats buf\n");
 | 
| +              break;
 | 
| +            }
 | 
| +            si->rc_stats_buf = p;
 | 
| +            si->rc_stats_buf_size = new_size;
 | 
| +          }
 | 
| +
 | 
| +          memcpy(si->rc_stats_buf + si->rc_stats_buf_used,
 | 
| +                 cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz);
 | 
| +          si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz;
 | 
| +          break;
 | 
| +        }
 | 
|          default: {
 | 
|            break;
 | 
|          }
 | 
|        }
 | 
|      }
 | 
| +    if (rawimg == NULL) {
 | 
| +      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);
 | 
| +  if (codec_ctx->config.enc->g_pass != VPX_RC_FIRST_PASS) {
 | 
| +    // 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;
 | 
| +    // get accumulated size of layer data
 | 
| +    si->frame_size = ld_list_get_buffer_size(cx_layer_list);
 | 
| +    if (si->frame_size > 0) {
 | 
| +      // 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, (uint8_t *)si->buffer);
 | 
|  
 | 
| -  // 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;
 | 
| +
 | 
| +      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->buffer_size = si->frame_size;
 | 
|    }
 | 
| -  // copy layer data into packet
 | 
| -  ld_list_copy_to_buffer(cx_layer_list, (uint8_t *)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;
 | 
|  
 | 
| @@ -1077,7 +1121,24 @@
 | 
|    si = (SvcInternal *)svc_ctx->internal;
 | 
|    if (si != NULL) {
 | 
|      free(si->buffer);
 | 
| +    if (si->rc_stats_buf) {
 | 
| +      free(si->rc_stats_buf);
 | 
| +    }
 | 
|      free(si);
 | 
|      svc_ctx->internal = NULL;
 | 
|    }
 | 
|  }
 | 
| +
 | 
| +size_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx) {
 | 
| +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
 | 
| +  if (svc_ctx == NULL || si == NULL) return 0;
 | 
| +  return si->rc_stats_buf_used;
 | 
| +}
 | 
| +
 | 
| +char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) {
 | 
| +  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
 | 
| +  if (svc_ctx == NULL || si == NULL) return NULL;
 | 
| +  return si->rc_stats_buf;
 | 
| +}
 | 
| +
 | 
| +
 | 
| 
 |