| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 /** | 11 /** |
| 12 * @file | 12 * @file |
| 13 * VP9 SVC encoding support via libvpx | 13 * VP9 SVC encoding support via libvpx |
| 14 */ | 14 */ |
| 15 | 15 |
| 16 #include <math.h> |
| 16 #include <stdarg.h> | 17 #include <stdarg.h> |
| 17 #include <stdio.h> | 18 #include <stdio.h> |
| 18 #include <stdlib.h> | 19 #include <stdlib.h> |
| 19 #include <string.h> | 20 #include <string.h> |
| 20 #define VPX_DISABLE_CTRL_TYPECHECKS 1 | 21 #define VPX_DISABLE_CTRL_TYPECHECKS 1 |
| 21 #define VPX_CODEC_DISABLE_COMPAT 1 | 22 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 22 #include "vpx/svc_context.h" | 23 #include "vpx/svc_context.h" |
| 23 #include "vpx/vp8cx.h" | 24 #include "vpx/vp8cx.h" |
| 24 #include "vpx/vpx_encoder.h" | 25 #include "vpx/vpx_encoder.h" |
| 25 | 26 |
| 26 #if defined(__MINGW32__) && !defined(MINGW_HAS_SECURE_API) | 27 #ifdef __MINGW32__ |
| 27 #define strtok_r strtok_s | 28 #define strtok_r strtok_s |
| 29 #ifndef MINGW_HAS_SECURE_API |
| 28 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h | 30 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h |
| 29 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); | 31 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); |
| 30 #endif | 32 #endif /* MINGW_HAS_SECURE_API */ |
| 33 #endif /* __MINGW32__ */ |
| 31 | 34 |
| 32 #ifdef _MSC_VER | 35 #ifdef _MSC_VER |
| 33 #define strdup _strdup | 36 #define strdup _strdup |
| 34 #define strtok_r strtok_s | 37 #define strtok_r strtok_s |
| 35 #endif | 38 #endif |
| 36 | 39 |
| 37 #define SVC_REFERENCE_FRAMES 8 | 40 #define SVC_REFERENCE_FRAMES 8 |
| 38 #define SUPERFRAME_SLOTS (8) | 41 #define SUPERFRAME_SLOTS (8) |
| 39 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) | 42 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) |
| 40 #define OPTION_BUFFER_SIZE 256 | 43 #define OPTION_BUFFER_SIZE 256 |
| 44 #define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v |
| 41 | 45 |
| 42 static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27"; | 46 static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27"; |
| 43 static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; | 47 static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; |
| 44 | 48 |
| 45 typedef struct SvcInternal { | 49 typedef struct SvcInternal { |
| 46 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options | 50 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options |
| 47 char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers | 51 char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers |
| 52 char quantizers_keyframe[OPTION_BUFFER_SIZE]; // set by |
| 53 // vpx_svc_set_quantizers |
| 48 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors | 54 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors |
| 49 | 55 |
| 50 // values extracted from option, quantizers | 56 // values extracted from option, quantizers |
| 51 int scaling_factor_num[VPX_SS_MAX_LAYERS]; | 57 int scaling_factor_num[VPX_SS_MAX_LAYERS]; |
| 52 int scaling_factor_den[VPX_SS_MAX_LAYERS]; | 58 int scaling_factor_den[VPX_SS_MAX_LAYERS]; |
| 59 int quantizer_keyframe[VPX_SS_MAX_LAYERS]; |
| 53 int quantizer[VPX_SS_MAX_LAYERS]; | 60 int quantizer[VPX_SS_MAX_LAYERS]; |
| 54 | 61 |
| 55 // accumulated statistics | 62 // accumulated statistics |
| 56 double psnr_in_layer[VPX_SS_MAX_LAYERS]; | 63 double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V |
| 57 uint32_t bytes_in_layer[VPX_SS_MAX_LAYERS]; | 64 uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; |
| 65 uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; |
| 58 | 66 |
| 59 // codec encoding values | 67 // codec encoding values |
| 60 int width; // width of highest layer | 68 int width; // width of highest layer |
| 61 int height; // height of highest layer | 69 int height; // height of highest layer |
| 62 int kf_dist; // distance between keyframes | 70 int kf_dist; // distance between keyframes |
| 63 | 71 |
| 64 // state variables | 72 // state variables |
| 65 int encode_frame_count; | 73 int encode_frame_count; |
| 66 int frame_within_gop; | 74 int frame_within_gop; |
| 67 vpx_enc_frame_flags_t enc_frame_flags; | 75 vpx_enc_frame_flags_t enc_frame_flags; |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 } else if (strcmp(value_str, "gf") == 0) { | 267 } else if (strcmp(value_str, "gf") == 0) { |
| 260 svc_ctx->encoding_mode = USE_GOLDEN_FRAME; | 268 svc_ctx->encoding_mode = USE_GOLDEN_FRAME; |
| 261 } else { | 269 } else { |
| 262 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str); | 270 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str); |
| 263 return VPX_CODEC_INVALID_PARAM; | 271 return VPX_CODEC_INVALID_PARAM; |
| 264 } | 272 } |
| 265 return VPX_CODEC_OK; | 273 return VPX_CODEC_OK; |
| 266 } | 274 } |
| 267 | 275 |
| 268 static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, | 276 static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, |
| 269 const char *quantizer_values) { | 277 const char *quantizer_values, |
| 278 const int is_keyframe) { |
| 270 char *input_string; | 279 char *input_string; |
| 271 char *token; | 280 char *token; |
| 272 const char *delim = ","; | 281 const char *delim = ","; |
| 273 char *save_ptr; | 282 char *save_ptr; |
| 274 int found = 0; | 283 int found = 0; |
| 275 int i, q; | 284 int i, q; |
| 276 vpx_codec_err_t res = VPX_CODEC_OK; | 285 vpx_codec_err_t res = VPX_CODEC_OK; |
| 277 SvcInternal *const si = get_svc_internal(svc_ctx); | 286 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 278 | 287 |
| 279 if (quantizer_values == NULL || strlen(quantizer_values) == 0) { | 288 if (quantizer_values == NULL || strlen(quantizer_values) == 0) { |
| 289 if (is_keyframe) { |
| 290 // If there non settings for key frame, we will apply settings from |
| 291 // non key frame. So just simply return here. |
| 292 return VPX_CODEC_INVALID_PARAM; |
| 293 } |
| 280 input_string = strdup(DEFAULT_QUANTIZER_VALUES); | 294 input_string = strdup(DEFAULT_QUANTIZER_VALUES); |
| 281 } else { | 295 } else { |
| 282 input_string = strdup(quantizer_values); | 296 input_string = strdup(quantizer_values); |
| 283 } | 297 } |
| 284 | 298 |
| 285 token = strtok_r(input_string, delim, &save_ptr); | 299 token = strtok_r(input_string, delim, &save_ptr); |
| 286 for (i = 0; i < svc_ctx->spatial_layers; ++i) { | 300 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
| 287 if (token != NULL) { | 301 if (token != NULL) { |
| 288 q = atoi(token); | 302 q = atoi(token); |
| 289 if (q <= 0 || q > 100) { | 303 if (q <= 0 || q > 100) { |
| 290 svc_log(svc_ctx, SVC_LOG_ERROR, | 304 svc_log(svc_ctx, SVC_LOG_ERROR, |
| 291 "svc-quantizer-values: invalid value %s\n", token); | 305 "svc-quantizer-values: invalid value %s\n", token); |
| 292 res = VPX_CODEC_INVALID_PARAM; | 306 res = VPX_CODEC_INVALID_PARAM; |
| 293 break; | 307 break; |
| 294 } | 308 } |
| 295 token = strtok_r(NULL, delim, &save_ptr); | 309 token = strtok_r(NULL, delim, &save_ptr); |
| 296 found = i + 1; | 310 found = i + 1; |
| 297 } else { | 311 } else { |
| 298 q = 0; | 312 q = 0; |
| 299 } | 313 } |
| 300 si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; | 314 if (is_keyframe) { |
| 315 si->quantizer_keyframe[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] |
| 316 = q; |
| 317 } else { |
| 318 si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; |
| 319 } |
| 301 } | 320 } |
| 302 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { | 321 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { |
| 303 svc_log(svc_ctx, SVC_LOG_ERROR, | 322 svc_log(svc_ctx, SVC_LOG_ERROR, |
| 304 "svc: quantizers: %d values required, but only %d specified\n", | 323 "svc: quantizers: %d values required, but only %d specified\n", |
| 305 svc_ctx->spatial_layers, found); | 324 svc_ctx->spatial_layers, found); |
| 306 res = VPX_CODEC_INVALID_PARAM; | 325 res = VPX_CODEC_INVALID_PARAM; |
| 307 } | 326 } |
| 308 free(input_string); | 327 free(input_string); |
| 309 return res; | 328 return res; |
| 310 } | 329 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 * Format: encoding-mode=<svc_mode>,layers=<layer_count> | 394 * Format: encoding-mode=<svc_mode>,layers=<layer_count> |
| 376 * scale-factors=<n1>/<d1>,<n2>/<d2>,... | 395 * scale-factors=<n1>/<d1>,<n2>/<d2>,... |
| 377 * quantizers=<q1>,<q2>,... | 396 * quantizers=<q1>,<q2>,... |
| 378 * svc_mode = [i|ip|alt_ip|gf] | 397 * svc_mode = [i|ip|alt_ip|gf] |
| 379 */ | 398 */ |
| 380 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { | 399 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { |
| 381 char *input_string; | 400 char *input_string; |
| 382 char *option_name; | 401 char *option_name; |
| 383 char *option_value; | 402 char *option_value; |
| 384 char *input_ptr; | 403 char *input_ptr; |
| 404 int is_keyframe_qaunt_set = 0; |
| 385 vpx_codec_err_t res = VPX_CODEC_OK; | 405 vpx_codec_err_t res = VPX_CODEC_OK; |
| 386 | 406 |
| 387 if (options == NULL) return VPX_CODEC_OK; | 407 if (options == NULL) return VPX_CODEC_OK; |
| 388 input_string = strdup(options); | 408 input_string = strdup(options); |
| 389 | 409 |
| 390 // parse option name | 410 // parse option name |
| 391 option_name = strtok_r(input_string, "=", &input_ptr); | 411 option_name = strtok_r(input_string, "=", &input_ptr); |
| 392 while (option_name != NULL) { | 412 while (option_name != NULL) { |
| 393 // parse option value | 413 // parse option value |
| 394 option_value = strtok_r(NULL, " ", &input_ptr); | 414 option_value = strtok_r(NULL, " ", &input_ptr); |
| 395 if (option_value == NULL) { | 415 if (option_value == NULL) { |
| 396 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", | 416 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", |
| 397 option_name); | 417 option_name); |
| 398 res = VPX_CODEC_INVALID_PARAM; | 418 res = VPX_CODEC_INVALID_PARAM; |
| 399 break; | 419 break; |
| 400 } | 420 } |
| 401 if (strcmp("encoding-mode", option_name) == 0) { | 421 if (strcmp("encoding-mode", option_name) == 0) { |
| 402 res = set_option_encoding_mode(svc_ctx, option_value); | 422 res = set_option_encoding_mode(svc_ctx, option_value); |
| 403 if (res != VPX_CODEC_OK) break; | 423 if (res != VPX_CODEC_OK) break; |
| 404 } else if (strcmp("layers", option_name) == 0) { | 424 } else if (strcmp("layers", option_name) == 0) { |
| 405 svc_ctx->spatial_layers = atoi(option_value); | 425 svc_ctx->spatial_layers = atoi(option_value); |
| 406 } else if (strcmp("scale-factors", option_name) == 0) { | 426 } else if (strcmp("scale-factors", option_name) == 0) { |
| 407 res = parse_scale_factors(svc_ctx, option_value); | 427 res = parse_scale_factors(svc_ctx, option_value); |
| 408 if (res != VPX_CODEC_OK) break; | 428 if (res != VPX_CODEC_OK) break; |
| 409 } else if (strcmp("quantizers", option_name) == 0) { | 429 } else if (strcmp("quantizers", option_name) == 0) { |
| 410 res = parse_quantizer_values(svc_ctx, option_value); | 430 res = parse_quantizer_values(svc_ctx, option_value, 0); |
| 411 if (res != VPX_CODEC_OK) break; | 431 if (res != VPX_CODEC_OK) break; |
| 432 if (!is_keyframe_qaunt_set) { |
| 433 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 434 memcpy(get_svc_internal(svc_ctx)->quantizer_keyframe, si->quantizer, |
| 435 sizeof(si->quantizer)); |
| 436 } |
| 437 } else if (strcmp("quantizers-keyframe", option_name) == 0) { |
| 438 res = parse_quantizer_values(svc_ctx, option_value, 1); |
| 439 if (res != VPX_CODEC_OK) break; |
| 440 is_keyframe_qaunt_set = 1; |
| 412 } else { | 441 } else { |
| 413 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); | 442 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); |
| 414 res = VPX_CODEC_INVALID_PARAM; | 443 res = VPX_CODEC_INVALID_PARAM; |
| 415 break; | 444 break; |
| 416 } | 445 } |
| 417 option_name = strtok_r(NULL, "=", &input_ptr); | 446 option_name = strtok_r(NULL, "=", &input_ptr); |
| 418 } | 447 } |
| 419 free(input_string); | 448 free(input_string); |
| 420 return res; | 449 return res; |
| 421 } | 450 } |
| 422 | 451 |
| 423 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { | 452 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { |
| 424 SvcInternal *const si = get_svc_internal(svc_ctx); | 453 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 425 if (svc_ctx == NULL || options == NULL || si == NULL) { | 454 if (svc_ctx == NULL || options == NULL || si == NULL) { |
| 426 return VPX_CODEC_INVALID_PARAM; | 455 return VPX_CODEC_INVALID_PARAM; |
| 427 } | 456 } |
| 428 strncpy(si->options, options, sizeof(si->options)); | 457 strncpy(si->options, options, sizeof(si->options)); |
| 429 si->options[sizeof(si->options) - 1] = '\0'; | 458 si->options[sizeof(si->options) - 1] = '\0'; |
| 430 return VPX_CODEC_OK; | 459 return VPX_CODEC_OK; |
| 431 } | 460 } |
| 432 | 461 |
| 433 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, | 462 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, |
| 434 const char *quantizers) { | 463 const char *quantizers, |
| 464 const int is_for_keyframe) { |
| 435 SvcInternal *const si = get_svc_internal(svc_ctx); | 465 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 436 if (svc_ctx == NULL || quantizers == NULL || si == NULL) { | 466 if (svc_ctx == NULL || quantizers == NULL || si == NULL) { |
| 437 return VPX_CODEC_INVALID_PARAM; | 467 return VPX_CODEC_INVALID_PARAM; |
| 438 } | 468 } |
| 439 strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); | 469 if (is_for_keyframe) { |
| 440 si->quantizers[sizeof(si->quantizers) - 1] = '\0'; | 470 strncpy(si->quantizers_keyframe, quantizers, sizeof(si->quantizers)); |
| 471 si->quantizers_keyframe[sizeof(si->quantizers_keyframe) - 1] = '\0'; |
| 472 } else { |
| 473 strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); |
| 474 si->quantizers[sizeof(si->quantizers) - 1] = '\0'; |
| 475 } |
| 441 return VPX_CODEC_OK; | 476 return VPX_CODEC_OK; |
| 442 } | 477 } |
| 443 | 478 |
| 444 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx, | 479 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx, |
| 445 const char *scale_factors) { | 480 const char *scale_factors) { |
| 446 SvcInternal *const si = get_svc_internal(svc_ctx); | 481 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 447 if (svc_ctx == NULL || scale_factors == NULL || si == NULL) { | 482 if (svc_ctx == NULL || scale_factors == NULL || si == NULL) { |
| 448 return VPX_CODEC_INVALID_PARAM; | 483 return VPX_CODEC_INVALID_PARAM; |
| 449 } | 484 } |
| 450 strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors)); | 485 strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors)); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 481 if (svc_ctx->spatial_layers < 1 || | 516 if (svc_ctx->spatial_layers < 1 || |
| 482 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { | 517 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { |
| 483 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", | 518 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", |
| 484 svc_ctx->spatial_layers); | 519 svc_ctx->spatial_layers); |
| 485 return VPX_CODEC_INVALID_PARAM; | 520 return VPX_CODEC_INVALID_PARAM; |
| 486 } | 521 } |
| 487 // use SvcInternal value for number of layers to enable forcing single layer | 522 // use SvcInternal value for number of layers to enable forcing single layer |
| 488 // for first frame | 523 // for first frame |
| 489 si->layers = svc_ctx->spatial_layers; | 524 si->layers = svc_ctx->spatial_layers; |
| 490 | 525 |
| 491 res = parse_quantizer_values(svc_ctx, si->quantizers); | 526 res = parse_quantizer_values(svc_ctx, si->quantizers, 0); |
| 492 if (res != VPX_CODEC_OK) return res; | 527 if (res != VPX_CODEC_OK) return res; |
| 493 | 528 |
| 529 res = parse_quantizer_values(svc_ctx, si->quantizers_keyframe, 1); |
| 530 if (res != VPX_CODEC_OK) |
| 531 memcpy(si->quantizer_keyframe, si->quantizer, sizeof(si->quantizer)); |
| 532 |
| 494 res = parse_scale_factors(svc_ctx, si->scale_factors); | 533 res = parse_scale_factors(svc_ctx, si->scale_factors); |
| 495 if (res != VPX_CODEC_OK) return res; | 534 if (res != VPX_CODEC_OK) return res; |
| 496 | 535 |
| 497 // parse aggregate command line options | 536 // parse aggregate command line options |
| 498 res = parse_options(svc_ctx, si->options); | 537 res = parse_options(svc_ctx, si->options); |
| 499 if (res != VPX_CODEC_OK) return res; | 538 if (res != VPX_CODEC_OK) return res; |
| 500 | 539 |
| 540 // Assign target bitrate for each layer. We calculate the ratio |
| 541 // from the resolution for now. |
| 542 // TODO(Minghai): Optimize the mechanism of allocating bits after |
| 543 // implementing svc two pass rate control. |
| 544 if (si->layers > 1) { |
| 545 int i; |
| 546 float total = 0; |
| 547 float alloc_ratio[VPX_SS_MAX_LAYERS] = {0}; |
| 548 |
| 549 for (i = 0; i < si->layers; ++i) { |
| 550 int pos = i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers; |
| 551 if (pos < VPX_SS_MAX_LAYERS && si->scaling_factor_den[pos] > 0) { |
| 552 alloc_ratio[i] = (float)(si->scaling_factor_num[pos] * 1.0 / |
| 553 si->scaling_factor_den[pos]); |
| 554 |
| 555 alloc_ratio[i] *= alloc_ratio[i]; |
| 556 total += alloc_ratio[i]; |
| 557 } |
| 558 } |
| 559 |
| 560 for (i = 0; i < si->layers; ++i) { |
| 561 if (total > 0) { |
| 562 enc_cfg->ss_target_bitrate[i] = (unsigned int) |
| 563 (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); |
| 564 } |
| 565 } |
| 566 } |
| 567 |
| 501 // modify encoder configuration | 568 // modify encoder configuration |
| 502 enc_cfg->ss_number_layers = si->layers; | 569 enc_cfg->ss_number_layers = si->layers; |
| 503 enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder. | 570 enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder. |
| 504 enc_cfg->kf_mode = VPX_KF_DISABLED; | 571 enc_cfg->kf_mode = VPX_KF_DISABLED; |
| 505 enc_cfg->g_pass = VPX_RC_ONE_PASS; | 572 enc_cfg->g_pass = VPX_RC_ONE_PASS; |
| 506 // Lag in frames not currently supported | 573 // Lag in frames not currently supported |
| 507 enc_cfg->g_lag_in_frames = 0; | 574 enc_cfg->g_lag_in_frames = 0; |
| 508 | 575 |
| 509 // TODO(ivanmaltz): determine if these values need to be set explicitly for | 576 // TODO(ivanmaltz): determine if these values need to be set explicitly for |
| 510 // svc, or if the normal default/override mechanism can be used | 577 // svc, or if the normal default/override mechanism can be used |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 if (layer == 0 || layer == 2) { | 771 if (layer == 0 || layer == 2) { |
| 705 layer += 1; | 772 layer += 1; |
| 706 } | 773 } |
| 707 } | 774 } |
| 708 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer, | 775 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer, |
| 709 &svc_params.width, | 776 &svc_params.width, |
| 710 &svc_params.height)) { | 777 &svc_params.height)) { |
| 711 svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); | 778 svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); |
| 712 } | 779 } |
| 713 layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; | 780 layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; |
| 714 svc_params.min_quantizer = si->quantizer[layer_index]; | 781 |
| 715 svc_params.max_quantizer = si->quantizer[layer_index]; | 782 if (vpx_svc_is_keyframe(svc_ctx)) { |
| 783 svc_params.min_quantizer = si->quantizer_keyframe[layer_index]; |
| 784 svc_params.max_quantizer = si->quantizer_keyframe[layer_index]; |
| 785 } else { |
| 786 svc_params.min_quantizer = si->quantizer[layer_index]; |
| 787 svc_params.max_quantizer = si->quantizer[layer_index]; |
| 788 } |
| 789 |
| 716 svc_params.distance_from_i_frame = si->frame_within_gop; | 790 svc_params.distance_from_i_frame = si->frame_within_gop; |
| 717 | 791 |
| 718 // Use buffer i for layer i LST | 792 // Use buffer i for layer i LST |
| 719 svc_params.lst_fb_idx = si->layer; | 793 svc_params.lst_fb_idx = si->layer; |
| 720 | 794 |
| 721 // Use buffer i-1 for layer i Alt (Inter-layer prediction) | 795 // Use buffer i-1 for layer i Alt (Inter-layer prediction) |
| 722 if (si->layer != 0) { | 796 if (si->layer != 0) { |
| 723 const int use_higher_layer = | 797 const int use_higher_layer = |
| 724 svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && | 798 svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && |
| 725 si->frame_within_gop == 0; | 799 si->frame_within_gop == 0; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 si->enc_frame_flags, deadline); | 879 si->enc_frame_flags, deadline); |
| 806 if (res != VPX_CODEC_OK) { | 880 if (res != VPX_CODEC_OK) { |
| 807 return res; | 881 return res; |
| 808 } | 882 } |
| 809 // save compressed data | 883 // save compressed data |
| 810 iter = NULL; | 884 iter = NULL; |
| 811 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { | 885 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { |
| 812 switch (cx_pkt->kind) { | 886 switch (cx_pkt->kind) { |
| 813 case VPX_CODEC_CX_FRAME_PKT: { | 887 case VPX_CODEC_CX_FRAME_PKT: { |
| 814 const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz); | 888 const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz); |
| 815 si->bytes_in_layer[si->layer] += frame_pkt_size; | 889 si->bytes_sum[si->layer] += frame_pkt_size; |
| 816 svc_log(svc_ctx, SVC_LOG_DEBUG, | 890 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 817 "SVC frame: %d, layer: %d, size: %u\n", | 891 "SVC frame: %d, layer: %d, size: %u\n", |
| 818 si->encode_frame_count, si->layer, frame_pkt_size); | 892 si->encode_frame_count, si->layer, frame_pkt_size); |
| 819 layer_data = | 893 layer_data = |
| 820 ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size); | 894 ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size); |
| 821 if (layer_data == NULL) { | 895 if (layer_data == NULL) { |
| 822 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n"); | 896 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n"); |
| 823 return VPX_CODEC_OK; | 897 return VPX_CODEC_OK; |
| 824 } | 898 } |
| 825 ld_list_add(&cx_layer_list, layer_data); | 899 ld_list_add(&cx_layer_list, layer_data); |
| 826 | 900 |
| 827 // save layer size in superframe index | 901 // save layer size in superframe index |
| 828 superframe.sizes[superframe.count++] = frame_pkt_size; | 902 superframe.sizes[superframe.count++] = frame_pkt_size; |
| 829 superframe.magnitude |= frame_pkt_size; | 903 superframe.magnitude |= frame_pkt_size; |
| 830 break; | 904 break; |
| 831 } | 905 } |
| 832 case VPX_CODEC_PSNR_PKT: { | 906 case VPX_CODEC_PSNR_PKT: { |
| 907 int i; |
| 833 svc_log(svc_ctx, SVC_LOG_DEBUG, | 908 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 834 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " | 909 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " |
| 835 "%2.3f %2.3f %2.3f %2.3f \n", | 910 "%2.3f %2.3f %2.3f %2.3f \n", |
| 836 si->encode_frame_count, si->layer, | 911 si->encode_frame_count, si->layer, |
| 837 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1], | 912 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1], |
| 838 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]); | 913 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]); |
| 839 si->psnr_in_layer[si->layer] += cx_pkt->data.psnr.psnr[0]; | 914 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 915 "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " |
| 916 "%2.3f %2.3f %2.3f %2.3f \n", |
| 917 si->encode_frame_count, si->layer, |
| 918 cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1], |
| 919 cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]); |
| 920 for (i = 0; i < COMPONENTS; i++) { |
| 921 si->psnr_sum[si->layer][i] += cx_pkt->data.psnr.psnr[i]; |
| 922 si->sse_sum[si->layer][i] += cx_pkt->data.psnr.sse[i]; |
| 923 } |
| 840 break; | 924 break; |
| 841 } | 925 } |
| 842 default: { | 926 default: { |
| 843 break; | 927 break; |
| 844 } | 928 } |
| 845 } | 929 } |
| 846 } | 930 } |
| 847 } | 931 } |
| 848 // add superframe index to layer data list | 932 // add superframe index to layer data list |
| 849 sf_create_index(&superframe); | 933 sf_create_index(&superframe); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 if (svc_ctx == NULL || si == NULL) return 0; | 991 if (svc_ctx == NULL || si == NULL) return 0; |
| 908 return si->is_keyframe; | 992 return si->is_keyframe; |
| 909 } | 993 } |
| 910 | 994 |
| 911 void vpx_svc_set_keyframe(SvcContext *svc_ctx) { | 995 void vpx_svc_set_keyframe(SvcContext *svc_ctx) { |
| 912 SvcInternal *const si = get_svc_internal(svc_ctx); | 996 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 913 if (svc_ctx == NULL || si == NULL) return; | 997 if (svc_ctx == NULL || si == NULL) return; |
| 914 si->frame_within_gop = 0; | 998 si->frame_within_gop = 0; |
| 915 } | 999 } |
| 916 | 1000 |
| 1001 static double calc_psnr(double d) { |
| 1002 if (d == 0) return 100; |
| 1003 return -10.0 * log(d) / log(10.0); |
| 1004 } |
| 1005 |
| 917 // dump accumulated statistics and reset accumulated values | 1006 // dump accumulated statistics and reset accumulated values |
| 918 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { | 1007 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { |
| 919 int number_of_frames, number_of_keyframes, encode_frame_count; | 1008 int number_of_frames, number_of_keyframes, encode_frame_count; |
| 920 int i; | 1009 int i, j; |
| 921 uint32_t bytes_total = 0; | 1010 uint32_t bytes_total = 0; |
| 1011 double scale[COMPONENTS]; |
| 1012 double psnr[COMPONENTS]; |
| 1013 double mse[COMPONENTS]; |
| 1014 double y_scale; |
| 1015 |
| 922 SvcInternal *const si = get_svc_internal(svc_ctx); | 1016 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 923 if (svc_ctx == NULL || si == NULL) return NULL; | 1017 if (svc_ctx == NULL || si == NULL) return NULL; |
| 924 | 1018 |
| 925 svc_log_reset(svc_ctx); | 1019 svc_log_reset(svc_ctx); |
| 926 | 1020 |
| 927 encode_frame_count = si->encode_frame_count; | 1021 encode_frame_count = si->encode_frame_count; |
| 928 if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); | 1022 if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); |
| 929 | 1023 |
| 930 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); | 1024 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); |
| 931 number_of_keyframes = encode_frame_count / si->kf_dist + 1; | 1025 number_of_keyframes = encode_frame_count / si->kf_dist + 1; |
| 932 for (i = 0; i < si->layers; ++i) { | 1026 for (i = 0; i < si->layers; ++i) { |
| 933 number_of_frames = encode_frame_count; | 1027 number_of_frames = encode_frame_count; |
| 934 | 1028 |
| 935 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && | 1029 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && |
| 936 (i == 1 || i == 3)) { | 1030 (i == 1 || i == 3)) { |
| 937 number_of_frames -= number_of_keyframes; | 1031 number_of_frames -= number_of_keyframes; |
| 938 } | 1032 } |
| 939 svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d PSNR=[%2.3f], Bytes=[%u]\n", i, | 1033 svc_log(svc_ctx, SVC_LOG_INFO, |
| 940 (double)si->psnr_in_layer[i] / number_of_frames, | 1034 "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", |
| 941 si->bytes_in_layer[i]); | 1035 i, (double)si->psnr_sum[i][0] / number_of_frames, |
| 942 bytes_total += si->bytes_in_layer[i]; | 1036 (double)si->psnr_sum[i][1] / number_of_frames, |
| 943 si->psnr_in_layer[i] = 0; | 1037 (double)si->psnr_sum[i][2] / number_of_frames, |
| 944 si->bytes_in_layer[i] = 0; | 1038 (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); |
| 1039 // the following psnr calculation is deduced from ffmpeg.c#print_report |
| 1040 y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; |
| 1041 scale[1] = y_scale; |
| 1042 scale[2] = scale[3] = y_scale / 4; // U or V |
| 1043 scale[0] = y_scale * 1.5; // total |
| 1044 |
| 1045 for (j = 0; j < COMPONENTS; j++) { |
| 1046 psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]); |
| 1047 mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j]; |
| 1048 } |
| 1049 svc_log(svc_ctx, SVC_LOG_INFO, |
| 1050 "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0], |
| 1051 psnr[1], psnr[2], psnr[3]); |
| 1052 svc_log(svc_ctx, SVC_LOG_INFO, |
| 1053 "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0], |
| 1054 mse[1], mse[2], mse[3]); |
| 1055 |
| 1056 bytes_total += si->bytes_sum[i]; |
| 1057 // clear sums for next time |
| 1058 si->bytes_sum[i] = 0; |
| 1059 for (j = 0; j < COMPONENTS; ++j) { |
| 1060 si->psnr_sum[i][j] = 0; |
| 1061 si->sse_sum[i][j] = 0; |
| 1062 } |
| 945 } | 1063 } |
| 946 | 1064 |
| 947 // only display statistics once | 1065 // only display statistics once |
| 948 si->encode_frame_count = 0; | 1066 si->encode_frame_count = 0; |
| 949 | 1067 |
| 950 svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); | 1068 svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); |
| 951 return vpx_svc_get_message(svc_ctx); | 1069 return vpx_svc_get_message(svc_ctx); |
| 952 } | 1070 } |
| 953 | 1071 |
| 954 void vpx_svc_release(SvcContext *svc_ctx) { | 1072 void vpx_svc_release(SvcContext *svc_ctx) { |
| 955 SvcInternal *si; | 1073 SvcInternal *si; |
| 956 if (svc_ctx == NULL) return; | 1074 if (svc_ctx == NULL) return; |
| 957 // do not use get_svc_internal as it will unnecessarily allocate an | 1075 // do not use get_svc_internal as it will unnecessarily allocate an |
| 958 // SvcInternal if it was not already allocated | 1076 // SvcInternal if it was not already allocated |
| 959 si = (SvcInternal *)svc_ctx->internal; | 1077 si = (SvcInternal *)svc_ctx->internal; |
| 960 if (si != NULL) { | 1078 if (si != NULL) { |
| 961 free(si->buffer); | 1079 free(si->buffer); |
| 962 free(si); | 1080 free(si); |
| 963 svc_ctx->internal = NULL; | 1081 svc_ctx->internal = NULL; |
| 964 } | 1082 } |
| 965 } | 1083 } |
| OLD | NEW |