blob: 97c1bf860d38992896f671bd166caf3df359dacc [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
Thomas Daede6eca8352017-03-17 14:14:12 -070030enum TestMode { kRealTime, kOnePassGood, kTwoPassGood };
31#define ALL_TEST_MODES \
Yaowu Xuc27fc142016-08-22 16:08:15 -070032 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood, \
Thomas Daede6eca8352017-03-17 14:14:12 -070033 ::libaom_test::kTwoPassGood)
John Koleszar2fb29ff2012-05-23 12:55:27 -070034
Thomas Daede6eca8352017-03-17 14:14:12 -070035#define ONE_PASS_TEST_MODES \
36 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood)
37
38#define TWO_PASS_TEST_MODES ::testing::Values(::libaom_test::kTwoPassGood)
John Koleszarb9180fc2012-05-16 15:27:00 -070039
Yaowu Xuc27fc142016-08-22 16:08:15 -070040// Provides an object to handle the libaom get_cx_data() iteration pattern
John Koleszarb9180fc2012-05-16 15:27:00 -070041class CxDataIterator {
42 public:
Yaowu Xuf883b422016-08-30 14:01:10 -070043 explicit CxDataIterator(aom_codec_ctx_t *encoder)
James Zern51b7fd02013-05-03 19:08:08 -070044 : encoder_(encoder), iter_(NULL) {}
John Koleszarb9180fc2012-05-16 15:27:00 -070045
Yaowu Xuf883b422016-08-30 14:01:10 -070046 const aom_codec_cx_pkt_t *Next() {
47 return aom_codec_get_cx_data(encoder_, &iter_);
John Koleszarb9180fc2012-05-16 15:27:00 -070048 }
49
50 private:
Yaowu Xuf883b422016-08-30 14:01:10 -070051 aom_codec_ctx_t *encoder_;
52 aom_codec_iter_t iter_;
John Koleszarb9180fc2012-05-16 15:27:00 -070053};
54
Yaowu Xuc27fc142016-08-22 16:08:15 -070055// Implements an in-memory store for libaom twopass statistics
John Koleszarb9180fc2012-05-16 15:27:00 -070056class TwopassStatsStore {
57 public:
Yaowu Xuf883b422016-08-30 14:01:10 -070058 void Append(const aom_codec_cx_pkt_t &pkt) {
John Koleszarb9180fc2012-05-16 15:27:00 -070059 buffer_.append(reinterpret_cast<char *>(pkt.data.twopass_stats.buf),
60 pkt.data.twopass_stats.sz);
61 }
62
Yaowu Xuf883b422016-08-30 14:01:10 -070063 aom_fixed_buf_t buf() {
64 const aom_fixed_buf_t buf = { &buffer_[0], buffer_.size() };
John Koleszarb9180fc2012-05-16 15:27:00 -070065 return buf;
66 }
67
clang-format3a826f12016-08-11 17:46:05 -070068 void Reset() { buffer_.clear(); }
Adrian Grange30f58b52012-10-02 09:36:41 -070069
John Koleszarb9180fc2012-05-16 15:27:00 -070070 protected:
clang-format3a826f12016-08-11 17:46:05 -070071 std::string buffer_;
John Koleszarb9180fc2012-05-16 15:27:00 -070072};
73
John Koleszarb9180fc2012-05-16 15:27:00 -070074// Provides a simplified interface to manage one video encoding pass, given
75// a configuration and video source.
76//
77// TODO(jkoleszar): The exact services it provides and the appropriate
78// level of abstraction will be fleshed out as more tests are written.
79class Encoder {
80 public:
Yaowu Xuf883b422016-08-30 14:01:10 -070081 Encoder(aom_codec_enc_cfg_t cfg, unsigned long deadline,
Adrian Grange4206c6d2012-10-02 11:03:09 -070082 const unsigned long init_flags, TwopassStatsStore *stats)
John Koleszar706cafe2013-01-18 11:51:12 -080083 : cfg_(cfg), deadline_(deadline), init_flags_(init_flags), stats_(stats) {
John Koleszarb9180fc2012-05-16 15:27:00 -070084 memset(&encoder_, 0, sizeof(encoder_));
85 }
86
Yaowu Xuf883b422016-08-30 14:01:10 -070087 virtual ~Encoder() { aom_codec_destroy(&encoder_); }
John Koleszarb9180fc2012-05-16 15:27:00 -070088
clang-format3a826f12016-08-11 17:46:05 -070089 CxDataIterator GetCxData() { return CxDataIterator(&encoder_); }
John Koleszarb9180fc2012-05-16 15:27:00 -070090
Yunqing Wang36664782014-12-12 14:34:30 -080091 void InitEncoder(VideoSource *video);
92
Yaowu Xuf883b422016-08-30 14:01:10 -070093 const aom_image_t *GetPreviewFrame() {
94 return aom_codec_get_preview_frame(&encoder_);
Yaowu Xuc953aea2012-08-30 13:43:15 -070095 }
Yaowu Xuf883b422016-08-30 14:01:10 -070096 // This is a thin wrapper around aom_codec_encode(), so refer to
97 // aom_encoder.h for its semantics.
Adrian Grange4206c6d2012-10-02 11:03:09 -070098 void EncodeFrame(VideoSource *video, const unsigned long frame_flags);
John Koleszarb9180fc2012-05-16 15:27:00 -070099
100 // Convenience wrapper for EncodeFrame()
clang-format3a826f12016-08-11 17:46:05 -0700101 void EncodeFrame(VideoSource *video) { EncodeFrame(video, 0); }
John Koleszarb9180fc2012-05-16 15:27:00 -0700102
John Koleszar606ac452012-07-10 15:43:44 -0700103 void Control(int ctrl_id, int arg) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700104 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
105 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
John Koleszar606ac452012-07-10 15:43:44 -0700106 }
107
Yaowu Xu7c514e22015-09-28 15:55:46 -0700108 void Control(int ctrl_id, int *arg) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700109 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
110 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
Yaowu Xu7c514e22015-09-28 15:55:46 -0700111 }
112
Yaowu Xuf883b422016-08-30 14:01:10 -0700113 void Control(int ctrl_id, struct aom_scaling_mode *arg) {
114 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
115 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
John Koleszar88f99f42013-02-06 12:44:20 -0800116 }
117
Yaowu Xuf883b422016-08-30 14:01:10 -0700118#if CONFIG_AV1_ENCODER
119 void Control(int ctrl_id, aom_active_map_t *arg) {
120 const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
121 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
Alex Conversea5654692014-03-11 16:40:57 -0700122 }
123#endif
124
Yaowu Xuf883b422016-08-30 14:01:10 -0700125 void Config(const aom_codec_enc_cfg_t *cfg) {
126 const aom_codec_err_t res = aom_codec_enc_config_set(&encoder_, cfg);
127 ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
Alex Converse797a2552015-01-15 13:56:55 -0800128 cfg_ = *cfg;
129 }
130
clang-format3a826f12016-08-11 17:46:05 -0700131 void set_deadline(unsigned long deadline) { deadline_ = deadline; }
John Koleszarb9180fc2012-05-16 15:27:00 -0700132
133 protected:
Yaowu Xuf883b422016-08-30 14:01:10 -0700134 virtual aom_codec_iface_t *CodecInterface() const = 0;
John Koleszar706cafe2013-01-18 11:51:12 -0800135
John Koleszarb9180fc2012-05-16 15:27:00 -0700136 const char *EncoderError() {
Yaowu Xuf883b422016-08-30 14:01:10 -0700137 const char *detail = aom_codec_error_detail(&encoder_);
138 return detail ? detail : aom_codec_error(&encoder_);
John Koleszarb9180fc2012-05-16 15:27:00 -0700139 }
140
141 // Encode an image
Adrian Grange4206c6d2012-10-02 11:03:09 -0700142 void EncodeFrameInternal(const VideoSource &video,
143 const unsigned long frame_flags);
John Koleszarb9180fc2012-05-16 15:27:00 -0700144
145 // Flush the encoder on EOS
146 void Flush();
147
Yaowu Xuf883b422016-08-30 14:01:10 -0700148 aom_codec_ctx_t encoder_;
149 aom_codec_enc_cfg_t cfg_;
clang-format3a826f12016-08-11 17:46:05 -0700150 unsigned long deadline_;
151 unsigned long init_flags_;
152 TwopassStatsStore *stats_;
John Koleszarb9180fc2012-05-16 15:27:00 -0700153};
154
John Koleszarb9180fc2012-05-16 15:27:00 -0700155// Common test functionality for all Encoder tests.
156//
157// This class is a mixin which provides the main loop common to all
158// encoder tests. It provides hooks which can be overridden by subclasses
159// to implement each test's specific behavior, while centralizing the bulk
160// of the boilerplate. Note that it doesn't inherit the gtest testing
161// classes directly, so that tests can be parameterized differently.
162class EncoderTest {
163 protected:
John Koleszar706cafe2013-01-18 11:51:12 -0800164 explicit EncoderTest(const CodecFactory *codec)
165 : codec_(codec), abort_(false), init_flags_(0), frame_flags_(0),
Thomas Daede80826142017-03-20 15:44:24 -0700166 last_pts_(0), mode_(kRealTime) {
Frank Galligan45f9ee22015-04-14 15:01:56 -0700167 // Default to 1 thread.
168 cfg_.g_threads = 1;
169 }
John Koleszarb9180fc2012-05-16 15:27:00 -0700170
171 virtual ~EncoderTest() {}
172
173 // Initialize the cfg_ member with the default configuration.
John Koleszar706cafe2013-01-18 11:51:12 -0800174 void InitializeConfig();
John Koleszarb9180fc2012-05-16 15:27:00 -0700175
176 // Map the TestMode enum to the deadline_ and passes_ variables.
177 void SetMode(TestMode mode);
178
hkuang93536072014-11-20 15:39:56 -0800179 // Set encoder flag.
180 void set_init_flags(unsigned long flag) { // NOLINT(runtime/int)
181 init_flags_ = flag;
182 }
183
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800184 // Main loop
John Koleszarb9180fc2012-05-16 15:27:00 -0700185 virtual void RunLoop(VideoSource *video);
186
187 // Hook to be called at the beginning of a pass.
James Zerncae810a2014-08-22 11:58:48 -0700188 virtual void BeginPassHook(unsigned int /*pass*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700189
190 // Hook to be called at the end of a pass.
191 virtual void EndPassHook() {}
192
193 // Hook to be called before encoding a frame.
clang-format3a826f12016-08-11 17:46:05 -0700194 virtual void PreEncodeFrameHook(VideoSource * /*video*/) {}
195 virtual void PreEncodeFrameHook(VideoSource * /*video*/,
196 Encoder * /*encoder*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700197
198 // Hook to be called on every compressed data packet.
Yaowu Xuf883b422016-08-30 14:01:10 -0700199 virtual void FramePktHook(const aom_codec_cx_pkt_t * /*pkt*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700200
Adrian Grangee6109db2012-10-02 11:27:29 -0700201 // Hook to be called on every PSNR packet.
Yaowu Xuf883b422016-08-30 14:01:10 -0700202 virtual void PSNRPktHook(const aom_codec_cx_pkt_t * /*pkt*/) {}
Adrian Grangee6109db2012-10-02 11:27:29 -0700203
John Koleszarb9180fc2012-05-16 15:27:00 -0700204 // Hook to determine whether the encode loop should continue.
James Zern1c05e9d2013-06-25 17:53:20 -0700205 virtual bool Continue() const {
206 return !(::testing::Test::HasFatalFailure() || abort_);
207 }
John Koleszarb9180fc2012-05-16 15:27:00 -0700208
clang-format3a826f12016-08-11 17:46:05 -0700209 const CodecFactory *codec_;
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800210 // Hook to determine whether to decode frame after encoding
211 virtual bool DoDecode() const { return 1; }
212
213 // Hook to handle encode/decode mismatch
Yaowu Xuf883b422016-08-30 14:01:10 -0700214 virtual void MismatchHook(const aom_image_t *img1, const aom_image_t *img2);
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800215
John Koleszar88f99f42013-02-06 12:44:20 -0800216 // Hook to be called on every decompressed frame.
Yaowu Xuf883b422016-08-30 14:01:10 -0700217 virtual void DecompressedFrameHook(const aom_image_t & /*img*/,
218 aom_codec_pts_t /*pts*/) {}
John Koleszar88f99f42013-02-06 12:44:20 -0800219
Jim Bankoski943e4322014-07-17 06:31:50 -0700220 // Hook to be called to handle decode result. Return true to continue.
Yaowu Xuf883b422016-08-30 14:01:10 -0700221 virtual bool HandleDecodeResult(const aom_codec_err_t res_dec,
Jim Bankoski943e4322014-07-17 06:31:50 -0700222 Decoder *decoder) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700223 EXPECT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
224 return AOM_CODEC_OK == res_dec;
Jim Bankoski943e4322014-07-17 06:31:50 -0700225 }
226
John Koleszar522d4bf2013-03-05 12:23:34 -0800227 // Hook that can modify the encoder's output data
Yaowu Xuf883b422016-08-30 14:01:10 -0700228 virtual const aom_codec_cx_pkt_t *MutateEncoderOutputHook(
229 const aom_codec_cx_pkt_t *pkt) {
John Koleszar522d4bf2013-03-05 12:23:34 -0800230 return pkt;
231 }
232
clang-format3a826f12016-08-11 17:46:05 -0700233 bool abort_;
Yaowu Xuf883b422016-08-30 14:01:10 -0700234 aom_codec_enc_cfg_t cfg_;
clang-format3a826f12016-08-11 17:46:05 -0700235 unsigned int passes_;
236 unsigned long deadline_;
237 TwopassStatsStore stats_;
238 unsigned long init_flags_;
239 unsigned long frame_flags_;
Yaowu Xuf883b422016-08-30 14:01:10 -0700240 aom_codec_pts_t last_pts_;
Thomas Daede80826142017-03-20 15:44:24 -0700241 TestMode mode_;
John Koleszarb9180fc2012-05-16 15:27:00 -0700242};
243
Yaowu Xuc27fc142016-08-22 16:08:15 -0700244} // namespace libaom_test
John Koleszarb9180fc2012-05-16 15:27:00 -0700245
John Koleszarb9180fc2012-05-16 15:27:00 -0700246#endif // TEST_ENCODE_TEST_DRIVER_H_