1/* 2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11/** 12 * @file 13 * VP9 SVC encoding support via libvpx 14 */ 15 16#include <assert.h> 17#include <math.h> 18#include <limits.h> 19#include <stdarg.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#define VPX_DISABLE_CTRL_TYPECHECKS 1 24#include "./vpx_config.h" 25#include "vpx/svc_context.h" 26#include "vpx/vp8cx.h" 27#include "vpx/vpx_encoder.h" 28#include "vpx_mem/vpx_mem.h" 29#include "vp9/common/vp9_onyxc_int.h" 30 31#ifdef __MINGW32__ 32#define strtok_r strtok_s 33#ifndef MINGW_HAS_SECURE_API 34// proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h 35_CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); 36#endif /* MINGW_HAS_SECURE_API */ 37#endif /* __MINGW32__ */ 38 39#ifdef _MSC_VER 40#define strdup _strdup 41#define strtok_r strtok_s 42#endif 43 44#define SVC_REFERENCE_FRAMES 8 45#define SUPERFRAME_SLOTS (8) 46#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) 47 48#define MAX_QUANTIZER 63 49 50static const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = { 4, 5, 7, 11, 51 16 }; 52 53static const int DEFAULT_SCALE_FACTORS_DEN[VPX_SS_MAX_LAYERS] = { 16, 16, 16, 54 16, 16 }; 55 56static const int DEFAULT_SCALE_FACTORS_NUM_2x[VPX_SS_MAX_LAYERS] = { 1, 2, 4 }; 57 58static const int DEFAULT_SCALE_FACTORS_DEN_2x[VPX_SS_MAX_LAYERS] = { 4, 4, 4 }; 59 60typedef enum { 61 QUANTIZER = 0, 62 BITRATE, 63 SCALE_FACTOR, 64 AUTO_ALT_REF, 65 ALL_OPTION_TYPES 66} LAYER_OPTION_TYPE; 67 68static const int option_max_values[ALL_OPTION_TYPES] = { 63, INT_MAX, INT_MAX, 69 1 }; 70 71static const int option_min_values[ALL_OPTION_TYPES] = { 0, 0, 1, 0 }; 72 73// One encoded frame 74typedef struct FrameData { 75 void *buf; // compressed data buffer 76 size_t size; // length of compressed data 77 vpx_codec_frame_flags_t flags; /**< flags for this frame */ 78 struct FrameData *next; 79} FrameData; 80 81static SvcInternal_t *get_svc_internal(SvcContext *svc_ctx) { 82 if (svc_ctx == NULL) return NULL; 83 if (svc_ctx->internal == NULL) { 84 SvcInternal_t *const si = (SvcInternal_t *)malloc(sizeof(*si)); 85 if (si != NULL) { 86 memset(si, 0, sizeof(*si)); 87 } 88 svc_ctx->internal = si; 89 } 90 return (SvcInternal_t *)svc_ctx->internal; 91} 92 93static const SvcInternal_t *get_const_svc_internal(const SvcContext *svc_ctx) { 94 if (svc_ctx == NULL) return NULL; 95 return (const SvcInternal_t *)svc_ctx->internal; 96} 97 98static void svc_log_reset(SvcContext *svc_ctx) { 99 SvcInternal_t *const si = (SvcInternal_t *)svc_ctx->internal; 100 si->message_buffer[0] = '\0'; 101} 102 103static int svc_log(SvcContext *svc_ctx, SVC_LOG_LEVEL level, const char *fmt, 104 ...) { 105 char buf[512]; 106 int retval = 0; 107 va_list ap; 108 SvcInternal_t *const si = get_svc_internal(svc_ctx); 109 110 if (level > svc_ctx->log_level) { 111 return retval; 112 } 113 114 va_start(ap, fmt); 115 retval = vsnprintf(buf, sizeof(buf), fmt, ap); 116 va_end(ap); 117 118 if (svc_ctx->log_print) { 119 printf("%s", buf); 120 } else { 121 strncat(si->message_buffer, buf, 122 sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); 123 } 124 125 if (level == SVC_LOG_ERROR) { 126 si->codec_ctx->err_detail = si->message_buffer; 127 } 128 return retval; 129} 130 131static vpx_codec_err_t extract_option(LAYER_OPTION_TYPE type, char *input, 132 int *value0, int *value1) { 133 if (type == SCALE_FACTOR) { 134 *value0 = strtol(input, &input, 10); 135 if (*input++ != '/') return VPX_CODEC_INVALID_PARAM; 136 *value1 = strtol(input, &input, 10); 137 138 if (*value0 < option_min_values[SCALE_FACTOR] || 139 *value1 < option_min_values[SCALE_FACTOR] || 140 *value0 > option_max_values[SCALE_FACTOR] || 141 *value1 > option_max_values[SCALE_FACTOR] || 142 *value0 > *value1) // num shouldn't be greater than den 143 return VPX_CODEC_INVALID_PARAM; 144 } else { 145 *value0 = atoi(input); 146 if (*value0 < option_min_values[type] || *value0 > option_max_values[type]) 147 return VPX_CODEC_INVALID_PARAM; 148 } 149 return VPX_CODEC_OK; 150} 151 152static vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx, 153 LAYER_OPTION_TYPE type, 154 const char *input, 155 int *option0, 156 int *option1) { 157 int i; 158 vpx_codec_err_t res = VPX_CODEC_OK; 159 char *input_string; 160 char *token; 161 const char *delim = ","; 162 char *save_ptr; 163 int num_layers = svc_ctx->spatial_layers; 164 if (type == BITRATE) 165 num_layers = svc_ctx->spatial_layers * svc_ctx->temporal_layers; 166 167 if (input == NULL || option0 == NULL || 168 (option1 == NULL && type == SCALE_FACTOR)) 169 return VPX_CODEC_INVALID_PARAM; 170 171 input_string = strdup(input); 172 token = strtok_r(input_string, delim, &save_ptr); 173 for (i = 0; i < num_layers; ++i) { 174 if (token != NULL) { 175 res = extract_option(type, token, option0 + i, option1 + i); 176 if (res != VPX_CODEC_OK) break; 177 token = strtok_r(NULL, delim, &save_ptr); 178 } else { 179 break; 180 } 181 } 182 if (res == VPX_CODEC_OK && i != num_layers) { 183 svc_log(svc_ctx, SVC_LOG_ERROR, 184 "svc: layer params type: %d %d values required, " 185 "but only %d specified\n", 186 type, num_layers, i); 187 res = VPX_CODEC_INVALID_PARAM; 188 } 189 free(input_string); 190 return res; 191} 192 193/** 194 * Parse SVC encoding options 195 * Format: encoding-mode=<svc_mode>,layers=<layer_count> 196 * scale-factors=<n1>/<d1>,<n2>/<d2>,... 197 * quantizers=<q1>,<q2>,... 198 * svc_mode = [i|ip|alt_ip|gf] 199 */ 200static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { 201 char *input_string; 202 char *option_name; 203 char *option_value; 204 char *input_ptr = NULL; 205 SvcInternal_t *const si = get_svc_internal(svc_ctx); 206 vpx_codec_err_t res = VPX_CODEC_OK; 207 int i, alt_ref_enabled = 0; 208 209 if (options == NULL) return VPX_CODEC_OK; 210 input_string = strdup(options); 211 212 // parse option name 213 option_name = strtok_r(input_string, "=", &input_ptr); 214 while (option_name != NULL) { 215 // parse option value 216 option_value = strtok_r(NULL, " ", &input_ptr); 217 if (option_value == NULL) { 218 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", 219 option_name); 220 res = VPX_CODEC_INVALID_PARAM; 221 break; 222 } 223 if (strcmp("spatial-layers", option_name) == 0) { 224 svc_ctx->spatial_layers = atoi(option_value); 225 } else if (strcmp("temporal-layers", option_name) == 0) { 226 svc_ctx->temporal_layers = atoi(option_value); 227 } else if (strcmp("scale-factors", option_name) == 0) { 228 res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value, 229 si->svc_params.scaling_factor_num, 230 si->svc_params.scaling_factor_den); 231 if (res != VPX_CODEC_OK) break; 232 } else if (strcmp("max-quantizers", option_name) == 0) { 233 res = 234 parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, 235 si->svc_params.max_quantizers, NULL); 236 if (res != VPX_CODEC_OK) break; 237 } else if (strcmp("min-quantizers", option_name) == 0) { 238 res = 239 parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, 240 si->svc_params.min_quantizers, NULL); 241 if (res != VPX_CODEC_OK) break; 242 } else if (strcmp("auto-alt-refs", option_name) == 0) { 243 res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value, 244 si->enable_auto_alt_ref, NULL); 245 if (res != VPX_CODEC_OK) break; 246 } else if (strcmp("bitrates", option_name) == 0) { 247 res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value, 248 si->bitrates, NULL); 249 if (res != VPX_CODEC_OK) break; 250 } else if (strcmp("multi-frame-contexts", option_name) == 0) { 251 si->use_multiple_frame_contexts = atoi(option_value); 252 } else { 253 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); 254 res = VPX_CODEC_INVALID_PARAM; 255 break; 256 } 257 option_name = strtok_r(NULL, "=", &input_ptr); 258 } 259 free(input_string); 260 261 for (i = 0; i < svc_ctx->spatial_layers; ++i) { 262 if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER || 263 si->svc_params.max_quantizers[i] < 0 || 264 si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] || 265 si->svc_params.min_quantizers[i] < 0) 266 res = VPX_CODEC_INVALID_PARAM; 267 } 268 269 if (si->use_multiple_frame_contexts && 270 (svc_ctx->spatial_layers > 3 || 271 svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4)) 272 res = VPX_CODEC_INVALID_PARAM; 273 274 for (i = 0; i < svc_ctx->spatial_layers; ++i) 275 alt_ref_enabled += si->enable_auto_alt_ref[i]; 276 if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) { 277 svc_log(svc_ctx, SVC_LOG_ERROR, 278 "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could" 279 "enabled auto alt reference frame, but % layers are enabled\n", 280 REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled); 281 res = VPX_CODEC_INVALID_PARAM; 282 } 283 284 return res; 285} 286 287vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { 288 SvcInternal_t *const si = get_svc_internal(svc_ctx); 289 if (svc_ctx == NULL || options == NULL || si == NULL) { 290 return VPX_CODEC_INVALID_PARAM; 291 } 292 strncpy(si->options, options, sizeof(si->options)); 293 si->options[sizeof(si->options) - 1] = '\0'; 294 return VPX_CODEC_OK; 295} 296 297vpx_codec_err_t assign_layer_bitrates(const SvcContext *svc_ctx, 298 vpx_codec_enc_cfg_t *const enc_cfg) { 299 int i; 300 const SvcInternal_t *const si = get_const_svc_internal(svc_ctx); 301 int sl, tl, spatial_layer_target; 302 303 if (svc_ctx->temporal_layering_mode != 0) { 304 if (si->bitrates[0] != 0) { 305 unsigned int total_bitrate = 0; 306 for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { 307 total_bitrate += si->bitrates[sl * svc_ctx->temporal_layers + 308 svc_ctx->temporal_layers - 1]; 309 for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) { 310 enc_cfg->ss_target_bitrate[sl * svc_ctx->temporal_layers] += 311 (unsigned int)si->bitrates[sl * svc_ctx->temporal_layers + tl]; 312 enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + tl] = 313 si->bitrates[sl * svc_ctx->temporal_layers + tl]; 314 if (tl > 0 && (si->bitrates[sl * svc_ctx->temporal_layers + tl] <= 315 si->bitrates[sl * svc_ctx->temporal_layers + tl - 1])) 316 return VPX_CODEC_INVALID_PARAM; 317 } 318 } 319 if (total_bitrate != enc_cfg->rc_target_bitrate) 320 return VPX_CODEC_INVALID_PARAM; 321 } else { 322 float total = 0; 323 float alloc_ratio[VPX_MAX_LAYERS] = { 0 }; 324 325 for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { 326 if (si->svc_params.scaling_factor_den[sl] > 0) { 327 alloc_ratio[sl] = (float)(pow(2, sl)); 328 total += alloc_ratio[sl]; 329 } 330 } 331 332 for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { 333 enc_cfg->ss_target_bitrate[sl] = spatial_layer_target = 334 (unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[sl] / 335 total); 336 if (svc_ctx->temporal_layering_mode == 3) { 337 enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] = 338 (spatial_layer_target * 6) / 10; // 60% 339 enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] = 340 (spatial_layer_target * 8) / 10; // 80% 341 enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 2] = 342 spatial_layer_target; 343 } else if (svc_ctx->temporal_layering_mode == 2 || 344 svc_ctx->temporal_layering_mode == 1) { 345 enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] = 346 spatial_layer_target * 2 / 3; 347 enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] = 348 spatial_layer_target; 349 } else { 350 // User should explicitly assign bitrates in this case. 351 assert(0); 352 } 353 } 354 } 355 } else { 356 if (si->bitrates[0] != 0) { 357 unsigned int total_bitrate = 0; 358 for (i = 0; i < svc_ctx->spatial_layers; ++i) { 359 enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i]; 360 enc_cfg->layer_target_bitrate[i] = (unsigned int)si->bitrates[i]; 361 total_bitrate += si->bitrates[i]; 362 } 363 if (total_bitrate != enc_cfg->rc_target_bitrate) 364 return VPX_CODEC_INVALID_PARAM; 365 } else { 366 float total = 0; 367 float alloc_ratio[VPX_MAX_LAYERS] = { 0 }; 368 369 for (i = 0; i < svc_ctx->spatial_layers; ++i) { 370 if (si->svc_params.scaling_factor_den[i] > 0) { 371 alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 / 372 si->svc_params.scaling_factor_den[i]); 373 374 alloc_ratio[i] *= alloc_ratio[i]; 375 total += alloc_ratio[i]; 376 } 377 } 378 for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) { 379 if (total > 0) { 380 enc_cfg->layer_target_bitrate[i] = 381 (unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[i] / 382 total); 383 } 384 } 385 } 386 } 387 return VPX_CODEC_OK; 388} 389 390vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, 391 vpx_codec_iface_t *iface, 392 vpx_codec_enc_cfg_t *enc_cfg) { 393 vpx_codec_err_t res; 394 int i, sl, tl; 395 SvcInternal_t *const si = get_svc_internal(svc_ctx); 396 if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL || 397 enc_cfg == NULL) { 398 return VPX_CODEC_INVALID_PARAM; 399 } 400 if (si == NULL) return VPX_CODEC_MEM_ERROR; 401 402 si->codec_ctx = codec_ctx; 403 404 si->width = enc_cfg->g_w; 405 si->height = enc_cfg->g_h; 406 407 si->kf_dist = enc_cfg->kf_max_dist; 408 409 if (svc_ctx->spatial_layers == 0) 410 svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; 411 if (svc_ctx->spatial_layers < 1 || 412 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { 413 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", 414 svc_ctx->spatial_layers); 415 return VPX_CODEC_INVALID_PARAM; 416 } 417 418 // Note: temporal_layering_mode only applies to one-pass CBR 419 // si->svc_params.temporal_layering_mode = svc_ctx->temporal_layering_mode; 420 if (svc_ctx->temporal_layering_mode == 3) { 421 svc_ctx->temporal_layers = 3; 422 } else if (svc_ctx->temporal_layering_mode == 2 || 423 svc_ctx->temporal_layering_mode == 1) { 424 svc_ctx->temporal_layers = 2; 425 } 426 427 for (sl = 0; sl < VPX_SS_MAX_LAYERS; ++sl) { 428 si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM[sl]; 429 si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN[sl]; 430 si->svc_params.speed_per_layer[sl] = svc_ctx->speed; 431 } 432 if (enc_cfg->rc_end_usage == VPX_CBR && enc_cfg->g_pass == VPX_RC_ONE_PASS && 433 svc_ctx->spatial_layers <= 3) { 434 for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { 435 int sl2 = (svc_ctx->spatial_layers == 2) ? sl + 1 : sl; 436 si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM_2x[sl2]; 437 si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN_2x[sl2]; 438 } 439 if (svc_ctx->spatial_layers == 1) { 440 si->svc_params.scaling_factor_num[0] = 1; 441 si->svc_params.scaling_factor_den[0] = 1; 442 } 443 } 444 for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) { 445 for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) { 446 i = sl * svc_ctx->temporal_layers + tl; 447 si->svc_params.max_quantizers[i] = MAX_QUANTIZER; 448 si->svc_params.min_quantizers[i] = 0; 449 if (enc_cfg->rc_end_usage == VPX_CBR && 450 enc_cfg->g_pass == VPX_RC_ONE_PASS) { 451 si->svc_params.max_quantizers[i] = 56; 452 si->svc_params.min_quantizers[i] = 2; 453 } 454 } 455 } 456 457 // Parse aggregate command line options. Options must start with 458 // "layers=xx" then followed by other options 459 res = parse_options(svc_ctx, si->options); 460 if (res != VPX_CODEC_OK) return res; 461 462 if (svc_ctx->spatial_layers < 1) svc_ctx->spatial_layers = 1; 463 if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) 464 svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS; 465 466 if (svc_ctx->temporal_layers < 1) svc_ctx->temporal_layers = 1; 467 if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS) 468 svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS; 469 470 if (svc_ctx->temporal_layers * svc_ctx->spatial_layers > VPX_MAX_LAYERS) { 471 svc_log(svc_ctx, SVC_LOG_ERROR, 472 "spatial layers * temporal layers exceeds the maximum number of " 473 "allowed layers of %d\n", 474 svc_ctx->spatial_layers * svc_ctx->temporal_layers, 475 (int)VPX_MAX_LAYERS); 476 return VPX_CODEC_INVALID_PARAM; 477 } 478 res = assign_layer_bitrates(svc_ctx, enc_cfg); 479 if (res != VPX_CODEC_OK) { 480 svc_log(svc_ctx, SVC_LOG_ERROR, 481 "layer bitrates incorrect: \n" 482 "1) spatial layer bitrates should sum up to target \n" 483 "2) temporal layer bitrates should be increasing within \n" 484 "a spatial layer \n"); 485 return VPX_CODEC_INVALID_PARAM; 486 } 487 488#if CONFIG_SPATIAL_SVC 489 for (i = 0; i < svc_ctx->spatial_layers; ++i) 490 enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; 491#endif 492 493 if (svc_ctx->temporal_layers > 1) { 494 int i; 495 for (i = 0; i < svc_ctx->temporal_layers; ++i) { 496 enc_cfg->ts_target_bitrate[i] = 497 enc_cfg->rc_target_bitrate / svc_ctx->temporal_layers; 498 enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i); 499 } 500 } 501 502 if (svc_ctx->threads) enc_cfg->g_threads = svc_ctx->threads; 503 504 // Modify encoder configuration 505 enc_cfg->ss_number_layers = svc_ctx->spatial_layers; 506 enc_cfg->ts_number_layers = svc_ctx->temporal_layers; 507 508 if (enc_cfg->rc_end_usage == VPX_CBR) { 509 enc_cfg->rc_resize_allowed = 0; 510 enc_cfg->rc_min_quantizer = 2; 511 enc_cfg->rc_max_quantizer = 56; 512 enc_cfg->rc_undershoot_pct = 50; 513 enc_cfg->rc_overshoot_pct = 50; 514 enc_cfg->rc_buf_initial_sz = 500; 515 enc_cfg->rc_buf_optimal_sz = 600; 516 enc_cfg->rc_buf_sz = 1000; 517 enc_cfg->rc_dropframe_thresh = 0; 518 } 519 520 if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) 521 enc_cfg->g_error_resilient = 1; 522 523 // Initialize codec 524 res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); 525 if (res != VPX_CODEC_OK) { 526 svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); 527 return res; 528 } 529 if (svc_ctx->spatial_layers > 1 || svc_ctx->temporal_layers > 1) { 530 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); 531 vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params); 532 } 533 return VPX_CODEC_OK; 534} 535 536/** 537 * Encode a frame into multiple layers 538 * Create a superframe containing the individual layers 539 */ 540vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, 541 struct vpx_image *rawimg, vpx_codec_pts_t pts, 542 int64_t duration, int deadline) { 543 vpx_codec_err_t res; 544 vpx_codec_iter_t iter; 545 const vpx_codec_cx_pkt_t *cx_pkt; 546 SvcInternal_t *const si = get_svc_internal(svc_ctx); 547 if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { 548 return VPX_CODEC_INVALID_PARAM; 549 } 550 551 svc_log_reset(svc_ctx); 552 553 res = 554 vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, deadline); 555 if (res != VPX_CODEC_OK) { 556 return res; 557 } 558 // save compressed data 559 iter = NULL; 560 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { 561 switch (cx_pkt->kind) { 562#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) 563#if CONFIG_SPATIAL_SVC 564 case VPX_CODEC_SPATIAL_SVC_LAYER_PSNR: { 565 int i; 566 for (i = 0; i < svc_ctx->spatial_layers; ++i) { 567 int j; 568 svc_log(svc_ctx, SVC_LOG_DEBUG, 569 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " 570 "%2.3f %2.3f %2.3f %2.3f \n", 571 si->psnr_pkt_received, i, cx_pkt->data.layer_psnr[i].psnr[0], 572 cx_pkt->data.layer_psnr[i].psnr[1], 573 cx_pkt->data.layer_psnr[i].psnr[2], 574 cx_pkt->data.layer_psnr[i].psnr[3]); 575 svc_log(svc_ctx, SVC_LOG_DEBUG, 576 "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " 577 "%2.3f %2.3f %2.3f %2.3f \n", 578 si->psnr_pkt_received, i, cx_pkt->data.layer_psnr[i].sse[0], 579 cx_pkt->data.layer_psnr[i].sse[1], 580 cx_pkt->data.layer_psnr[i].sse[2], 581 cx_pkt->data.layer_psnr[i].sse[3]); 582 583 for (j = 0; j < COMPONENTS; ++j) { 584 si->psnr_sum[i][j] += cx_pkt->data.layer_psnr[i].psnr[j]; 585 si->sse_sum[i][j] += cx_pkt->data.layer_psnr[i].sse[j]; 586 } 587 } 588 ++si->psnr_pkt_received; 589 break; 590 } 591 case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: { 592 int i; 593 for (i = 0; i < svc_ctx->spatial_layers; ++i) 594 si->bytes_sum[i] += cx_pkt->data.layer_sizes[i]; 595 break; 596 } 597#endif 598#endif 599 case VPX_CODEC_PSNR_PKT: { 600#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION) 601 int j; 602 svc_log(svc_ctx, SVC_LOG_DEBUG, 603 "frame: %d, layer: %d, PSNR(Total/Y/U/V): " 604 "%2.3f %2.3f %2.3f %2.3f \n", 605 si->psnr_pkt_received, 0, cx_pkt->data.layer_psnr[0].psnr[0], 606 cx_pkt->data.layer_psnr[0].psnr[1], 607 cx_pkt->data.layer_psnr[0].psnr[2], 608 cx_pkt->data.layer_psnr[0].psnr[3]); 609 for (j = 0; j < COMPONENTS; ++j) { 610 si->psnr_sum[0][j] += cx_pkt->data.layer_psnr[0].psnr[j]; 611 si->sse_sum[0][j] += cx_pkt->data.layer_psnr[0].sse[j]; 612 } 613#endif 614 } 615 ++si->psnr_pkt_received; 616 break; 617 default: { break; } 618 } 619 } 620 621 return VPX_CODEC_OK; 622} 623 624const char *vpx_svc_get_message(const SvcContext *svc_ctx) { 625 const SvcInternal_t *const si = get_const_svc_internal(svc_ctx); 626 if (svc_ctx == NULL || si == NULL) return NULL; 627 return si->message_buffer; 628} 629 630static double calc_psnr(double d) { 631 if (d == 0) return 100; 632 return -10.0 * log(d) / log(10.0); 633} 634 635// dump accumulated statistics and reset accumulated values 636const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { 637 int number_of_frames; 638 int i, j; 639 uint32_t bytes_total = 0; 640 double scale[COMPONENTS]; 641 double psnr[COMPONENTS]; 642 double mse[COMPONENTS]; 643 double y_scale; 644 645 SvcInternal_t *const si = get_svc_internal(svc_ctx); 646 if (svc_ctx == NULL || si == NULL) return NULL; 647 648 svc_log_reset(svc_ctx); 649 650 number_of_frames = si->psnr_pkt_received; 651 if (number_of_frames <= 0) return vpx_svc_get_message(svc_ctx); 652 653 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); 654 for (i = 0; i < svc_ctx->spatial_layers; ++i) { 655 svc_log(svc_ctx, SVC_LOG_INFO, 656 "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", 657 i, (double)si->psnr_sum[i][0] / number_of_frames, 658 (double)si->psnr_sum[i][1] / number_of_frames, 659 (double)si->psnr_sum[i][2] / number_of_frames, 660 (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); 661 // the following psnr calculation is deduced from ffmpeg.c#print_report 662 y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; 663 scale[1] = y_scale; 664 scale[2] = scale[3] = y_scale / 4; // U or V 665 scale[0] = y_scale * 1.5; // total 666 667 for (j = 0; j < COMPONENTS; j++) { 668 psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]); 669 mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j]; 670 } 671 svc_log(svc_ctx, SVC_LOG_INFO, 672 "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0], 673 psnr[1], psnr[2], psnr[3]); 674 svc_log(svc_ctx, SVC_LOG_INFO, 675 "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0], 676 mse[1], mse[2], mse[3]); 677 678 bytes_total += si->bytes_sum[i]; 679 // Clear sums for next time. 680 si->bytes_sum[i] = 0; 681 for (j = 0; j < COMPONENTS; ++j) { 682 si->psnr_sum[i][j] = 0; 683 si->sse_sum[i][j] = 0; 684 } 685 } 686 687 // only display statistics once 688 si->psnr_pkt_received = 0; 689 690 svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); 691 return vpx_svc_get_message(svc_ctx); 692} 693 694void vpx_svc_release(SvcContext *svc_ctx) { 695 SvcInternal_t *si; 696 if (svc_ctx == NULL) return; 697 // do not use get_svc_internal as it will unnecessarily allocate an 698 // SvcInternal_t if it was not already allocated 699 si = (SvcInternal_t *)svc_ctx->internal; 700 if (si != NULL) { 701 free(si); 702 svc_ctx->internal = NULL; 703 } 704} 705