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