blob: 5de949d7c16c25df3348af5057d84ede636541bc [file] [log] [blame]
John Koleszarb9180fc2012-05-16 15:27:00 -07001/*
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
John Koleszarb9180fc2012-05-16 15:27:00 -07003 *
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07004 * 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.
John Koleszarb9180fc2012-05-16 15:27:00 -070010 */
11#ifndef TEST_ENCODE_TEST_DRIVER_H_
12#define TEST_ENCODE_TEST_DRIVER_H_
Deb Mukherjee01cafaa2013-01-15 06:43:35 -080013
John Koleszarb9180fc2012-05-16 15:27:00 -070014#include <string>
15#include <vector>
James Zern51b7fd02013-05-03 19:08:08 -070016
Tom Finegan7a07ece2017-02-07 17:14:05 -080017#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
Jingning Han097d59c2015-07-29 14:51:36 -070018
Yaowu Xuf883b422016-08-30 14:01:10 -070019#include "./aom_config.h"
20#if CONFIG_AV1_ENCODER
21#include "aom/aomcx.h"
Alex Conversea5654692014-03-11 16:40:57 -070022#endif
Yaowu Xuf883b422016-08-30 14:01:10 -070023#include "aom/aom_encoder.h"
John Koleszarb9180fc2012-05-16 15:27:00 -070024
Yaowu Xuc27fc142016-08-22 16:08:15 -070025namespace libaom_test {
John Koleszarb9180fc2012-05-16 15:27:00 -070026
John Koleszar706cafe2013-01-18 11:51:12 -080027class CodecFactory;
John Koleszarb9180fc2012-05-16 15:27:00 -070028class VideoSource;
29
30enum TestMode {
31 kRealTime,
32 kOnePassGood,
33 kOnePassBest,
34 kTwoPassGood,
35 kTwoPassBest
36};
clang-format3a826f12016-08-11 17:46:05 -070037#define ALL_TEST_MODES \
Yaowu Xuc27fc142016-08-22 16:08:15 -070038 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood, \
39 ::libaom_test::kOnePassBest, ::libaom_test::kTwoPassGood, \
40 ::libaom_test::kTwoPassBest)
John Koleszarb9180fc2012-05-16 15:27:00 -070041
clang-format3a826f12016-08-11 17:46:05 -070042#define ONE_PASS_TEST_MODES \
Yaowu Xuc27fc142016-08-22 16:08:15 -070043 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood, \
44 ::libaom_test::kOnePassBest)
John Koleszar2fb29ff2012-05-23 12:55:27 -070045
clang-format3a826f12016-08-11 17:46:05 -070046#define TWO_PASS_TEST_MODES \
Yaowu Xuc27fc142016-08-22 16:08:15 -070047 ::testing::Values(::libaom_test::kTwoPassGood, ::libaom_test::kTwoPassBest)
John Koleszarb9180fc2012-05-16 15:27:00 -070048
Yaowu Xuc27fc142016-08-22 16:08:15 -070049// Provides an object to handle the libaom get_cx_data() iteration pattern
John Koleszarb9180fc2012-05-16 15:27:00 -070050class CxDataIterator {
51 public:
Yaowu Xuf883b422016-08-30 14:01:10 -070052 explicit CxDataIterator(aom_codec_ctx_t *encoder)
James Zern51b7fd02013-05-03 19:08:08 -070053 : encoder_(encoder), iter_(NULL) {}
John Koleszarb9180fc2012-05-16 15:27:00 -070054
Yaowu Xuf883b422016-08-30 14:01:10 -070055 const aom_codec_cx_pkt_t *Next() {
56 return aom_codec_get_cx_data(encoder_, &iter_);
John Koleszarb9180fc2012-05-16 15:27:00 -070057 }
58
59 private:
Yaowu Xuf883b422016-08-30 14:01:10 -070060 aom_codec_ctx_t *encoder_;
61 aom_codec_iter_t iter_;
John Koleszarb9180fc2012-05-16 15:27:00 -070062};
63
Yaowu Xuc27fc142016-08-22 16:08:15 -070064// Implements an in-memory store for libaom twopass statistics
John Koleszarb9180fc2012-05-16 15:27:00 -070065class TwopassStatsStore {
66 public:
Yaowu Xuf883b422016-08-30 14:01:10 -070067 void Append(const aom_codec_cx_pkt_t &pkt) {
John Koleszarb9180fc2012-05-16 15:27:00 -070068 buffer_.append(reinterpret_cast<char *>(pkt.data.twopass_stats.buf),
69 pkt.data.twopass_stats.sz);
70 }
71
Yaowu Xuf883b422016-08-30 14:01:10 -070072 aom_fixed_buf_t buf() {
73 const aom_fixed_buf_t buf = { &buffer_[0], buffer_.size() };
John Koleszarb9180fc2012-05-16 15:27:00 -070074 return buf;
75 }
76
clang-format3a826f12016-08-11 17:46:05 -070077 void Reset() { buffer_.clear(); }
Adrian Grange30f58b52012-10-02 09:36:41 -070078
John Koleszarb9180fc2012-05-16 15:27:00 -070079 protected:
clang-format3a826f12016-08-11 17:46:05 -070080 std::string buffer_;
John Koleszarb9180fc2012-05-16 15:27:00 -070081};
82
John Koleszarb9180fc2012-05-16 15:27:00 -070083// Provides a simplified interface to manage one video encoding pass, given
84// a configuration and video source.
85//
86// TODO(jkoleszar): The exact services it provides and the appropriate
87// level of abstraction will be fleshed out as more tests are written.
88class Encoder {
89 public:
Yaowu Xuf883b422016-08-30 14:01:10 -070090 Encoder(aom_codec_enc_cfg_t cfg, unsigned long deadline,
Adrian Grange4206c6d2012-10-02 11:03:09 -070091 const unsigned long init_flags, TwopassStatsStore *stats)
John Koleszar706cafe2013-01-18 11:51:12 -080092 : cfg_(cfg), deadline_(deadline), init_flags_(init_flags), stats_(stats) {
John Koleszarb9180fc2012-05-16 15:27:00 -070093 memset(&encoder_, 0, sizeof(encoder_));
94 }
95
Yaowu Xuf883b422016-08-30 14:01:10 -070096 virtual ~Encoder() { aom_codec_destroy(&encoder_); }
John Koleszarb9180fc2012-05-16 15:27:00 -070097
clang-format3a826f12016-08-11 17:46:05 -070098 CxDataIterator GetCxData() { return CxDataIterator(&encoder_); }
John Koleszarb9180fc2012-05-16 15:27:00 -070099
Yunqing Wang36664782014-12-12 14:34:30 -0800100 void InitEncoder(VideoSource *video);
101
Yaowu Xuf883b422016-08-30 14:01:10 -0700102 const aom_image_t *GetPreviewFrame() {
103 return aom_codec_get_preview_frame(&encoder_);
Yaowu Xuc953aea2012-08-30 13:43:15 -0700104 }
Yaowu Xuf883b422016-08-30 14:01:10 -0700105 // This is a thin wrapper around aom_codec_encode(), so refer to
106 // aom_encoder.h for its semantics.
Adrian Grange4206c6d2012-10-02 11:03:09 -0700107 void EncodeFrame(VideoSource *video, const unsigned long frame_flags);
John Koleszarb9180fc2012-05-16 15:27:00 -0700108
109 // Convenience wrapper for EncodeFrame()
clang-format3a826f12016-08-11 17:46:05 -0700110 void EncodeFrame(VideoSource *video) { EncodeFrame(video, 0); }
John Koleszarb9180fc2012-05-16 15:27:00 -0700111
John Koleszar606ac452012-07-10 15:43:44 -0700112 void Control(int ctrl_id, int arg) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700113 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
114 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
John Koleszar606ac452012-07-10 15:43:44 -0700115 }
116
Yaowu Xu7c514e22015-09-28 15:55:46 -0700117 void Control(int ctrl_id, int *arg) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700118 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
119 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
Yaowu Xu7c514e22015-09-28 15:55:46 -0700120 }
121
Yaowu Xuf883b422016-08-30 14:01:10 -0700122 void Control(int ctrl_id, struct aom_scaling_mode *arg) {
123 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
124 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
John Koleszar88f99f42013-02-06 12:44:20 -0800125 }
126
Yaowu Xuf883b422016-08-30 14:01:10 -0700127#if CONFIG_AV1_ENCODER
128 void Control(int ctrl_id, aom_active_map_t *arg) {
129 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
130 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
Alex Conversea5654692014-03-11 16:40:57 -0700131 }
132#endif
133
Yaowu Xuf883b422016-08-30 14:01:10 -0700134 void Config(const aom_codec_enc_cfg_t *cfg) {
135 const aom_codec_err_t res = aom_codec_enc_config_set(&encoder_, cfg);
136 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
Alex Converse797a2552015-01-15 13:56:55 -0800137 cfg_ = *cfg;
138 }
139
clang-format3a826f12016-08-11 17:46:05 -0700140 void set_deadline(unsigned long deadline) { deadline_ = deadline; }
John Koleszarb9180fc2012-05-16 15:27:00 -0700141
142 protected:
Yaowu Xuf883b422016-08-30 14:01:10 -0700143 virtual aom_codec_iface_t *CodecInterface() const = 0;
John Koleszar706cafe2013-01-18 11:51:12 -0800144
John Koleszarb9180fc2012-05-16 15:27:00 -0700145 const char *EncoderError() {
Yaowu Xuf883b422016-08-30 14:01:10 -0700146 const char *detail = aom_codec_error_detail(&encoder_);
147 return detail ? detail : aom_codec_error(&encoder_);
John Koleszarb9180fc2012-05-16 15:27:00 -0700148 }
149
150 // Encode an image
Adrian Grange4206c6d2012-10-02 11:03:09 -0700151 void EncodeFrameInternal(const VideoSource &video,
152 const unsigned long frame_flags);
John Koleszarb9180fc2012-05-16 15:27:00 -0700153
154 // Flush the encoder on EOS
155 void Flush();
156
Yaowu Xuf883b422016-08-30 14:01:10 -0700157 aom_codec_ctx_t encoder_;
158 aom_codec_enc_cfg_t cfg_;
clang-format3a826f12016-08-11 17:46:05 -0700159 unsigned long deadline_;
160 unsigned long init_flags_;
161 TwopassStatsStore *stats_;
John Koleszarb9180fc2012-05-16 15:27:00 -0700162};
163
John Koleszarb9180fc2012-05-16 15:27:00 -0700164// Common test functionality for all Encoder tests.
165//
166// This class is a mixin which provides the main loop common to all
167// encoder tests. It provides hooks which can be overridden by subclasses
168// to implement each test's specific behavior, while centralizing the bulk
169// of the boilerplate. Note that it doesn't inherit the gtest testing
170// classes directly, so that tests can be parameterized differently.
171class EncoderTest {
172 protected:
John Koleszar706cafe2013-01-18 11:51:12 -0800173 explicit EncoderTest(const CodecFactory *codec)
174 : codec_(codec), abort_(false), init_flags_(0), frame_flags_(0),
Frank Galligan45f9ee22015-04-14 15:01:56 -0700175 last_pts_(0) {
176 // Default to 1 thread.
177 cfg_.g_threads = 1;
178 }
John Koleszarb9180fc2012-05-16 15:27:00 -0700179
180 virtual ~EncoderTest() {}
181
182 // Initialize the cfg_ member with the default configuration.
John Koleszar706cafe2013-01-18 11:51:12 -0800183 void InitializeConfig();
John Koleszarb9180fc2012-05-16 15:27:00 -0700184
185 // Map the TestMode enum to the deadline_ and passes_ variables.
186 void SetMode(TestMode mode);
187
hkuang93536072014-11-20 15:39:56 -0800188 // Set encoder flag.
189 void set_init_flags(unsigned long flag) { // NOLINT(runtime/int)
190 init_flags_ = flag;
191 }
192
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800193 // Main loop
John Koleszarb9180fc2012-05-16 15:27:00 -0700194 virtual void RunLoop(VideoSource *video);
195
196 // Hook to be called at the beginning of a pass.
James Zerncae810a2014-08-22 11:58:48 -0700197 virtual void BeginPassHook(unsigned int /*pass*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700198
199 // Hook to be called at the end of a pass.
200 virtual void EndPassHook() {}
201
202 // Hook to be called before encoding a frame.
clang-format3a826f12016-08-11 17:46:05 -0700203 virtual void PreEncodeFrameHook(VideoSource * /*video*/) {}
204 virtual void PreEncodeFrameHook(VideoSource * /*video*/,
205 Encoder * /*encoder*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700206
207 // Hook to be called on every compressed data packet.
Yaowu Xuf883b422016-08-30 14:01:10 -0700208 virtual void FramePktHook(const aom_codec_cx_pkt_t * /*pkt*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700209
Adrian Grangee6109db2012-10-02 11:27:29 -0700210 // Hook to be called on every PSNR packet.
Yaowu Xuf883b422016-08-30 14:01:10 -0700211 virtual void PSNRPktHook(const aom_codec_cx_pkt_t * /*pkt*/) {}
Adrian Grangee6109db2012-10-02 11:27:29 -0700212
John Koleszarb9180fc2012-05-16 15:27:00 -0700213 // Hook to determine whether the encode loop should continue.
James Zern1c05e9d2013-06-25 17:53:20 -0700214 virtual bool Continue() const {
215 return !(::testing::Test::HasFatalFailure() || abort_);
216 }
John Koleszarb9180fc2012-05-16 15:27:00 -0700217
clang-format3a826f12016-08-11 17:46:05 -0700218 const CodecFactory *codec_;
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800219 // Hook to determine whether to decode frame after encoding
220 virtual bool DoDecode() const { return 1; }
221
222 // Hook to handle encode/decode mismatch
Yaowu Xuf883b422016-08-30 14:01:10 -0700223 virtual void MismatchHook(const aom_image_t *img1, const aom_image_t *img2);
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800224
John Koleszar88f99f42013-02-06 12:44:20 -0800225 // Hook to be called on every decompressed frame.
Yaowu Xuf883b422016-08-30 14:01:10 -0700226 virtual void DecompressedFrameHook(const aom_image_t & /*img*/,
227 aom_codec_pts_t /*pts*/) {}
John Koleszar88f99f42013-02-06 12:44:20 -0800228
Jim Bankoski943e4322014-07-17 06:31:50 -0700229 // Hook to be called to handle decode result. Return true to continue.
Yaowu Xuf883b422016-08-30 14:01:10 -0700230 virtual bool HandleDecodeResult(const aom_codec_err_t res_dec,
Jim Bankoski943e4322014-07-17 06:31:50 -0700231 Decoder *decoder) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700232 EXPECT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
233 return AOM_CODEC_OK == res_dec;
Jim Bankoski943e4322014-07-17 06:31:50 -0700234 }
235
John Koleszar522d4bf2013-03-05 12:23:34 -0800236 // Hook that can modify the encoder's output data
Yaowu Xuf883b422016-08-30 14:01:10 -0700237 virtual const aom_codec_cx_pkt_t *MutateEncoderOutputHook(
238 const aom_codec_cx_pkt_t *pkt) {
John Koleszar522d4bf2013-03-05 12:23:34 -0800239 return pkt;
240 }
241
clang-format3a826f12016-08-11 17:46:05 -0700242 bool abort_;
Yaowu Xuf883b422016-08-30 14:01:10 -0700243 aom_codec_enc_cfg_t cfg_;
244 aom_codec_dec_cfg_t dec_cfg_;
clang-format3a826f12016-08-11 17:46:05 -0700245 unsigned int passes_;
246 unsigned long deadline_;
247 TwopassStatsStore stats_;
248 unsigned long init_flags_;
249 unsigned long frame_flags_;
Yaowu Xuf883b422016-08-30 14:01:10 -0700250 aom_codec_pts_t last_pts_;
John Koleszarb9180fc2012-05-16 15:27:00 -0700251};
252
Yaowu Xuc27fc142016-08-22 16:08:15 -0700253} // namespace libaom_test
John Koleszarb9180fc2012-05-16 15:27:00 -0700254
John Koleszarb9180fc2012-05-16 15:27:00 -0700255#endif // TEST_ENCODE_TEST_DRIVER_H_