OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2012 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 // This is an example demonstrating how to implement a multi-layer VP9 | 11 // This is an example demonstrating how to implement a multi-layer VP9 |
12 // encoding scheme based on temporal scalability for video applications | 12 // encoding scheme based on temporal scalability for video applications |
13 // that benefit from a scalable bitstream. | 13 // that benefit from a scalable bitstream. |
14 | 14 |
15 #include <math.h> | 15 #include <math.h> |
16 #include <stdio.h> | 16 #include <stdio.h> |
17 #include <stdlib.h> | 17 #include <stdlib.h> |
18 #include <string.h> | 18 #include <string.h> |
19 | 19 |
20 #define VPX_CODEC_DISABLE_COMPAT 1 | 20 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 21 #include "./vpx_config.h" |
| 22 #include "vpx_ports/vpx_timer.h" |
21 #include "vpx/vp8cx.h" | 23 #include "vpx/vp8cx.h" |
22 #include "vpx/vpx_encoder.h" | 24 #include "vpx/vpx_encoder.h" |
23 | 25 |
24 #include "./tools_common.h" | 26 #include "./tools_common.h" |
25 #include "./video_writer.h" | 27 #include "./video_writer.h" |
26 | 28 |
27 static const char *exec_name; | 29 static const char *exec_name; |
28 | 30 |
29 void usage_exit() { | 31 void usage_exit() { |
30 exit(EXIT_FAILURE); | 32 exit(EXIT_FAILURE); |
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 | 430 |
429 int main(int argc, char **argv) { | 431 int main(int argc, char **argv) { |
430 VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS]; | 432 VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS]; |
431 vpx_codec_ctx_t codec; | 433 vpx_codec_ctx_t codec; |
432 vpx_codec_enc_cfg_t cfg; | 434 vpx_codec_enc_cfg_t cfg; |
433 int frame_cnt = 0; | 435 int frame_cnt = 0; |
434 vpx_image_t raw; | 436 vpx_image_t raw; |
435 vpx_codec_err_t res; | 437 vpx_codec_err_t res; |
436 unsigned int width; | 438 unsigned int width; |
437 unsigned int height; | 439 unsigned int height; |
| 440 int speed; |
438 int frame_avail; | 441 int frame_avail; |
439 int got_data; | 442 int got_data; |
440 int flags = 0; | 443 int flags = 0; |
441 unsigned int i; | 444 unsigned int i; |
442 int pts = 0; // PTS starts at 0. | 445 int pts = 0; // PTS starts at 0. |
443 int frame_duration = 1; // 1 timebase tick per frame. | 446 int frame_duration = 1; // 1 timebase tick per frame. |
444 int layering_mode = 0; | 447 int layering_mode = 0; |
445 int layer_flags[VPX_TS_MAX_PERIODICITY] = {0}; | 448 int layer_flags[VPX_TS_MAX_PERIODICITY] = {0}; |
446 int flag_periodicity = 1; | 449 int flag_periodicity = 1; |
447 int max_intra_size_pct; | 450 int max_intra_size_pct; |
448 vpx_svc_layer_id_t layer_id = {0, 0}; | 451 vpx_svc_layer_id_t layer_id = {0, 0}; |
449 const VpxInterface *encoder = NULL; | 452 const VpxInterface *encoder = NULL; |
450 FILE *infile = NULL; | 453 FILE *infile = NULL; |
451 struct RateControlMetrics rc; | 454 struct RateControlMetrics rc; |
| 455 int64_t cx_time = 0; |
452 | 456 |
453 exec_name = argv[0]; | 457 exec_name = argv[0]; |
454 // Check usage and arguments. | 458 // Check usage and arguments. |
455 if (argc < 11) { | 459 if (argc < 11) { |
456 die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> " | 460 die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> " |
457 "<rate_num> <rate_den> <frame_drop_threshold> <mode> " | 461 "<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> " |
458 "<Rate_0> ... <Rate_nlayers-1> \n", argv[0]); | 462 "<Rate_0> ... <Rate_nlayers-1> \n", argv[0]); |
459 } | 463 } |
460 | 464 |
461 encoder = get_vpx_encoder_by_name(argv[3]); | 465 encoder = get_vpx_encoder_by_name(argv[3]); |
462 if (!encoder) | 466 if (!encoder) |
463 die("Unsupported codec."); | 467 die("Unsupported codec."); |
464 | 468 |
465 printf("Using %s\n", vpx_codec_iface_name(encoder->interface())); | 469 printf("Using %s\n", vpx_codec_iface_name(encoder->interface())); |
466 | 470 |
467 width = strtol(argv[4], NULL, 0); | 471 width = strtol(argv[4], NULL, 0); |
468 height = strtol(argv[5], NULL, 0); | 472 height = strtol(argv[5], NULL, 0); |
469 if (width < 16 || width % 2 || height < 16 || height % 2) { | 473 if (width < 16 || width % 2 || height < 16 || height % 2) { |
470 die("Invalid resolution: %d x %d", width, height); | 474 die("Invalid resolution: %d x %d", width, height); |
471 } | 475 } |
472 | 476 |
473 layering_mode = strtol(argv[9], NULL, 0); | 477 layering_mode = strtol(argv[10], NULL, 0); |
474 if (layering_mode < 0 || layering_mode > 12) { | 478 if (layering_mode < 0 || layering_mode > 12) { |
475 die("Invalid mode (0..12) %s", argv[9]); | 479 die("Invalid layering mode (0..12) %s", argv[10]); |
476 } | 480 } |
477 | 481 |
478 if (argc != 10 + mode_to_num_layers[layering_mode]) { | 482 if (argc != 11 + mode_to_num_layers[layering_mode]) { |
479 die("Invalid number of arguments"); | 483 die("Invalid number of arguments"); |
480 } | 484 } |
481 | 485 |
482 if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) { | 486 if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) { |
483 die("Failed to allocate image", width, height); | 487 die("Failed to allocate image", width, height); |
484 } | 488 } |
485 | 489 |
486 // Populate encoder configuration. | 490 // Populate encoder configuration. |
487 res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0); | 491 res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0); |
488 if (res) { | 492 if (res) { |
489 printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); | 493 printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); |
490 return EXIT_FAILURE; | 494 return EXIT_FAILURE; |
491 } | 495 } |
492 | 496 |
493 // Update the default configuration with our settings. | 497 // Update the default configuration with our settings. |
494 cfg.g_w = width; | 498 cfg.g_w = width; |
495 cfg.g_h = height; | 499 cfg.g_h = height; |
496 | 500 |
497 // Timebase format e.g. 30fps: numerator=1, demoninator = 30. | 501 // Timebase format e.g. 30fps: numerator=1, demoninator = 30. |
498 cfg.g_timebase.num = strtol(argv[6], NULL, 0); | 502 cfg.g_timebase.num = strtol(argv[6], NULL, 0); |
499 cfg.g_timebase.den = strtol(argv[7], NULL, 0); | 503 cfg.g_timebase.den = strtol(argv[7], NULL, 0); |
500 | 504 |
501 for (i = 10; (int)i < 10 + mode_to_num_layers[layering_mode]; ++i) { | 505 speed = strtol(argv[8], NULL, 0); |
502 cfg.ts_target_bitrate[i - 10] = strtol(argv[i], NULL, 0); | 506 if (speed < 0) { |
| 507 die("Invalid speed setting: must be positive"); |
| 508 } |
| 509 |
| 510 for (i = 11; (int)i < 11 + mode_to_num_layers[layering_mode]; ++i) { |
| 511 cfg.ts_target_bitrate[i - 11] = strtol(argv[i], NULL, 0); |
503 } | 512 } |
504 | 513 |
505 // Real time parameters. | 514 // Real time parameters. |
506 cfg.rc_dropframe_thresh = strtol(argv[8], NULL, 0); | 515 cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0); |
507 cfg.rc_end_usage = VPX_CBR; | 516 cfg.rc_end_usage = VPX_CBR; |
508 cfg.rc_resize_allowed = 0; | 517 cfg.rc_resize_allowed = 0; |
509 cfg.rc_min_quantizer = 2; | 518 cfg.rc_min_quantizer = 2; |
510 cfg.rc_max_quantizer = 56; | 519 cfg.rc_max_quantizer = 56; |
511 cfg.rc_undershoot_pct = 50; | 520 cfg.rc_undershoot_pct = 50; |
512 cfg.rc_overshoot_pct = 50; | 521 cfg.rc_overshoot_pct = 50; |
513 cfg.rc_buf_initial_sz = 500; | 522 cfg.rc_buf_initial_sz = 500; |
514 cfg.rc_buf_optimal_sz = 600; | 523 cfg.rc_buf_optimal_sz = 600; |
515 cfg.rc_buf_sz = 1000; | 524 cfg.rc_buf_sz = 1000; |
516 | 525 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 if (!outfile[i]) | 562 if (!outfile[i]) |
554 die("Failed to open %s for writing", file_name); | 563 die("Failed to open %s for writing", file_name); |
555 } | 564 } |
556 // No spatial layers in this encoder. | 565 // No spatial layers in this encoder. |
557 cfg.ss_number_layers = 1; | 566 cfg.ss_number_layers = 1; |
558 | 567 |
559 // Initialize codec. | 568 // Initialize codec. |
560 if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0)) | 569 if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0)) |
561 die_codec(&codec, "Failed to initialize encoder"); | 570 die_codec(&codec, "Failed to initialize encoder"); |
562 | 571 |
563 vpx_codec_control(&codec, VP8E_SET_CPUUSED, -6); | 572 if (strncmp(encoder->name, "vp8", 3) == 0) { |
564 vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1); | 573 vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed); |
565 if (strncmp(encoder->name, "vp9", 3) == 0) { | 574 vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1); |
566 vpx_codec_control(&codec, VP8E_SET_CPUUSED, 3); | 575 } else if (strncmp(encoder->name, "vp9", 3) == 0) { |
567 vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 0); | 576 vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed); |
568 if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) { | 577 vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3); |
569 die_codec(&codec, "Failed to set SVC"); | 578 vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0); |
| 579 vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 0); |
| 580 if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) { |
| 581 die_codec(&codec, "Failed to set SVC"); |
570 } | 582 } |
571 } | 583 } |
572 vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1); | 584 vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1); |
573 vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1); | 585 vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1); |
574 // This controls the maximum target size of the key frame. | 586 // This controls the maximum target size of the key frame. |
575 // For generating smaller key frames, use a smaller max_intra_size_pct | 587 // For generating smaller key frames, use a smaller max_intra_size_pct |
576 // value, like 100 or 200. | 588 // value, like 100 or 200. |
577 max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5) | 589 max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5) |
578 * ((double) cfg.g_timebase.den / cfg.g_timebase.num) / 10.0); | 590 * ((double) cfg.g_timebase.den / cfg.g_timebase.num) / 10.0); |
| 591 // For low-quality key frame. |
| 592 max_intra_size_pct = 200; |
579 vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, max_intra_size_pct); | 593 vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, max_intra_size_pct); |
580 | 594 |
581 frame_avail = 1; | 595 frame_avail = 1; |
582 while (frame_avail || got_data) { | 596 while (frame_avail || got_data) { |
| 597 struct vpx_usec_timer timer; |
583 vpx_codec_iter_t iter = NULL; | 598 vpx_codec_iter_t iter = NULL; |
584 const vpx_codec_cx_pkt_t *pkt; | 599 const vpx_codec_cx_pkt_t *pkt; |
585 // Update the temporal layer_id. No spatial layers in this test. | 600 // Update the temporal layer_id. No spatial layers in this test. |
586 layer_id.spatial_layer_id = 0; | 601 layer_id.spatial_layer_id = 0; |
587 layer_id.temporal_layer_id = | 602 layer_id.temporal_layer_id = |
588 cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; | 603 cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; |
589 if (strncmp(encoder->name, "vp9", 3) == 0) { | 604 if (strncmp(encoder->name, "vp9", 3) == 0) { |
590 vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id); | 605 vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id); |
591 } | 606 } |
592 flags = layer_flags[frame_cnt % flag_periodicity]; | 607 flags = layer_flags[frame_cnt % flag_periodicity]; |
593 frame_avail = vpx_img_read(&raw, infile); | 608 frame_avail = vpx_img_read(&raw, infile); |
594 if (frame_avail) | 609 if (frame_avail) |
595 ++rc.layer_input_frames[layer_id.temporal_layer_id]; | 610 ++rc.layer_input_frames[layer_id.temporal_layer_id]; |
| 611 vpx_usec_timer_start(&timer); |
596 if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, 1, flags, | 612 if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, 1, flags, |
597 VPX_DL_REALTIME)) { | 613 VPX_DL_REALTIME)) { |
598 die_codec(&codec, "Failed to encode frame"); | 614 die_codec(&codec, "Failed to encode frame"); |
599 } | 615 } |
| 616 vpx_usec_timer_mark(&timer); |
| 617 cx_time += vpx_usec_timer_elapsed(&timer); |
600 // Reset KF flag. | 618 // Reset KF flag. |
601 if (layering_mode != 7) { | 619 if (layering_mode != 7) { |
602 layer_flags[0] &= ~VPX_EFLAG_FORCE_KF; | 620 layer_flags[0] &= ~VPX_EFLAG_FORCE_KF; |
603 } | 621 } |
604 got_data = 0; | 622 got_data = 0; |
605 while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { | 623 while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { |
606 got_data = 1; | 624 got_data = 1; |
607 switch (pkt->kind) { | 625 switch (pkt->kind) { |
608 case VPX_CODEC_CX_FRAME_PKT: | 626 case VPX_CODEC_CX_FRAME_PKT: |
609 for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; | 627 for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; |
(...skipping 15 matching lines...) Expand all Loading... |
625 break; | 643 break; |
626 default: | 644 default: |
627 break; | 645 break; |
628 } | 646 } |
629 } | 647 } |
630 ++frame_cnt; | 648 ++frame_cnt; |
631 pts += frame_duration; | 649 pts += frame_duration; |
632 } | 650 } |
633 fclose(infile); | 651 fclose(infile); |
634 printout_rate_control_summary(&rc, &cfg, frame_cnt); | 652 printout_rate_control_summary(&rc, &cfg, frame_cnt); |
| 653 printf("\n"); |
| 654 printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n", |
| 655 frame_cnt, |
| 656 1000 * (float)cx_time / (double)(frame_cnt * 1000000), |
| 657 1000000 * (double)frame_cnt / (double)cx_time); |
635 | 658 |
636 if (vpx_codec_destroy(&codec)) | 659 if (vpx_codec_destroy(&codec)) |
637 die_codec(&codec, "Failed to destroy codec"); | 660 die_codec(&codec, "Failed to destroy codec"); |
638 | 661 |
639 // Try to rewrite the output file headers with the actual frame count. | 662 // Try to rewrite the output file headers with the actual frame count. |
640 for (i = 0; i < cfg.ts_number_layers; ++i) | 663 for (i = 0; i < cfg.ts_number_layers; ++i) |
641 vpx_video_writer_close(outfile[i]); | 664 vpx_video_writer_close(outfile[i]); |
642 | 665 |
643 return EXIT_SUCCESS; | 666 return EXIT_SUCCESS; |
644 } | 667 } |
OLD | NEW |