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 TEST_ENCODE_TEST_DRIVER_H_
12 #define TEST_ENCODE_TEST_DRIVER_H_
17 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
19 #include "./aom_config.h"
20 #if CONFIG_AV1_ENCODER
21 #include "aom/aomcx.h"
23 #include "aom/aom_encoder.h"
25 namespace libaom_test
{
30 enum TestMode
{ kRealTime
, kOnePassGood
, kTwoPassGood
};
31 #define ALL_TEST_MODES \
32 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood, \
33 ::libaom_test::kTwoPassGood)
35 #define ONE_PASS_TEST_MODES \
36 ::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood)
38 #define TWO_PASS_TEST_MODES ::testing::Values(::libaom_test::kTwoPassGood)
40 #define NONREALTIME_TEST_MODES \
41 ::testing::Values(::libaom_test::kOnePassGood, ::libaom_test::kTwoPassGood)
43 // Provides an object to handle the libaom get_cx_data() iteration pattern
44 class CxDataIterator
{
46 explicit CxDataIterator(aom_codec_ctx_t
*encoder
)
47 : encoder_(encoder
), iter_(NULL
) {}
49 const aom_codec_cx_pkt_t
*Next() {
50 return aom_codec_get_cx_data(encoder_
, &iter_
);
54 aom_codec_ctx_t
*encoder_
;
55 aom_codec_iter_t iter_
;
58 // Implements an in-memory store for libaom twopass statistics
59 class TwopassStatsStore
{
61 void Append(const aom_codec_cx_pkt_t
&pkt
) {
62 buffer_
.append(reinterpret_cast<char *>(pkt
.data
.twopass_stats
.buf
),
63 pkt
.data
.twopass_stats
.sz
);
66 aom_fixed_buf_t
buf() {
67 const aom_fixed_buf_t buf
= { &buffer_
[0], buffer_
.size() };
71 void Reset() { buffer_
.clear(); }
77 // Provides a simplified interface to manage one video encoding pass, given
78 // a configuration and video source.
80 // TODO(jkoleszar): The exact services it provides and the appropriate
81 // level of abstraction will be fleshed out as more tests are written.
84 Encoder(aom_codec_enc_cfg_t cfg
, const uint32_t init_flags
,
85 TwopassStatsStore
*stats
)
86 : cfg_(cfg
), init_flags_(init_flags
), stats_(stats
) {
87 memset(&encoder_
, 0, sizeof(encoder_
));
90 virtual ~Encoder() { aom_codec_destroy(&encoder_
); }
92 CxDataIterator
GetCxData() { return CxDataIterator(&encoder_
); }
94 void InitEncoder(VideoSource
*video
);
96 const aom_image_t
*GetPreviewFrame() {
97 return aom_codec_get_preview_frame(&encoder_
);
99 // This is a thin wrapper around aom_codec_encode(), so refer to
100 // aom_encoder.h for its semantics.
101 void EncodeFrame(VideoSource
*video
, const unsigned long frame_flags
);
103 // Convenience wrapper for EncodeFrame()
104 void EncodeFrame(VideoSource
*video
) { EncodeFrame(video
, 0); }
106 void Control(int ctrl_id
, int arg
) {
107 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
108 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
111 void Control(int ctrl_id
, int *arg
) {
112 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
113 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
116 void Control(int ctrl_id
, struct aom_scaling_mode
*arg
) {
117 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
118 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
121 #if CONFIG_AV1_ENCODER
122 void Control(int ctrl_id
, aom_active_map_t
*arg
) {
123 const aom_codec_err_t res
= aom_codec_control_(&encoder_
, ctrl_id
, arg
);
124 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
128 void Config(const aom_codec_enc_cfg_t
*cfg
) {
129 const aom_codec_err_t res
= aom_codec_enc_config_set(&encoder_
, cfg
);
130 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
135 virtual aom_codec_iface_t
*CodecInterface() const = 0;
137 const char *EncoderError() {
138 const char *detail
= aom_codec_error_detail(&encoder_
);
139 return detail
? detail
: aom_codec_error(&encoder_
);
143 void EncodeFrameInternal(const VideoSource
&video
,
144 const unsigned long frame_flags
);
146 // Flush the encoder on EOS
149 aom_codec_ctx_t encoder_
;
150 aom_codec_enc_cfg_t cfg_
;
151 unsigned long init_flags_
;
152 TwopassStatsStore
*stats_
;
155 // Common test functionality for all Encoder tests.
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.
164 explicit EncoderTest(const CodecFactory
*codec
)
165 : codec_(codec
), abort_(false), init_flags_(0), frame_flags_(0),
166 last_pts_(0), mode_(kRealTime
) {
167 // Default to 1 thread.
171 virtual ~EncoderTest() {}
173 // Initialize the cfg_ member with the default configuration.
174 void InitializeConfig();
176 // Map the TestMode enum to the passes_ variables.
177 void SetMode(TestMode mode
);
180 void set_init_flags(unsigned long flag
) { // NOLINT(runtime/int)
185 virtual void RunLoop(VideoSource
*video
);
187 // Hook to be called at the beginning of a pass.
188 virtual void BeginPassHook(unsigned int /*pass*/) {}
190 // Hook to be called at the end of a pass.
191 virtual void EndPassHook() {}
193 // Hook to be called before encoding a frame.
194 virtual void PreEncodeFrameHook(VideoSource
* /*video*/) {}
195 virtual void PreEncodeFrameHook(VideoSource
* /*video*/,
196 Encoder
* /*encoder*/) {}
198 // Hook to be called on every compressed data packet.
199 virtual void FramePktHook(const aom_codec_cx_pkt_t
* /*pkt*/) {}
201 // Hook to be called on every PSNR packet.
202 virtual void PSNRPktHook(const aom_codec_cx_pkt_t
* /*pkt*/) {}
204 // Hook to determine whether the encode loop should continue.
205 virtual bool Continue() const {
206 return !(::testing::Test::HasFatalFailure() || abort_
);
209 const CodecFactory
*codec_
;
210 // Hook to determine whether to decode frame after encoding
211 virtual bool DoDecode() const { return 1; }
213 // Hook to handle encode/decode mismatch
214 virtual void MismatchHook(const aom_image_t
*img1
, const aom_image_t
*img2
);
216 // Hook to be called on every decompressed frame.
217 virtual void DecompressedFrameHook(const aom_image_t
& /*img*/,
218 aom_codec_pts_t
/*pts*/) {}
220 // Hook to be called to handle decode result. Return true to continue.
221 virtual bool HandleDecodeResult(const aom_codec_err_t res_dec
,
223 EXPECT_EQ(AOM_CODEC_OK
, res_dec
) << decoder
->DecodeError();
224 return AOM_CODEC_OK
== res_dec
;
227 // Hook that can modify the encoder's output data
228 virtual const aom_codec_cx_pkt_t
*MutateEncoderOutputHook(
229 const aom_codec_cx_pkt_t
*pkt
) {
234 aom_codec_enc_cfg_t cfg_
;
235 unsigned int passes_
;
236 TwopassStatsStore stats_
;
237 unsigned long init_flags_
;
238 unsigned long frame_flags_
;
239 aom_codec_pts_t last_pts_
;
243 } // namespace libaom_test
245 #endif // TEST_ENCODE_TEST_DRIVER_H_