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