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