| Index: source/libvpx/vpx/src/svc_encodeframe.c
|
| ===================================================================
|
| --- source/libvpx/vpx/src/svc_encodeframe.c (revision 281795)
|
| +++ source/libvpx/vpx/src/svc_encodeframe.c (working copy)
|
| @@ -24,6 +24,7 @@
|
| #include "vpx/svc_context.h"
|
| #include "vpx/vp8cx.h"
|
| #include "vpx/vpx_encoder.h"
|
| +#include "vpx_mem/vpx_mem.h"
|
|
|
| #ifdef __MINGW32__
|
| #define strtok_r strtok_s
|
| @@ -47,17 +48,22 @@
|
| static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27";
|
| static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16";
|
|
|
| +// One encoded frame
|
| +typedef struct FrameData {
|
| + void *buf; // compressed data buffer
|
| + size_t size; // length of compressed data
|
| + vpx_codec_frame_flags_t flags; /**< flags for this frame */
|
| + struct FrameData *next;
|
| +} FrameData;
|
| +
|
| typedef struct SvcInternal {
|
| char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options
|
| char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers
|
| - char quantizers_keyframe[OPTION_BUFFER_SIZE]; // set by
|
| - // vpx_svc_set_quantizers
|
| char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors
|
|
|
| // values extracted from option, quantizers
|
| int scaling_factor_num[VPX_SS_MAX_LAYERS];
|
| int scaling_factor_den[VPX_SS_MAX_LAYERS];
|
| - int quantizer_keyframe[VPX_SS_MAX_LAYERS];
|
| int quantizer[VPX_SS_MAX_LAYERS];
|
|
|
| // accumulated statistics
|
| @@ -72,15 +78,15 @@
|
|
|
| // state variables
|
| int encode_frame_count;
|
| + int frame_received;
|
| int frame_within_gop;
|
| vpx_enc_frame_flags_t enc_frame_flags;
|
| int layers;
|
| int layer;
|
| int is_keyframe;
|
|
|
| - size_t frame_size;
|
| - size_t buffer_size;
|
| - void *buffer;
|
| + FrameData *frame_list;
|
| + FrameData *frame_temp;
|
|
|
| char *rc_stats_buf;
|
| size_t rc_stats_buf_size;
|
| @@ -90,128 +96,54 @@
|
| vpx_codec_ctx_t *codec_ctx;
|
| } SvcInternal;
|
|
|
| -// Superframe is used to generate an index of individual frames (i.e., layers)
|
| -struct Superframe {
|
| - int count;
|
| - uint32_t sizes[SUPERFRAME_SLOTS];
|
| - uint32_t magnitude;
|
| - uint8_t buffer[SUPERFRAME_BUFFER_SIZE];
|
| - size_t index_size;
|
| -};
|
| -
|
| -// One encoded frame layer
|
| -struct LayerData {
|
| - void *buf; // compressed data buffer
|
| - size_t size; // length of compressed data
|
| - struct LayerData *next;
|
| -};
|
| -
|
| -// create LayerData from encoder output
|
| -static struct LayerData *ld_create(void *buf, size_t size) {
|
| - struct LayerData *const layer_data =
|
| - (struct LayerData *)malloc(sizeof(*layer_data));
|
| - if (layer_data == NULL) {
|
| +// create FrameData from encoder output
|
| +static struct FrameData *fd_create(void *buf, size_t size,
|
| + vpx_codec_frame_flags_t flags) {
|
| + struct FrameData *const frame_data =
|
| + (struct FrameData *)vpx_malloc(sizeof(*frame_data));
|
| + if (frame_data == NULL) {
|
| return NULL;
|
| }
|
| - layer_data->buf = malloc(size);
|
| - if (layer_data->buf == NULL) {
|
| - free(layer_data);
|
| + frame_data->buf = vpx_malloc(size);
|
| + if (frame_data->buf == NULL) {
|
| + vpx_free(frame_data);
|
| return NULL;
|
| }
|
| - memcpy(layer_data->buf, buf, size);
|
| - layer_data->size = size;
|
| - return layer_data;
|
| + vpx_memcpy(frame_data->buf, buf, size);
|
| + frame_data->size = size;
|
| + frame_data->flags = flags;
|
| + return frame_data;
|
| }
|
|
|
| -// free LayerData
|
| -static void ld_free(struct LayerData *layer_data) {
|
| - if (layer_data) {
|
| - if (layer_data->buf) {
|
| - free(layer_data->buf);
|
| - layer_data->buf = NULL;
|
| - }
|
| - free(layer_data);
|
| +// free FrameData
|
| +static void fd_free(struct FrameData *p) {
|
| + if (p) {
|
| + if (p->buf)
|
| + vpx_free(p->buf);
|
| + vpx_free(p);
|
| }
|
| }
|
|
|
| -// add layer data to list
|
| -static void ld_list_add(struct LayerData **list, struct LayerData *layer_data) {
|
| - struct LayerData **p = list;
|
| +// add FrameData to list
|
| +static void fd_list_add(struct FrameData **list, struct FrameData *layer_data) {
|
| + struct FrameData **p = list;
|
|
|
| while (*p != NULL) p = &(*p)->next;
|
| *p = layer_data;
|
| layer_data->next = NULL;
|
| }
|
|
|
| -// get accumulated size of layer data
|
| -static size_t ld_list_get_buffer_size(struct LayerData *list) {
|
| - struct LayerData *p;
|
| - size_t size = 0;
|
| +// free FrameData list
|
| +static void fd_free_list(struct FrameData *list) {
|
| + struct FrameData *p = list;
|
|
|
| - for (p = list; p != NULL; p = p->next) {
|
| - size += p->size;
|
| - }
|
| - return size;
|
| -}
|
| -
|
| -// copy layer data to buffer
|
| -static void ld_list_copy_to_buffer(struct LayerData *list, uint8_t *buffer) {
|
| - struct LayerData *p;
|
| -
|
| - for (p = list; p != NULL; p = p->next) {
|
| - buffer[0] = 1;
|
| - memcpy(buffer, p->buf, p->size);
|
| - buffer += p->size;
|
| - }
|
| -}
|
| -
|
| -// free layer data list
|
| -static void ld_list_free(struct LayerData *list) {
|
| - struct LayerData *p = list;
|
| -
|
| while (p) {
|
| list = list->next;
|
| - ld_free(p);
|
| + fd_free(p);
|
| p = list;
|
| }
|
| }
|
|
|
| -static void sf_create_index(struct Superframe *sf) {
|
| - uint8_t marker = 0xc0;
|
| - int i;
|
| - uint32_t mag, mask;
|
| - uint8_t *bufp;
|
| -
|
| - if (sf->count == 0 || sf->count >= 8) return;
|
| -
|
| - // Add the number of frames to the marker byte
|
| - marker |= sf->count - 1;
|
| -
|
| - // Choose the magnitude
|
| - for (mag = 0, mask = 0xff; mag < 4; ++mag) {
|
| - if (sf->magnitude < mask) break;
|
| - mask <<= 8;
|
| - mask |= 0xff;
|
| - }
|
| - marker |= mag << 3;
|
| -
|
| - // Write the index
|
| - sf->index_size = 2 + (mag + 1) * sf->count;
|
| - bufp = sf->buffer;
|
| -
|
| - *bufp++ = marker;
|
| - for (i = 0; i < sf->count; ++i) {
|
| - int this_sz = sf->sizes[i];
|
| - uint32_t j;
|
| -
|
| - for (j = 0; j <= mag; ++j) {
|
| - *bufp++ = this_sz & 0xff;
|
| - this_sz >>= 8;
|
| - }
|
| - }
|
| - *bufp++ = marker;
|
| -}
|
| -
|
| static SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
|
| if (svc_ctx == NULL) return NULL;
|
| if (svc_ctx->internal == NULL) {
|
| @@ -262,26 +194,8 @@
|
| return retval;
|
| }
|
|
|
| -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;
|
| -}
|
| -
|
| static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
|
| - const char *quantizer_values,
|
| - const int is_keyframe) {
|
| + const char *quantizer_values) {
|
| char *input_string;
|
| char *token;
|
| const char *delim = ",";
|
| @@ -292,11 +206,6 @@
|
| SvcInternal *const si = get_svc_internal(svc_ctx);
|
|
|
| if (quantizer_values == NULL || strlen(quantizer_values) == 0) {
|
| - if (is_keyframe) {
|
| - // If there non settings for key frame, we will apply settings from
|
| - // non key frame. So just simply return here.
|
| - return VPX_CODEC_INVALID_PARAM;
|
| - }
|
| input_string = strdup(DEFAULT_QUANTIZER_VALUES);
|
| } else {
|
| input_string = strdup(quantizer_values);
|
| @@ -317,12 +226,7 @@
|
| } else {
|
| q = 0;
|
| }
|
| - if (is_keyframe) {
|
| - si->quantizer_keyframe[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers]
|
| - = q;
|
| - } else {
|
| - si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q;
|
| - }
|
| + 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,
|
| @@ -407,7 +311,6 @@
|
| char *option_name;
|
| char *option_value;
|
| char *input_ptr;
|
| - int is_keyframe_qaunt_set = 0;
|
| vpx_codec_err_t res = VPX_CODEC_OK;
|
|
|
| if (options == NULL) return VPX_CODEC_OK;
|
| @@ -424,26 +327,14 @@
|
| 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) {
|
| + 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, 0);
|
| + res = parse_quantizer_values(svc_ctx, option_value);
|
| if (res != VPX_CODEC_OK) break;
|
| - if (!is_keyframe_qaunt_set) {
|
| - SvcInternal *const si = get_svc_internal(svc_ctx);
|
| - memcpy(get_svc_internal(svc_ctx)->quantizer_keyframe, si->quantizer,
|
| - sizeof(si->quantizer));
|
| - }
|
| - } else if (strcmp("quantizers-keyframe", option_name) == 0) {
|
| - res = parse_quantizer_values(svc_ctx, option_value, 1);
|
| - if (res != VPX_CODEC_OK) break;
|
| - is_keyframe_qaunt_set = 1;
|
| } else {
|
| svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
|
| res = VPX_CODEC_INVALID_PARAM;
|
| @@ -466,19 +357,13 @@
|
| }
|
|
|
| vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
|
| - const char *quantizers,
|
| - const int is_for_keyframe) {
|
| + const char *quantizers) {
|
| SvcInternal *const si = get_svc_internal(svc_ctx);
|
| if (svc_ctx == NULL || quantizers == NULL || si == NULL) {
|
| return VPX_CODEC_INVALID_PARAM;
|
| }
|
| - if (is_for_keyframe) {
|
| - strncpy(si->quantizers_keyframe, quantizers, sizeof(si->quantizers));
|
| - si->quantizers_keyframe[sizeof(si->quantizers_keyframe) - 1] = '\0';
|
| - } else {
|
| - strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
|
| - si->quantizers[sizeof(si->quantizers) - 1] = '\0';
|
| - }
|
| + strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
|
| + si->quantizers[sizeof(si->quantizers) - 1] = '\0';
|
| return VPX_CODEC_OK;
|
| }
|
|
|
| @@ -525,13 +410,9 @@
|
| return VPX_CODEC_INVALID_PARAM;
|
| }
|
|
|
| - res = parse_quantizer_values(svc_ctx, si->quantizers, 0);
|
| + res = parse_quantizer_values(svc_ctx, si->quantizers);
|
| if (res != VPX_CODEC_OK) return res;
|
|
|
| - res = parse_quantizer_values(svc_ctx, si->quantizers_keyframe, 1);
|
| - if (res != VPX_CODEC_OK)
|
| - memcpy(si->quantizer_keyframe, si->quantizer, sizeof(si->quantizer));
|
| -
|
| res = parse_scale_factors(svc_ctx, si->scale_factors);
|
| if (res != VPX_CODEC_OK) return res;
|
|
|
| @@ -574,8 +455,6 @@
|
| // modify encoder configuration
|
| enc_cfg->ss_number_layers = si->layers;
|
| enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder.
|
| - // 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
|
| @@ -608,6 +487,34 @@
|
| return VPX_CODEC_OK;
|
| }
|
|
|
| +static void accumulate_frame_size_for_each_layer(SvcInternal *const si,
|
| + const uint8_t *const buf,
|
| + const size_t size) {
|
| + uint8_t marker = buf[size - 1];
|
| + if ((marker & 0xe0) == 0xc0) {
|
| + const uint32_t frames = (marker & 0x7) + 1;
|
| + const uint32_t mag = ((marker >> 3) & 0x3) + 1;
|
| + const size_t index_sz = 2 + mag * frames;
|
| +
|
| + uint8_t marker2 = buf[size - index_sz];
|
| +
|
| + if (size >= index_sz && marker2 == marker) {
|
| + // found a valid superframe index
|
| + uint32_t i, j;
|
| + const uint8_t *x = &buf[size - index_sz + 1];
|
| +
|
| + // frames has a maximum of 8 and mag has a maximum of 4.
|
| + for (i = 0; i < frames; i++) {
|
| + uint32_t this_sz = 0;
|
| +
|
| + for (j = 0; j < mag; j++)
|
| + this_sz |= (*x++) << (j * 8);
|
| + si->bytes_sum[i] += this_sz;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| // SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h
|
|
|
| // encoder should reference the last frame
|
| @@ -664,62 +571,14 @@
|
| 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;
|
| + 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);
|
| }
|
| +
|
| si->enc_frame_flags = flags;
|
| }
|
|
|
| @@ -765,13 +624,6 @@
|
| 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)) {
|
| @@ -780,13 +632,8 @@
|
| layer_index = layer + VPX_SS_MAX_LAYERS - si->layers;
|
|
|
| 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];
|
| - }
|
| + svc_params.min_quantizer = si->quantizer[layer_index];
|
| + svc_params.max_quantizer = si->quantizer[layer_index];
|
| } else {
|
| svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer;
|
| svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer;
|
| @@ -798,22 +645,9 @@
|
| 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;
|
| - }
|
| + svc_params.alt_fb_idx = (si->layer > 0) ? si->layer - 1 : 0;
|
| + svc_params.gld_fb_idx = svc_params.lst_fb_idx;
|
|
|
| - 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);
|
| @@ -846,15 +680,12 @@
|
| 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;
|
| + int layer_for_psnr = 0;
|
| SvcInternal *const si = get_svc_internal(svc_ctx);
|
| 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;
|
|
|
| @@ -863,7 +694,6 @@
|
| si->frame_within_gop = 0;
|
| }
|
| si->is_keyframe = (si->frame_within_gop == 0);
|
| - si->frame_size = 0;
|
|
|
| if (rawimg != NULL) {
|
| svc_log(svc_ctx, SVC_LOG_DEBUG,
|
| @@ -872,124 +702,85 @@
|
| 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;
|
| - }
|
| -
|
| - if (rawimg != NULL) {
|
| + if (rawimg != NULL) {
|
| + // encode each layer
|
| + for (si->layer = 0; si->layer < si->layers; ++si->layer) {
|
| 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_sum[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 VPX_CODEC_OK;
|
| - }
|
| - ld_list_add(&cx_layer_list, layer_data);
|
| + 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) {
|
| + case VPX_CODEC_CX_FRAME_PKT: {
|
| + fd_list_add(&si->frame_list, fd_create(cx_pkt->data.frame.buf,
|
| + cx_pkt->data.frame.sz,
|
| + cx_pkt->data.frame.flags));
|
| + accumulate_frame_size_for_each_layer(si, cx_pkt->data.frame.buf,
|
| + cx_pkt->data.frame.sz);
|
|
|
| - // save layer size in superframe index
|
| - superframe.sizes[superframe.count++] = frame_pkt_size;
|
| - superframe.magnitude |= frame_pkt_size;
|
| - break;
|
| - }
|
| - case VPX_CODEC_PSNR_PKT: {
|
| - int i;
|
| - 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]);
|
| - 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->encode_frame_count, si->layer,
|
| - cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1],
|
| - cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]);
|
| - for (i = 0; i < COMPONENTS; i++) {
|
| - si->psnr_sum[si->layer][i] += cx_pkt->data.psnr.psnr[i];
|
| - si->sse_sum[si->layer][i] += cx_pkt->data.psnr.sse[i];
|
| - }
|
| - break;
|
| - }
|
| - case VPX_CODEC_STATS_PKT: {
|
| - size_t new_size = si->rc_stats_buf_used +
|
| - cx_pkt->data.twopass_stats.sz;
|
| + svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, "
|
| + "pts: %d\n", si->frame_received,
|
| + (cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? 1 : 0,
|
| + (int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts);
|
|
|
| - 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;
|
| + ++si->frame_received;
|
| + layer_for_psnr = 0;
|
| + break;
|
| + }
|
| + case VPX_CODEC_PSNR_PKT: {
|
| + int i;
|
| + 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->frame_received, layer_for_psnr,
|
| + cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1],
|
| + cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.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->frame_received, layer_for_psnr,
|
| + cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1],
|
| + cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]);
|
| + for (i = 0; i < COMPONENTS; i++) {
|
| + si->psnr_sum[layer_for_psnr][i] += cx_pkt->data.psnr.psnr[i];
|
| + si->sse_sum[layer_for_psnr][i] += cx_pkt->data.psnr.sse[i];
|
| }
|
| - default: {
|
| - break;
|
| - }
|
| + ++layer_for_psnr;
|
| + break;
|
| }
|
| - }
|
| - if (rawimg == NULL) {
|
| - break;
|
| - }
|
| - }
|
| - 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);
|
| + case VPX_CODEC_STATS_PKT: {
|
| + size_t new_size = si->rc_stats_buf_used +
|
| + cx_pkt->data.twopass_stats.sz;
|
|
|
| - // 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;
|
| + 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");
|
| + return VPX_CODEC_MEM_ERROR;
|
| + }
|
| + si->rc_stats_buf = p;
|
| + si->rc_stats_buf_size = new_size;
|
| }
|
| - 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);
|
| + 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) {
|
| ++si->frame_within_gop;
|
| ++si->encode_frame_count;
|
| @@ -1004,16 +795,27 @@
|
| return si->message_buffer;
|
| }
|
|
|
| -void *vpx_svc_get_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->buffer;
|
| +// We will maintain a list of output frame buffers since with lag_in_frame
|
| +// we need to output all frame buffers at the end. vpx_svc_get_buffer() will
|
| +// remove a frame buffer from the list the put it to a temporal pointer, which
|
| +// will be removed at the next vpx_svc_get_buffer() or when closing encoder.
|
| +void *vpx_svc_get_buffer(SvcContext *svc_ctx) {
|
| + SvcInternal *const si = get_svc_internal(svc_ctx);
|
| + if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return NULL;
|
| +
|
| + if (si->frame_temp)
|
| + fd_free(si->frame_temp);
|
| +
|
| + si->frame_temp = si->frame_list;
|
| + si->frame_list = si->frame_list->next;
|
| +
|
| + return si->frame_temp->buf;
|
| }
|
|
|
| size_t vpx_svc_get_frame_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->frame_size;
|
| + if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0;
|
| + return si->frame_list->size;
|
| }
|
|
|
| int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) {
|
| @@ -1024,8 +826,8 @@
|
|
|
| int vpx_svc_is_keyframe(const SvcContext *svc_ctx) {
|
| const SvcInternal *const si = get_const_svc_internal(svc_ctx);
|
| - if (svc_ctx == NULL || si == NULL) return 0;
|
| - return si->is_keyframe;
|
| + if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0;
|
| + return (si->frame_list->flags & VPX_FRAME_IS_KEY) != 0;
|
| }
|
|
|
| void vpx_svc_set_keyframe(SvcContext *svc_ctx) {
|
| @@ -1041,7 +843,7 @@
|
|
|
| // 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 number_of_frames, encode_frame_count;
|
| int i, j;
|
| uint32_t bytes_total = 0;
|
| double scale[COMPONENTS];
|
| @@ -1058,14 +860,9 @@
|
| 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 Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
|
| i, (double)si->psnr_sum[i][0] / number_of_frames,
|
| @@ -1112,7 +909,8 @@
|
| // SvcInternal if it was not already allocated
|
| si = (SvcInternal *)svc_ctx->internal;
|
| if (si != NULL) {
|
| - free(si->buffer);
|
| + fd_free(si->frame_temp);
|
| + fd_free_list(si->frame_list);
|
| if (si->rc_stats_buf) {
|
| free(si->rc_stats_buf);
|
| }
|
|
|