1 /*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
11
12 #include <string>
13 #include <tuple>
14
15 #include "config/aom_version.h"
16
17 #include "aom_ports/aom_timer.h"
18 #include "common/ivfenc.h"
19 #include "test/codec_factory.h"
20 #include "test/decode_test_driver.h"
21 #include "test/encode_test_driver.h"
22 #include "test/i420_video_source.h"
23 #include "test/ivf_video_source.h"
24 #include "test/md5_helper.h"
25 #include "test/util.h"
26 #include "test/webm_video_source.h"
27
28 using std::make_tuple;
29
30 namespace {
31
32 #define VIDEO_NAME 0
33 #define THREADS 1
34
35 const double kUsecsInSec = 1000000.0;
36 const char kNewEncodeOutputFile[] = "new_encode.ivf";
37
38 /*
39 DecodePerfTest takes a tuple of filename + number of threads to decode with
40 */
41 typedef std::tuple<const char *, unsigned> DecodePerfParam;
42
43 // TODO(jimbankoski): Add actual test vectors here when available.
44 // const DecodePerfParam kAV1DecodePerfVectors[] = {};
45
46 /*
47 In order to reflect real world performance as much as possible, Perf tests
48 *DO NOT* do any correctness checks. Please run them alongside correctness
49 tests to ensure proper codec integrity. Furthermore, in this test we
50 deliberately limit the amount of system calls we make to avoid OS
51 preemption.
52
53 TODO(joshualitt) create a more detailed perf measurement test to collect
54 power/temp/min max frame decode times/etc
55 */
56
57 class DecodePerfTest : public ::testing::TestWithParam<DecodePerfParam> {};
58
TEST_P(DecodePerfTest,PerfTest)59 TEST_P(DecodePerfTest, PerfTest) {
60 const char *const video_name = GET_PARAM(VIDEO_NAME);
61 const unsigned threads = GET_PARAM(THREADS);
62
63 libaom_test::WebMVideoSource video(video_name);
64 video.Init();
65
66 aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
67 cfg.threads = threads;
68 cfg.allow_lowbitdepth = 1;
69 libaom_test::AV1Decoder decoder(cfg, 0);
70
71 aom_usec_timer t;
72 aom_usec_timer_start(&t);
73
74 for (video.Begin(); video.cxdata() != NULL; video.Next()) {
75 decoder.DecodeFrame(video.cxdata(), video.frame_size());
76 }
77
78 aom_usec_timer_mark(&t);
79 const double elapsed_secs = double(aom_usec_timer_elapsed(&t)) / kUsecsInSec;
80 const unsigned frames = video.frame_number();
81 const double fps = double(frames) / elapsed_secs;
82
83 printf("{\n");
84 printf("\t\"type\" : \"decode_perf_test\",\n");
85 printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
86 printf("\t\"videoName\" : \"%s\",\n", video_name);
87 printf("\t\"threadCount\" : %u,\n", threads);
88 printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
89 printf("\t\"totalFrames\" : %u,\n", frames);
90 printf("\t\"framesPerSecond\" : %f\n", fps);
91 printf("}\n");
92 }
93
94 // TODO(jimbankoski): Enabled when we have actual AV1 Decode vectors.
95 // INSTANTIATE_TEST_SUITE_P(AV1, DecodePerfTest,
96 // ::testing::ValuesIn(kAV1DecodePerfVectors));
97
98 class AV1NewEncodeDecodePerfTest
99 : public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
100 public ::libaom_test::EncoderTest {
101 protected:
AV1NewEncodeDecodePerfTest()102 AV1NewEncodeDecodePerfTest()
103 : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), speed_(0),
104 outfile_(0), out_frames_(0) {}
105
~AV1NewEncodeDecodePerfTest()106 virtual ~AV1NewEncodeDecodePerfTest() {}
107
SetUp()108 virtual void SetUp() {
109 InitializeConfig();
110 SetMode(encoding_mode_);
111
112 cfg_.g_lag_in_frames = 25;
113 cfg_.rc_min_quantizer = 2;
114 cfg_.rc_max_quantizer = 56;
115 cfg_.rc_dropframe_thresh = 0;
116 cfg_.rc_undershoot_pct = 50;
117 cfg_.rc_overshoot_pct = 50;
118 cfg_.rc_buf_sz = 1000;
119 cfg_.rc_buf_initial_sz = 500;
120 cfg_.rc_buf_optimal_sz = 600;
121 cfg_.rc_end_usage = AOM_VBR;
122 }
123
PreEncodeFrameHook(::libaom_test::VideoSource * video,::libaom_test::Encoder * encoder)124 virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
125 ::libaom_test::Encoder *encoder) {
126 if (video->frame() == 0) {
127 encoder->Control(AOME_SET_CPUUSED, speed_);
128 encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
129 encoder->Control(AV1E_SET_TILE_COLUMNS, 2);
130 }
131 }
132
BeginPassHook(unsigned int)133 virtual void BeginPassHook(unsigned int /*pass*/) {
134 const char *const env = getenv("LIBAOM_TEST_DATA_PATH");
135 const std::string data_path(env ? env : ".");
136 const std::string path_to_source = data_path + "/" + kNewEncodeOutputFile;
137 outfile_ = fopen(path_to_source.c_str(), "wb");
138 ASSERT_TRUE(outfile_ != NULL);
139 }
140
EndPassHook()141 virtual void EndPassHook() {
142 if (outfile_ != NULL) {
143 if (!fseek(outfile_, 0, SEEK_SET))
144 ivf_write_file_header(outfile_, &cfg_, AV1_FOURCC, out_frames_);
145 fclose(outfile_);
146 outfile_ = NULL;
147 }
148 }
149
FramePktHook(const aom_codec_cx_pkt_t * pkt)150 virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
151 ++out_frames_;
152
153 // Write initial file header if first frame.
154 if (pkt->data.frame.pts == 0)
155 ivf_write_file_header(outfile_, &cfg_, AV1_FOURCC, out_frames_);
156
157 // Write frame header and data.
158 ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
159 ASSERT_EQ(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_),
160 pkt->data.frame.sz);
161 }
162
DoDecode() const163 virtual bool DoDecode() const { return false; }
164
set_speed(unsigned int speed)165 void set_speed(unsigned int speed) { speed_ = speed; }
166
167 private:
168 libaom_test::TestMode encoding_mode_;
169 uint32_t speed_;
170 FILE *outfile_;
171 uint32_t out_frames_;
172 };
173
174 struct EncodePerfTestVideo {
EncodePerfTestVideo__anon06853f160111::EncodePerfTestVideo175 EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
176 uint32_t bitrate_, int frames_)
177 : name(name_), width(width_), height(height_), bitrate(bitrate_),
178 frames(frames_) {}
179 const char *name;
180 uint32_t width;
181 uint32_t height;
182 uint32_t bitrate;
183 int frames;
184 };
185
186 const EncodePerfTestVideo kAV1EncodePerfTestVectors[] = {
187 EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
188 };
189
TEST_P(AV1NewEncodeDecodePerfTest,PerfTest)190 TEST_P(AV1NewEncodeDecodePerfTest, PerfTest) {
191 SetUp();
192
193 // TODO(JBB): Make this work by going through the set of given files.
194 const int i = 0;
195 const aom_rational timebase = { 33333333, 1000000000 };
196 cfg_.g_timebase = timebase;
197 cfg_.rc_target_bitrate = kAV1EncodePerfTestVectors[i].bitrate;
198
199 init_flags_ = AOM_CODEC_USE_PSNR;
200
201 const char *video_name = kAV1EncodePerfTestVectors[i].name;
202 libaom_test::I420VideoSource video(
203 video_name, kAV1EncodePerfTestVectors[i].width,
204 kAV1EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0,
205 kAV1EncodePerfTestVectors[i].frames);
206 set_speed(2);
207
208 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
209
210 const uint32_t threads = 4;
211
212 libaom_test::IVFVideoSource decode_video(kNewEncodeOutputFile);
213 decode_video.Init();
214
215 aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
216 cfg.threads = threads;
217 cfg.allow_lowbitdepth = 1;
218 libaom_test::AV1Decoder decoder(cfg, 0);
219
220 aom_usec_timer t;
221 aom_usec_timer_start(&t);
222
223 for (decode_video.Begin(); decode_video.cxdata() != NULL;
224 decode_video.Next()) {
225 decoder.DecodeFrame(decode_video.cxdata(), decode_video.frame_size());
226 }
227
228 aom_usec_timer_mark(&t);
229 const double elapsed_secs =
230 static_cast<double>(aom_usec_timer_elapsed(&t)) / kUsecsInSec;
231 const unsigned decode_frames = decode_video.frame_number();
232 const double fps = static_cast<double>(decode_frames) / elapsed_secs;
233
234 printf("{\n");
235 printf("\t\"type\" : \"decode_perf_test\",\n");
236 printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
237 printf("\t\"videoName\" : \"%s\",\n", kNewEncodeOutputFile);
238 printf("\t\"threadCount\" : %u,\n", threads);
239 printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
240 printf("\t\"totalFrames\" : %u,\n", decode_frames);
241 printf("\t\"framesPerSecond\" : %f\n", fps);
242 printf("}\n");
243 }
244
245 AV1_INSTANTIATE_TEST_SUITE(AV1NewEncodeDecodePerfTest,
246 ::testing::Values(::libaom_test::kTwoPassGood));
247 } // namespace
248