• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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() != nullptr; 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_(nullptr), out_frames_(0) {}
105 
106   ~AV1NewEncodeDecodePerfTest() override = default;
107 
SetUp()108   void SetUp() override {
109     InitializeConfig(encoding_mode_);
110 
111     cfg_.g_lag_in_frames = 25;
112     cfg_.rc_min_quantizer = 2;
113     cfg_.rc_max_quantizer = 56;
114     cfg_.rc_dropframe_thresh = 0;
115     cfg_.rc_undershoot_pct = 50;
116     cfg_.rc_overshoot_pct = 50;
117     cfg_.rc_buf_sz = 1000;
118     cfg_.rc_buf_initial_sz = 500;
119     cfg_.rc_buf_optimal_sz = 600;
120     cfg_.rc_end_usage = AOM_VBR;
121   }
122 
PreEncodeFrameHook(::libaom_test::VideoSource * video,::libaom_test::Encoder * encoder)123   void PreEncodeFrameHook(::libaom_test::VideoSource *video,
124                           ::libaom_test::Encoder *encoder) override {
125     if (video->frame() == 0) {
126       encoder->Control(AOME_SET_CPUUSED, speed_);
127       encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
128       encoder->Control(AV1E_SET_TILE_COLUMNS, 2);
129     }
130   }
131 
BeginPassHook(unsigned int)132   void BeginPassHook(unsigned int /*pass*/) override {
133     const char *const env = getenv("LIBAOM_TEST_DATA_PATH");
134     const std::string data_path(env ? env : ".");
135     const std::string path_to_source = data_path + "/" + kNewEncodeOutputFile;
136     outfile_ = fopen(path_to_source.c_str(), "wb");
137     ASSERT_NE(outfile_, nullptr);
138   }
139 
EndPassHook()140   void EndPassHook() override {
141     if (outfile_ != nullptr) {
142       if (!fseek(outfile_, 0, SEEK_SET))
143         ivf_write_file_header(outfile_, &cfg_, AV1_FOURCC, out_frames_);
144       fclose(outfile_);
145       outfile_ = nullptr;
146     }
147   }
148 
FramePktHook(const aom_codec_cx_pkt_t * pkt)149   void FramePktHook(const aom_codec_cx_pkt_t *pkt) override {
150     ++out_frames_;
151 
152     // Write initial file header if first frame.
153     if (pkt->data.frame.pts == 0)
154       ivf_write_file_header(outfile_, &cfg_, AV1_FOURCC, out_frames_);
155 
156     // Write frame header and data.
157     ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
158     ASSERT_EQ(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_),
159               pkt->data.frame.sz);
160   }
161 
DoDecode() const162   bool DoDecode() const override { return false; }
163 
set_speed(unsigned int speed)164   void set_speed(unsigned int speed) { speed_ = speed; }
165 
166  private:
167   libaom_test::TestMode encoding_mode_;
168   uint32_t speed_;
169   FILE *outfile_;
170   uint32_t out_frames_;
171 };
172 
173 struct EncodePerfTestVideo {
EncodePerfTestVideo__anon5e0e487a0111::EncodePerfTestVideo174   EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
175                       uint32_t bitrate_, int frames_)
176       : name(name_), width(width_), height(height_), bitrate(bitrate_),
177         frames(frames_) {}
178   const char *name;
179   uint32_t width;
180   uint32_t height;
181   uint32_t bitrate;
182   int frames;
183 };
184 
185 const EncodePerfTestVideo kAV1EncodePerfTestVectors[] = {
186   EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
187 };
188 
TEST_P(AV1NewEncodeDecodePerfTest,PerfTest)189 TEST_P(AV1NewEncodeDecodePerfTest, PerfTest) {
190   SetUp();
191 
192   // TODO(JBB): Make this work by going through the set of given files.
193   const int i = 0;
194   const aom_rational timebase = { 33333333, 1000000000 };
195   cfg_.g_timebase = timebase;
196   cfg_.rc_target_bitrate = kAV1EncodePerfTestVectors[i].bitrate;
197 
198   init_flags_ = AOM_CODEC_USE_PSNR;
199 
200   const char *video_name = kAV1EncodePerfTestVectors[i].name;
201   libaom_test::I420VideoSource video(
202       video_name, kAV1EncodePerfTestVectors[i].width,
203       kAV1EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0,
204       kAV1EncodePerfTestVectors[i].frames);
205   set_speed(2);
206 
207   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
208 
209   const uint32_t threads = 4;
210 
211   libaom_test::IVFVideoSource decode_video(kNewEncodeOutputFile);
212   decode_video.Init();
213 
214   aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
215   cfg.threads = threads;
216   cfg.allow_lowbitdepth = 1;
217   libaom_test::AV1Decoder decoder(cfg, 0);
218 
219   aom_usec_timer t;
220   aom_usec_timer_start(&t);
221 
222   for (decode_video.Begin(); decode_video.cxdata() != nullptr;
223        decode_video.Next()) {
224     decoder.DecodeFrame(decode_video.cxdata(), decode_video.frame_size());
225   }
226 
227   aom_usec_timer_mark(&t);
228   const double elapsed_secs =
229       static_cast<double>(aom_usec_timer_elapsed(&t)) / kUsecsInSec;
230   const unsigned decode_frames = decode_video.frame_number();
231   const double fps = static_cast<double>(decode_frames) / elapsed_secs;
232 
233   printf("{\n");
234   printf("\t\"type\" : \"decode_perf_test\",\n");
235   printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
236   printf("\t\"videoName\" : \"%s\",\n", kNewEncodeOutputFile);
237   printf("\t\"threadCount\" : %u,\n", threads);
238   printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
239   printf("\t\"totalFrames\" : %u,\n", decode_frames);
240   printf("\t\"framesPerSecond\" : %f\n", fps);
241   printf("}\n");
242 }
243 
244 AV1_INSTANTIATE_TEST_SUITE(AV1NewEncodeDecodePerfTest,
245                            ::testing::Values(::libaom_test::kTwoPassGood));
246 }  // namespace
247