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 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 int height; // height of highest layer | 79 int height; // height of highest layer |
80 int kf_dist; // distance between keyframes | 80 int kf_dist; // distance between keyframes |
81 | 81 |
82 // state variables | 82 // state variables |
83 int encode_frame_count; | 83 int encode_frame_count; |
84 int frame_received; | 84 int frame_received; |
85 int frame_within_gop; | 85 int frame_within_gop; |
86 int layers; | 86 int layers; |
87 int layer; | 87 int layer; |
88 int is_keyframe; | 88 int is_keyframe; |
| 89 int use_multiple_frame_contexts; |
89 | 90 |
90 FrameData *frame_list; | 91 FrameData *frame_list; |
91 FrameData *frame_temp; | 92 FrameData *frame_temp; |
92 | 93 |
93 char *rc_stats_buf; | 94 char *rc_stats_buf; |
94 size_t rc_stats_buf_size; | 95 size_t rc_stats_buf_size; |
95 size_t rc_stats_buf_used; | 96 size_t rc_stats_buf_used; |
96 | 97 |
97 char message_buffer[2048]; | 98 char message_buffer[2048]; |
98 vpx_codec_ctx_t *codec_ctx; | 99 vpx_codec_ctx_t *codec_ctx; |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 * Format: encoding-mode=<svc_mode>,layers=<layer_count> | 360 * Format: encoding-mode=<svc_mode>,layers=<layer_count> |
360 * scale-factors=<n1>/<d1>,<n2>/<d2>,... | 361 * scale-factors=<n1>/<d1>,<n2>/<d2>,... |
361 * quantizers=<q1>,<q2>,... | 362 * quantizers=<q1>,<q2>,... |
362 * svc_mode = [i|ip|alt_ip|gf] | 363 * svc_mode = [i|ip|alt_ip|gf] |
363 */ | 364 */ |
364 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { | 365 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { |
365 char *input_string; | 366 char *input_string; |
366 char *option_name; | 367 char *option_name; |
367 char *option_value; | 368 char *option_value; |
368 char *input_ptr; | 369 char *input_ptr; |
| 370 SvcInternal *const si = get_svc_internal(svc_ctx); |
369 vpx_codec_err_t res = VPX_CODEC_OK; | 371 vpx_codec_err_t res = VPX_CODEC_OK; |
370 | 372 |
371 if (options == NULL) return VPX_CODEC_OK; | 373 if (options == NULL) return VPX_CODEC_OK; |
372 input_string = strdup(options); | 374 input_string = strdup(options); |
373 | 375 |
374 // parse option name | 376 // parse option name |
375 option_name = strtok_r(input_string, "=", &input_ptr); | 377 option_name = strtok_r(input_string, "=", &input_ptr); |
376 while (option_name != NULL) { | 378 while (option_name != NULL) { |
377 // parse option value | 379 // parse option value |
378 option_value = strtok_r(NULL, " ", &input_ptr); | 380 option_value = strtok_r(NULL, " ", &input_ptr); |
379 if (option_value == NULL) { | 381 if (option_value == NULL) { |
380 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", | 382 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", |
381 option_name); | 383 option_name); |
382 res = VPX_CODEC_INVALID_PARAM; | 384 res = VPX_CODEC_INVALID_PARAM; |
383 break; | 385 break; |
384 } | 386 } |
385 if (strcmp("layers", option_name) == 0) { | 387 if (strcmp("spatial-layers", option_name) == 0) { |
386 svc_ctx->spatial_layers = atoi(option_value); | 388 svc_ctx->spatial_layers = atoi(option_value); |
| 389 } else if (strcmp("temporal-layers", option_name) == 0) { |
| 390 svc_ctx->temporal_layers = atoi(option_value); |
387 } else if (strcmp("scale-factors", option_name) == 0) { | 391 } else if (strcmp("scale-factors", option_name) == 0) { |
388 res = parse_scale_factors(svc_ctx, option_value); | 392 res = parse_scale_factors(svc_ctx, option_value); |
389 if (res != VPX_CODEC_OK) break; | 393 if (res != VPX_CODEC_OK) break; |
390 } else if (strcmp("quantizers", option_name) == 0) { | 394 } else if (strcmp("quantizers", option_name) == 0) { |
391 res = parse_quantizer_values(svc_ctx, option_value); | 395 res = parse_quantizer_values(svc_ctx, option_value); |
392 if (res != VPX_CODEC_OK) break; | 396 if (res != VPX_CODEC_OK) break; |
393 } else if (strcmp("auto-alt-refs", option_name) == 0) { | 397 } else if (strcmp("auto-alt-refs", option_name) == 0) { |
394 res = parse_auto_alt_ref(svc_ctx, option_value); | 398 res = parse_auto_alt_ref(svc_ctx, option_value); |
395 if (res != VPX_CODEC_OK) break; | 399 if (res != VPX_CODEC_OK) break; |
| 400 } else if (strcmp("multi-frame-contexts", option_name) == 0) { |
| 401 si->use_multiple_frame_contexts = atoi(option_value); |
396 } else { | 402 } else { |
397 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); | 403 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); |
398 res = VPX_CODEC_INVALID_PARAM; | 404 res = VPX_CODEC_INVALID_PARAM; |
399 break; | 405 break; |
400 } | 406 } |
401 option_name = strtok_r(NULL, "=", &input_ptr); | 407 option_name = strtok_r(NULL, "=", &input_ptr); |
402 } | 408 } |
403 free(input_string); | 409 free(input_string); |
| 410 |
| 411 if (si->use_multiple_frame_contexts && |
| 412 (svc_ctx->spatial_layers > 3 || |
| 413 svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4)) |
| 414 res = VPX_CODEC_INVALID_PARAM; |
| 415 |
404 return res; | 416 return res; |
405 } | 417 } |
406 | 418 |
407 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { | 419 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { |
408 SvcInternal *const si = get_svc_internal(svc_ctx); | 420 SvcInternal *const si = get_svc_internal(svc_ctx); |
409 if (svc_ctx == NULL || options == NULL || si == NULL) { | 421 if (svc_ctx == NULL || options == NULL || si == NULL) { |
410 return VPX_CODEC_INVALID_PARAM; | 422 return VPX_CODEC_INVALID_PARAM; |
411 } | 423 } |
412 strncpy(si->options, options, sizeof(si->options)); | 424 strncpy(si->options, options, sizeof(si->options)); |
413 si->options[sizeof(si->options) - 1] = '\0'; | 425 si->options[sizeof(si->options) - 1] = '\0'; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
473 if (res != VPX_CODEC_OK) return res; | 485 if (res != VPX_CODEC_OK) return res; |
474 | 486 |
475 res = parse_scale_factors(svc_ctx, si->scale_factors); | 487 res = parse_scale_factors(svc_ctx, si->scale_factors); |
476 if (res != VPX_CODEC_OK) return res; | 488 if (res != VPX_CODEC_OK) return res; |
477 | 489 |
478 // Parse aggregate command line options. Options must start with | 490 // Parse aggregate command line options. Options must start with |
479 // "layers=xx" then followed by other options | 491 // "layers=xx" then followed by other options |
480 res = parse_options(svc_ctx, si->options); | 492 res = parse_options(svc_ctx, si->options); |
481 if (res != VPX_CODEC_OK) return res; | 493 if (res != VPX_CODEC_OK) return res; |
482 | 494 |
| 495 if (svc_ctx->spatial_layers < 1) |
| 496 svc_ctx->spatial_layers = 1; |
| 497 if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) |
| 498 svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS; |
| 499 |
| 500 if (svc_ctx->temporal_layers < 1) |
| 501 svc_ctx->temporal_layers = 1; |
| 502 if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS) |
| 503 svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS; |
| 504 |
483 si->layers = svc_ctx->spatial_layers; | 505 si->layers = svc_ctx->spatial_layers; |
484 | 506 |
485 // Assign target bitrate for each layer. We calculate the ratio | 507 // Assign target bitrate for each layer. We calculate the ratio |
486 // from the resolution for now. | 508 // from the resolution for now. |
487 // TODO(Minghai): Optimize the mechanism of allocating bits after | 509 // TODO(Minghai): Optimize the mechanism of allocating bits after |
488 // implementing svc two pass rate control. | 510 // implementing svc two pass rate control. |
489 if (si->layers > 1) { | 511 if (si->layers > 1) { |
490 float total = 0; | 512 float total = 0; |
491 float alloc_ratio[VPX_SS_MAX_LAYERS] = {0}; | 513 float alloc_ratio[VPX_SS_MAX_LAYERS] = {0}; |
492 | 514 |
(...skipping 15 matching lines...) Expand all Loading... |
508 (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); | 530 (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); |
509 } | 531 } |
510 } | 532 } |
511 } | 533 } |
512 | 534 |
513 #if CONFIG_SPATIAL_SVC | 535 #if CONFIG_SPATIAL_SVC |
514 for (i = 0; i < si->layers; ++i) | 536 for (i = 0; i < si->layers; ++i) |
515 enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; | 537 enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; |
516 #endif | 538 #endif |
517 | 539 |
| 540 if (svc_ctx->temporal_layers > 1) { |
| 541 int i; |
| 542 for (i = 0; i < svc_ctx->temporal_layers; ++i) { |
| 543 enc_cfg->ts_target_bitrate[i] = enc_cfg->rc_target_bitrate / |
| 544 svc_ctx->temporal_layers; |
| 545 enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i); |
| 546 } |
| 547 } |
| 548 |
518 // modify encoder configuration | 549 // modify encoder configuration |
519 enc_cfg->ss_number_layers = si->layers; | 550 enc_cfg->ss_number_layers = si->layers; |
520 enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder. | 551 enc_cfg->ts_number_layers = svc_ctx->temporal_layers; |
521 | 552 |
522 // TODO(ivanmaltz): determine if these values need to be set explicitly for | 553 // TODO(ivanmaltz): determine if these values need to be set explicitly for |
523 // svc, or if the normal default/override mechanism can be used | 554 // svc, or if the normal default/override mechanism can be used |
524 enc_cfg->rc_dropframe_thresh = 0; | 555 enc_cfg->rc_dropframe_thresh = 0; |
525 enc_cfg->rc_resize_allowed = 0; | 556 enc_cfg->rc_resize_allowed = 0; |
526 | 557 |
527 if (enc_cfg->g_pass == VPX_RC_ONE_PASS) { | 558 if (enc_cfg->g_pass == VPX_RC_ONE_PASS) { |
528 enc_cfg->rc_min_quantizer = 33; | 559 enc_cfg->rc_min_quantizer = 33; |
529 enc_cfg->rc_max_quantizer = 33; | 560 enc_cfg->rc_max_quantizer = 33; |
530 } | 561 } |
531 | 562 |
532 enc_cfg->rc_undershoot_pct = 100; | 563 enc_cfg->rc_undershoot_pct = 100; |
533 enc_cfg->rc_overshoot_pct = 15; | 564 enc_cfg->rc_overshoot_pct = 15; |
534 enc_cfg->rc_buf_initial_sz = 500; | 565 enc_cfg->rc_buf_initial_sz = 500; |
535 enc_cfg->rc_buf_optimal_sz = 600; | 566 enc_cfg->rc_buf_optimal_sz = 600; |
536 enc_cfg->rc_buf_sz = 1000; | 567 enc_cfg->rc_buf_sz = 1000; |
537 enc_cfg->g_error_resilient = 1; | 568 if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) |
| 569 enc_cfg->g_error_resilient = 1; |
538 | 570 |
539 // Initialize codec | 571 // Initialize codec |
540 res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); | 572 res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); |
541 if (res != VPX_CODEC_OK) { | 573 if (res != VPX_CODEC_OK) { |
542 svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); | 574 svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); |
543 return res; | 575 return res; |
544 } | 576 } |
545 | 577 |
546 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); | 578 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); |
547 vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1); | 579 vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1); |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
869 return si->rc_stats_buf_used; | 901 return si->rc_stats_buf_used; |
870 } | 902 } |
871 | 903 |
872 char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) { | 904 char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) { |
873 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 905 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
874 if (svc_ctx == NULL || si == NULL) return NULL; | 906 if (svc_ctx == NULL || si == NULL) return NULL; |
875 return si->rc_stats_buf; | 907 return si->rc_stats_buf; |
876 } | 908 } |
877 | 909 |
878 | 910 |
OLD | NEW |