2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
11 #ifndef AOM_TEST_ENCODE_TEST_DRIVER_H_
12 #define AOM_TEST_ENCODE_TEST_DRIVER_H_
17 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
19 #include "config/aom_config.h"
21 #if CONFIG_AV1_ENCODER
22 #include "aom/aomcx.h"
24 #include "aom/aom_encoder.h"
26 namespace libaom_test
{
31 enum TestMode
{ kRealTime
, kOnePassGood
, kTwoPassGood
};
32 #define ALL_TEST_MODES \
33 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood, \
34 ::libaom_test::kTwoPassGood)
36 #define ONE_PASS_TEST_MODES \
37 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood)
39 #define TWO_PASS_TEST_MODES ::testing::Values(::libaom_test::kTwoPassGood)
41 #define NONREALTIME_TEST_MODES \
42 ::testing::Values(::libaom_test::kOnePassGood, ::libaom_test::kTwoPassGood)
44 // Provides an object to handle the libaom get_cx_data() iteration pattern
45 class CxDataIterator
{
47 explicit CxDataIterator(aom_codec_ctx_t
*encoder
)
48 : encoder_(encoder
), iter_(NULL
) {}
50 const aom_codec_cx_pkt_t
*Next() {
51 return aom_codec_get_cx_data(encoder_
, &iter_
);
55 aom_codec_ctx_t
*encoder_
;
56 aom_codec_iter_t iter_
;
59 // Implements an in-memory store for libaom twopass statistics
60 class TwopassStatsStore
{
62 void Append(const aom_codec_cx_pkt_t
&pkt
) {
63 buffer_
.append(reinterpret_cast<char *>(pkt
.data
.twopass_stats
.buf
),
64 pkt
.data
.twopass_stats
.sz
);
67 aom_fixed_buf_t
buf() {
68 const aom_fixed_buf_t buf
= { &buffer_
[0], buffer_
.size() };
72 void Reset() { buffer_
.clear(); }
78 // Provides a simplified interface to manage one video encoding pass, given
79 // a configuration and video source.
81 // TODO(jkoleszar): The exact services it provides and the appropriate
82 // level of abstraction will be fleshed out as more tests are written.
85 Encoder(aom_codec_enc_cfg_t cfg
, const uint32_t init_flags
,
86 TwopassStatsStore
*stats
)
87 : cfg_(cfg
), init_flags_(init_flags
), stats_(stats
) {
88 memset(&encoder_
, 0, sizeof(encoder_
));
91 virtual ~Encoder() { aom_codec_destroy(&encoder_
); }
93 CxDataIterator
GetCxData() { return CxDataIterator(&encoder_
); }
95 void InitEncoder(VideoSource
*video
);
97 const aom_image_t
*GetPreviewFrame() {
98 return aom_codec_get_preview_frame(&encoder_
);
100 // This is a thin wrapper around aom_codec_encode(), so refer to
101 // aom_encoder.h for its semantics.
102 void EncodeFrame(VideoSource
*video
, const unsigned long frame_flags
);
104 // Convenience wrapper for EncodeFrame()
105 void EncodeFrame(VideoSource
*video
) { EncodeFrame(video
, 0); }
107 void Control(int ctrl_id
, int arg
) {
108 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
109 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
112 void Control(int ctrl_id
, int *arg
) {
113 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
114 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
117 void Control(int ctrl_id
, struct aom_scaling_mode
*arg
) {
118 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
119 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
122 #if CONFIG_AV1_ENCODER
123 void Control(int ctrl_id
, aom_active_map_t
*arg
) {
124 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
125 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
129 void Config(const aom_codec_enc_cfg_t
*cfg
) {
130 const aom_codec_err_t res
= aom_codec_enc_config_set(&encoder_
, cfg
);
131 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
136 virtual aom_codec_iface_t
*CodecInterface() const = 0;
138 const char *EncoderError() {
139 const char *detail
= aom_codec_error_detail(&encoder_
);
140 return detail
? detail
: aom_codec_error(&encoder_
);
144 void EncodeFrameInternal(const VideoSource
&video
,
145 const unsigned long frame_flags
);
147 // Flush the encoder on EOS
150 aom_codec_ctx_t encoder_
;
151 aom_codec_enc_cfg_t cfg_
;
152 unsigned long init_flags_
;
153 TwopassStatsStore
*stats_
;
156 // Common test functionality for all Encoder tests.
158 // This class is a mixin which provides the main loop common to all
159 // encoder tests. It provides hooks which can be overridden by subclasses
160 // to implement each test's specific behavior, while centralizing the bulk
161 // of the boilerplate. Note that it doesn't inherit the gtest testing
162 // classes directly, so that tests can be parameterized differently.
165 explicit EncoderTest(const CodecFactory
*codec
)
166 : codec_(codec
), abort_(false), init_flags_(0), frame_flags_(0),
167 last_pts_(0), mode_(kRealTime
) {
168 // Default to 1 thread.
172 virtual ~EncoderTest() {}
174 // Initialize the cfg_ member with the default configuration.
175 void InitializeConfig();
177 // Map the TestMode enum to the passes_ variables.
178 void SetMode(TestMode mode
);
181 void set_init_flags(unsigned long flag
) { // NOLINT(runtime/int)
186 virtual void RunLoop(VideoSource
*video
);
188 // Hook to be called at the beginning of a pass.
189 virtual void BeginPassHook(unsigned int /*pass*/) {}
191 // Hook to be called at the end of a pass.
192 virtual void EndPassHook() {}
194 // Hook to be called before encoding a frame.
195 virtual void PreEncodeFrameHook(VideoSource
* /*video*/) {}
196 virtual void PreEncodeFrameHook(VideoSource
* /*video*/,
197 Encoder
* /*encoder*/) {}
199 // Hook to be called on every compressed data packet.
200 virtual void FramePktHook(const aom_codec_cx_pkt_t
* /*pkt*/) {}
202 // Hook to be called on every PSNR packet.
203 virtual void PSNRPktHook(const aom_codec_cx_pkt_t
* /*pkt*/) {}
205 // Hook to determine whether the encode loop should continue.
206 virtual bool Continue() const {
207 return !(::testing::Test::HasFatalFailure() || abort_
);
210 // Hook to determine whether to decode frame after encoding
211 virtual bool DoDecode() const { return true; }
213 // Hook to determine whether to decode invisible frames after encoding
214 virtual bool DoDecodeInvisible() const { return true; }
216 // Hook to handle encode/decode mismatch
217 virtual void MismatchHook(const aom_image_t
*img1
, const aom_image_t
*img2
);
219 // Hook to be called on every decompressed frame.
220 virtual void DecompressedFrameHook(const aom_image_t
& /*img*/,
221 aom_codec_pts_t
/*pts*/) {}
223 // Hook to be called to handle decode result. Return true to continue.
224 virtual bool HandleDecodeResult(const aom_codec_err_t res_dec
,
226 EXPECT_EQ(AOM_CODEC_OK
, res_dec
) << decoder
->DecodeError();
227 return AOM_CODEC_OK
== res_dec
;
230 // Hook that can modify the encoder's output data
231 virtual const aom_codec_cx_pkt_t
*MutateEncoderOutputHook(
232 const aom_codec_cx_pkt_t
*pkt
) {
236 const CodecFactory
*codec_
;
238 aom_codec_enc_cfg_t cfg_
;
239 unsigned int passes_
;
240 TwopassStatsStore stats_
;
241 unsigned long init_flags_
;
242 unsigned long frame_flags_
;
243 aom_codec_pts_t last_pts_
;
247 } // namespace libaom_test
249 #endif // AOM_TEST_ENCODE_TEST_DRIVER_H_