Home | History | Annotate | Download | only in test
      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 #include <string>
     12 #include "test/codec_factory.h"
     13 #include "test/decode_test_driver.h"
     14 #include "test/encode_test_driver.h"
     15 #include "test/i420_video_source.h"
     16 #include "test/ivf_video_source.h"
     17 #include "test/md5_helper.h"
     18 #include "test/util.h"
     19 #include "test/webm_video_source.h"
     20 #include "vpx_ports/vpx_timer.h"
     21 #include "./ivfenc.h"
     22 #include "./vpx_version.h"
     23 
     24 using std::tr1::make_tuple;
     25 
     26 namespace {
     27 
     28 #define VIDEO_NAME 0
     29 #define THREADS 1
     30 
     31 const double kUsecsInSec = 1000000.0;
     32 const char kNewEncodeOutputFile[] = "new_encode.ivf";
     33 
     34 /*
     35  DecodePerfTest takes a tuple of filename + number of threads to decode with
     36  */
     37 typedef std::tr1::tuple<const char *, unsigned> DecodePerfParam;
     38 
     39 const DecodePerfParam kVP9DecodePerfVectors[] = {
     40   make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1),
     41   make_tuple("vp90-2-bbb_640x360_tile_1x2_337kbps.webm", 2),
     42   make_tuple("vp90-2-bbb_854x480_tile_1x2_651kbps.webm", 2),
     43   make_tuple("vp90-2-bbb_1280x720_tile_1x4_1310kbps.webm", 4),
     44   make_tuple("vp90-2-bbb_1920x1080_tile_1x1_2581kbps.webm", 1),
     45   make_tuple("vp90-2-bbb_1920x1080_tile_1x4_2586kbps.webm", 4),
     46   make_tuple("vp90-2-bbb_1920x1080_tile_1x4_fpm_2304kbps.webm", 4),
     47   make_tuple("vp90-2-sintel_426x182_tile_1x1_171kbps.webm", 1),
     48   make_tuple("vp90-2-sintel_640x272_tile_1x2_318kbps.webm", 2),
     49   make_tuple("vp90-2-sintel_854x364_tile_1x2_621kbps.webm", 2),
     50   make_tuple("vp90-2-sintel_1280x546_tile_1x4_1257kbps.webm", 4),
     51   make_tuple("vp90-2-sintel_1920x818_tile_1x4_fpm_2279kbps.webm", 4),
     52   make_tuple("vp90-2-tos_426x178_tile_1x1_181kbps.webm", 1),
     53   make_tuple("vp90-2-tos_640x266_tile_1x2_336kbps.webm", 2),
     54   make_tuple("vp90-2-tos_854x356_tile_1x2_656kbps.webm", 2),
     55   make_tuple("vp90-2-tos_854x356_tile_1x2_fpm_546kbps.webm", 2),
     56   make_tuple("vp90-2-tos_1280x534_tile_1x4_1306kbps.webm", 4),
     57   make_tuple("vp90-2-tos_1280x534_tile_1x4_fpm_952kbps.webm", 4),
     58   make_tuple("vp90-2-tos_1920x800_tile_1x4_fpm_2335kbps.webm", 4),
     59 };
     60 
     61 /*
     62  In order to reflect real world performance as much as possible, Perf tests
     63  *DO NOT* do any correctness checks. Please run them alongside correctness
     64  tests to ensure proper codec integrity. Furthermore, in this test we
     65  deliberately limit the amount of system calls we make to avoid OS
     66  preemption.
     67 
     68  TODO(joshualitt) create a more detailed perf measurement test to collect
     69    power/temp/min max frame decode times/etc
     70  */
     71 
     72 class DecodePerfTest : public ::testing::TestWithParam<DecodePerfParam> {};
     73 
     74 TEST_P(DecodePerfTest, PerfTest) {
     75   const char *const video_name = GET_PARAM(VIDEO_NAME);
     76   const unsigned threads = GET_PARAM(THREADS);
     77 
     78   libvpx_test::WebMVideoSource video(video_name);
     79   video.Init();
     80 
     81   vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
     82   cfg.threads = threads;
     83   libvpx_test::VP9Decoder decoder(cfg, 0);
     84 
     85   vpx_usec_timer t;
     86   vpx_usec_timer_start(&t);
     87 
     88   for (video.Begin(); video.cxdata() != NULL; video.Next()) {
     89     decoder.DecodeFrame(video.cxdata(), video.frame_size());
     90   }
     91 
     92   vpx_usec_timer_mark(&t);
     93   const double elapsed_secs = double(vpx_usec_timer_elapsed(&t)) / kUsecsInSec;
     94   const unsigned frames = video.frame_number();
     95   const double fps = double(frames) / elapsed_secs;
     96 
     97   printf("{\n");
     98   printf("\t\"type\" : \"decode_perf_test\",\n");
     99   printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
    100   printf("\t\"videoName\" : \"%s\",\n", video_name);
    101   printf("\t\"threadCount\" : %u,\n", threads);
    102   printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
    103   printf("\t\"totalFrames\" : %u,\n", frames);
    104   printf("\t\"framesPerSecond\" : %f\n", fps);
    105   printf("}\n");
    106 }
    107 
    108 INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest,
    109                         ::testing::ValuesIn(kVP9DecodePerfVectors));
    110 
    111 class VP9NewEncodeDecodePerfTest
    112     : public ::libvpx_test::EncoderTest,
    113       public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
    114  protected:
    115   VP9NewEncodeDecodePerfTest()
    116       : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), speed_(0),
    117         outfile_(0), out_frames_(0) {}
    118 
    119   virtual ~VP9NewEncodeDecodePerfTest() {}
    120 
    121   virtual void SetUp() {
    122     InitializeConfig();
    123     SetMode(encoding_mode_);
    124 
    125     cfg_.g_lag_in_frames = 25;
    126     cfg_.rc_min_quantizer = 2;
    127     cfg_.rc_max_quantizer = 56;
    128     cfg_.rc_dropframe_thresh = 0;
    129     cfg_.rc_undershoot_pct = 50;
    130     cfg_.rc_overshoot_pct = 50;
    131     cfg_.rc_buf_sz = 1000;
    132     cfg_.rc_buf_initial_sz = 500;
    133     cfg_.rc_buf_optimal_sz = 600;
    134     cfg_.rc_resize_allowed = 0;
    135     cfg_.rc_end_usage = VPX_VBR;
    136   }
    137 
    138   virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
    139                                   ::libvpx_test::Encoder *encoder) {
    140     if (video->frame() == 1) {
    141       encoder->Control(VP8E_SET_CPUUSED, speed_);
    142       encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
    143       encoder->Control(VP9E_SET_TILE_COLUMNS, 2);
    144     }
    145   }
    146 
    147   virtual void BeginPassHook(unsigned int /*pass*/) {
    148     const std::string data_path = getenv("LIBVPX_TEST_DATA_PATH");
    149     const std::string path_to_source = data_path + "/" + kNewEncodeOutputFile;
    150     outfile_ = fopen(path_to_source.c_str(), "wb");
    151     ASSERT_TRUE(outfile_ != NULL);
    152   }
    153 
    154   virtual void EndPassHook() {
    155     if (outfile_ != NULL) {
    156       if (!fseek(outfile_, 0, SEEK_SET)) {
    157         ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
    158       }
    159       fclose(outfile_);
    160       outfile_ = NULL;
    161     }
    162   }
    163 
    164   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
    165     ++out_frames_;
    166 
    167     // Write initial file header if first frame.
    168     if (pkt->data.frame.pts == 0) {
    169       ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
    170     }
    171 
    172     // Write frame header and data.
    173     ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
    174     ASSERT_EQ(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_),
    175               pkt->data.frame.sz);
    176   }
    177 
    178   virtual bool DoDecode() const { return false; }
    179 
    180   void set_speed(unsigned int speed) { speed_ = speed; }
    181 
    182  private:
    183   libvpx_test::TestMode encoding_mode_;
    184   uint32_t speed_;
    185   FILE *outfile_;
    186   uint32_t out_frames_;
    187 };
    188 
    189 struct EncodePerfTestVideo {
    190   EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
    191                       uint32_t bitrate_, int frames_)
    192       : name(name_), width(width_), height(height_), bitrate(bitrate_),
    193         frames(frames_) {}
    194   const char *name;
    195   uint32_t width;
    196   uint32_t height;
    197   uint32_t bitrate;
    198   int frames;
    199 };
    200 
    201 const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
    202   EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
    203 };
    204 
    205 TEST_P(VP9NewEncodeDecodePerfTest, PerfTest) {
    206   SetUp();
    207 
    208   // TODO(JBB): Make this work by going through the set of given files.
    209   const int i = 0;
    210   const vpx_rational timebase = { 33333333, 1000000000 };
    211   cfg_.g_timebase = timebase;
    212   cfg_.rc_target_bitrate = kVP9EncodePerfTestVectors[i].bitrate;
    213 
    214   init_flags_ = VPX_CODEC_USE_PSNR;
    215 
    216   const char *video_name = kVP9EncodePerfTestVectors[i].name;
    217   libvpx_test::I420VideoSource video(
    218       video_name, kVP9EncodePerfTestVectors[i].width,
    219       kVP9EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0,
    220       kVP9EncodePerfTestVectors[i].frames);
    221   set_speed(2);
    222 
    223   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
    224 
    225   const uint32_t threads = 4;
    226 
    227   libvpx_test::IVFVideoSource decode_video(kNewEncodeOutputFile);
    228   decode_video.Init();
    229 
    230   vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
    231   cfg.threads = threads;
    232   libvpx_test::VP9Decoder decoder(cfg, 0);
    233 
    234   vpx_usec_timer t;
    235   vpx_usec_timer_start(&t);
    236 
    237   for (decode_video.Begin(); decode_video.cxdata() != NULL;
    238        decode_video.Next()) {
    239     decoder.DecodeFrame(decode_video.cxdata(), decode_video.frame_size());
    240   }
    241 
    242   vpx_usec_timer_mark(&t);
    243   const double elapsed_secs =
    244       static_cast<double>(vpx_usec_timer_elapsed(&t)) / kUsecsInSec;
    245   const unsigned decode_frames = decode_video.frame_number();
    246   const double fps = static_cast<double>(decode_frames) / elapsed_secs;
    247 
    248   printf("{\n");
    249   printf("\t\"type\" : \"decode_perf_test\",\n");
    250   printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
    251   printf("\t\"videoName\" : \"%s\",\n", kNewEncodeOutputFile);
    252   printf("\t\"threadCount\" : %u,\n", threads);
    253   printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
    254   printf("\t\"totalFrames\" : %u,\n", decode_frames);
    255   printf("\t\"framesPerSecond\" : %f\n", fps);
    256   printf("}\n");
    257 }
    258 
    259 VP9_INSTANTIATE_TEST_CASE(VP9NewEncodeDecodePerfTest,
    260                           ::testing::Values(::libvpx_test::kTwoPassGood));
    261 }  // namespace
    262