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