xref: /aosp_15_r20/external/libaom/test/decode_perf_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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