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 int kMaxPsnr = 100;
32 const double kUsecsInSec = 1000000.0;
33 const char kNewEncodeOutputFile[] = "new_encode.ivf";
34
35 /*
36 DecodePerfTest takes a tuple of filename + number of threads to decode with
37 */
38 typedef std::tr1::tuple<const char *, unsigned> DecodePerfParam;
39
40 const 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
73 class DecodePerfTest : public ::testing::TestWithParam<DecodePerfParam> {
74 };
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() != 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
111 INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest,
112 ::testing::ValuesIn(kVP9DecodePerfVectors));
113
114 class VP9NewEncodeDecodePerfTest :
115 public ::libvpx_test::EncoderTest,
116 public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
117 protected:
VP9NewEncodeDecodePerfTest()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
~VP9NewEncodeDecodePerfTest()126 virtual ~VP9NewEncodeDecodePerfTest() {}
127
SetUp()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
PreEncodeFrameHook(::libvpx_test::VideoSource * video,::libvpx_test::Encoder * encoder)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
BeginPassHook(unsigned int)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
EndPassHook()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
FramePktHook(const vpx_codec_cx_pkt_t * pkt)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
DoDecode()183 virtual bool DoDecode() { return false; }
184
set_speed(unsigned int speed)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
196 struct EncodePerfTestVideo {
EncodePerfTestVideo__anonf93d29300111::EncodePerfTestVideo197 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
211 const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
212 EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
213 };
214
TEST_P(VP9NewEncodeDecodePerfTest,PerfTest)215 TEST_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
271 VP9_INSTANTIATE_TEST_CASE(
272 VP9NewEncodeDecodePerfTest, ::testing::Values(::libvpx_test::kTwoPassGood));
273 } // namespace
274