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