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
, kAllIntra
};
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_(nullptr) {}
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 aom_codec_flags_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
, aom_enc_frame_flags_t 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 void Control(int ctrl_id
, struct aom_svc_layer_id
*arg
) {
123 const aom_codec_err_t res
= aom_codec_control(&encoder_
, ctrl_id
, arg
);
124 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
127 void Control(int ctrl_id
, struct aom_svc_ref_frame_config
*arg
) {
128 const aom_codec_err_t res
= aom_codec_control(&encoder_
, ctrl_id
, arg
);
129 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
132 void Control(int ctrl_id
, struct aom_svc_ref_frame_comp_pred
*arg
) {
133 const aom_codec_err_t res
= aom_codec_control(&encoder_
, ctrl_id
, arg
);
134 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
137 void Control(int ctrl_id
, struct aom_svc_params
*arg
) {
138 const aom_codec_err_t res
= aom_codec_control(&encoder_
, ctrl_id
, arg
);
139 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
142 void Control(int ctrl_id
, struct aom_ext_part_funcs
*arg
) {
143 const aom_codec_err_t res
= aom_codec_control(&encoder_
, ctrl_id
, arg
);
144 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
147 #if CONFIG_AV1_ENCODER
148 void Control(int ctrl_id
, aom_active_map_t
*arg
) {
149 const aom_codec_err_t res
= aom_codec_control(&encoder_
, ctrl_id
, arg
);
150 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
154 void SetOption(const char *name
, const char *value
) {
155 const aom_codec_err_t res
= aom_codec_set_option(&encoder_
, name
, value
);
156 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
159 void Config(const aom_codec_enc_cfg_t
*cfg
) {
160 const aom_codec_err_t res
= aom_codec_enc_config_set(&encoder_
, cfg
);
161 ASSERT_EQ(AOM_CODEC_OK
, res
) << EncoderError();
166 virtual aom_codec_iface_t
*CodecInterface() const = 0;
168 const char *EncoderError() {
169 const char *detail
= aom_codec_error_detail(&encoder_
);
170 return detail
? detail
: aom_codec_error(&encoder_
);
174 void EncodeFrameInternal(const VideoSource
&video
,
175 aom_enc_frame_flags_t frame_flags
);
177 // Flush the encoder on EOS
180 aom_codec_ctx_t encoder_
;
181 aom_codec_enc_cfg_t cfg_
;
182 aom_codec_flags_t init_flags_
;
183 TwopassStatsStore
*stats_
;
186 // Common test functionality for all Encoder tests.
188 // This class is a mixin which provides the main loop common to all
189 // encoder tests. It provides hooks which can be overridden by subclasses
190 // to implement each test's specific behavior, while centralizing the bulk
191 // of the boilerplate. Note that it doesn't inherit the gtest testing
192 // classes directly, so that tests can be parameterized differently.
195 explicit EncoderTest(const CodecFactory
*codec
)
196 : codec_(codec
), abort_(false), init_flags_(0), frame_flags_(0),
198 // Default to 1 thread.
202 virtual ~EncoderTest() = default;
204 // Initialize the cfg_ member with the default configuration for the
205 // TestMode enum and maps the TestMode enum to the passes_ variable.
206 void InitializeConfig(TestMode mode
);
209 void set_init_flags(aom_codec_flags_t flag
) { init_flags_
= flag
; }
212 virtual void RunLoop(VideoSource
*video
);
214 // Hook to be called at the beginning of a pass.
215 virtual void BeginPassHook(unsigned int /*pass*/) {}
217 // Hook to be called at the end of a pass.
218 virtual void EndPassHook() {}
220 // Hook to be called before encoding a frame.
221 virtual void PreEncodeFrameHook(VideoSource
* /*video*/,
222 Encoder
* /*encoder*/) {}
224 virtual void PostEncodeFrameHook(Encoder
* /*encoder*/) {}
226 // Hook to be called on every compressed data packet.
227 virtual void FramePktHook(const aom_codec_cx_pkt_t
* /*pkt*/) {}
229 // Hook to be called on every PSNR packet.
230 virtual void PSNRPktHook(const aom_codec_cx_pkt_t
* /*pkt*/) {}
232 // Hook to be called on every first pass stats packet.
233 virtual void StatsPktHook(const aom_codec_cx_pkt_t
* /*pkt*/) {}
235 // Calculates SSIM at frame level.
236 virtual void CalculateFrameLevelSSIM(const aom_image_t
* /*img_src*/,
237 const aom_image_t
* /*img_enc*/,
238 aom_bit_depth_t
/*bit_depth*/,
239 unsigned int /*input_bit_depth*/) {}
241 // Hook to determine whether the encode loop should continue.
242 virtual bool Continue() const {
243 return !(::testing::Test::HasFatalFailure() || abort_
);
246 // Hook to determine whether to decode frame after encoding
247 virtual bool DoDecode() const { return true; }
249 // Hook to determine whether to decode invisible frames after encoding
250 virtual bool DoDecodeInvisible() const { return true; }
252 // Hook to handle encode/decode mismatch
253 virtual void MismatchHook(const aom_image_t
*img1
, const aom_image_t
*img2
);
255 // Hook to be called on every decompressed frame.
256 virtual void DecompressedFrameHook(const aom_image_t
& /*img*/,
257 aom_codec_pts_t
/*pts*/) {}
259 // Hook to be called to handle decode result. Return true to continue.
260 virtual bool HandleDecodeResult(const aom_codec_err_t res_dec
,
262 EXPECT_EQ(AOM_CODEC_OK
, res_dec
) << decoder
->DecodeError();
263 return AOM_CODEC_OK
== res_dec
;
266 virtual int GetNumSpatialLayers() { return 1; }
268 // Hook that can modify the encoder's output data
269 virtual const aom_codec_cx_pkt_t
*MutateEncoderOutputHook(
270 const aom_codec_cx_pkt_t
*pkt
) {
274 const CodecFactory
*codec_
;
276 aom_codec_enc_cfg_t cfg_
;
277 unsigned int passes_
;
278 TwopassStatsStore stats_
;
279 aom_codec_flags_t init_flags_
;
280 aom_enc_frame_flags_t frame_flags_
;
284 } // namespace libaom_test
286 #endif // AOM_TEST_ENCODE_TEST_DRIVER_H_