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