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