blob: a77bd647884548d98b88273bc62db273dd81fd61 [file] [log] [blame]
John Koleszarb9180fc2012-05-16 15:27:00 -07001/*
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#ifndef TEST_ENCODE_TEST_DRIVER_H_
11#define TEST_ENCODE_TEST_DRIVER_H_
Deb Mukherjee01cafaa2013-01-15 06:43:35 -080012
John Koleszarb9180fc2012-05-16 15:27:00 -070013#include <string>
14#include <vector>
James Zern51b7fd02013-05-03 19:08:08 -070015
16#include "./vpx_config.h"
John Koleszarb9180fc2012-05-16 15:27:00 -070017#include "third_party/googletest/src/include/gtest/gtest.h"
18#include "vpx/vpx_encoder.h"
Alex Conversea5654692014-03-11 16:40:57 -070019#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
20#include "vpx/vp8cx.h"
21#endif
John Koleszarb9180fc2012-05-16 15:27:00 -070022
23namespace libvpx_test {
24
John Koleszar706cafe2013-01-18 11:51:12 -080025class CodecFactory;
John Koleszarb9180fc2012-05-16 15:27:00 -070026class VideoSource;
27
28enum TestMode {
29 kRealTime,
30 kOnePassGood,
31 kOnePassBest,
32 kTwoPassGood,
33 kTwoPassBest
34};
35#define ALL_TEST_MODES ::testing::Values(::libvpx_test::kRealTime, \
36 ::libvpx_test::kOnePassGood, \
37 ::libvpx_test::kOnePassBest, \
38 ::libvpx_test::kTwoPassGood, \
39 ::libvpx_test::kTwoPassBest)
40
John Koleszar2fb29ff2012-05-23 12:55:27 -070041#define ONE_PASS_TEST_MODES ::testing::Values(::libvpx_test::kRealTime, \
42 ::libvpx_test::kOnePassGood, \
43 ::libvpx_test::kOnePassBest)
44
John Koleszar706cafe2013-01-18 11:51:12 -080045#define TWO_PASS_TEST_MODES ::testing::Values(::libvpx_test::kTwoPassGood, \
46 ::libvpx_test::kTwoPassBest)
47
John Koleszarb9180fc2012-05-16 15:27:00 -070048
49// Provides an object to handle the libvpx get_cx_data() iteration pattern
50class CxDataIterator {
51 public:
52 explicit CxDataIterator(vpx_codec_ctx_t *encoder)
James Zern51b7fd02013-05-03 19:08:08 -070053 : encoder_(encoder), iter_(NULL) {}
John Koleszarb9180fc2012-05-16 15:27:00 -070054
55 const vpx_codec_cx_pkt_t *Next() {
56 return vpx_codec_get_cx_data(encoder_, &iter_);
57 }
58
59 private:
60 vpx_codec_ctx_t *encoder_;
61 vpx_codec_iter_t iter_;
62};
63
John Koleszarb9180fc2012-05-16 15:27:00 -070064// Implements an in-memory store for libvpx twopass statistics
65class TwopassStatsStore {
66 public:
67 void Append(const vpx_codec_cx_pkt_t &pkt) {
68 buffer_.append(reinterpret_cast<char *>(pkt.data.twopass_stats.buf),
69 pkt.data.twopass_stats.sz);
70 }
71
72 vpx_fixed_buf_t buf() {
73 const vpx_fixed_buf_t buf = { &buffer_[0], buffer_.size() };
74 return buf;
75 }
76
Adrian Grange30f58b52012-10-02 09:36:41 -070077 void Reset() {
78 buffer_.clear();
79 }
80
John Koleszarb9180fc2012-05-16 15:27:00 -070081 protected:
82 std::string buffer_;
83};
84
85
86// Provides a simplified interface to manage one video encoding pass, given
87// a configuration and video source.
88//
89// TODO(jkoleszar): The exact services it provides and the appropriate
90// level of abstraction will be fleshed out as more tests are written.
91class Encoder {
92 public:
93 Encoder(vpx_codec_enc_cfg_t cfg, unsigned long deadline,
Adrian Grange4206c6d2012-10-02 11:03:09 -070094 const unsigned long init_flags, TwopassStatsStore *stats)
John Koleszar706cafe2013-01-18 11:51:12 -080095 : cfg_(cfg), deadline_(deadline), init_flags_(init_flags), stats_(stats) {
John Koleszarb9180fc2012-05-16 15:27:00 -070096 memset(&encoder_, 0, sizeof(encoder_));
97 }
98
James Zern51b7fd02013-05-03 19:08:08 -070099 virtual ~Encoder() {
John Koleszarb9180fc2012-05-16 15:27:00 -0700100 vpx_codec_destroy(&encoder_);
101 }
102
103 CxDataIterator GetCxData() {
104 return CxDataIterator(&encoder_);
105 }
106
Yaowu Xuc953aea2012-08-30 13:43:15 -0700107 const vpx_image_t *GetPreviewFrame() {
108 return vpx_codec_get_preview_frame(&encoder_);
109 }
John Koleszarb9180fc2012-05-16 15:27:00 -0700110 // This is a thin wrapper around vpx_codec_encode(), so refer to
111 // vpx_encoder.h for its semantics.
Adrian Grange4206c6d2012-10-02 11:03:09 -0700112 void EncodeFrame(VideoSource *video, const unsigned long frame_flags);
John Koleszarb9180fc2012-05-16 15:27:00 -0700113
114 // Convenience wrapper for EncodeFrame()
115 void EncodeFrame(VideoSource *video) {
116 EncodeFrame(video, 0);
117 }
118
John Koleszar606ac452012-07-10 15:43:44 -0700119 void Control(int ctrl_id, int arg) {
120 const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
121 ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
122 }
123
John Koleszar88f99f42013-02-06 12:44:20 -0800124 void Control(int ctrl_id, struct vpx_scaling_mode *arg) {
125 const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
126 ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
127 }
128
Marco Paniconi4864ab22014-02-06 09:23:17 -0800129 void Control(int ctrl_id, struct vpx_svc_layer_id *arg) {
130 const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
131 ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
132 }
133
Alex Conversea5654692014-03-11 16:40:57 -0700134#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
135 void Control(int ctrl_id, vpx_active_map_t *arg) {
136 const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
137 ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
138 }
139#endif
140
John Koleszarb9180fc2012-05-16 15:27:00 -0700141 void set_deadline(unsigned long deadline) {
142 deadline_ = deadline;
143 }
144
145 protected:
James Zern4a703572014-01-31 16:32:42 -0800146 virtual vpx_codec_iface_t* CodecInterface() const = 0;
John Koleszar706cafe2013-01-18 11:51:12 -0800147
John Koleszarb9180fc2012-05-16 15:27:00 -0700148 const char *EncoderError() {
149 const char *detail = vpx_codec_error_detail(&encoder_);
150 return detail ? detail : vpx_codec_error(&encoder_);
151 }
152
153 // Encode an image
Adrian Grange4206c6d2012-10-02 11:03:09 -0700154 void EncodeFrameInternal(const VideoSource &video,
155 const unsigned long frame_flags);
John Koleszarb9180fc2012-05-16 15:27:00 -0700156
157 // Flush the encoder on EOS
158 void Flush();
159
160 vpx_codec_ctx_t encoder_;
161 vpx_codec_enc_cfg_t cfg_;
162 unsigned long deadline_;
Adrian Grange4206c6d2012-10-02 11:03:09 -0700163 unsigned long init_flags_;
John Koleszarb9180fc2012-05-16 15:27:00 -0700164 TwopassStatsStore *stats_;
165};
166
John Koleszarb9180fc2012-05-16 15:27:00 -0700167// Common test functionality for all Encoder tests.
168//
169// This class is a mixin which provides the main loop common to all
170// encoder tests. It provides hooks which can be overridden by subclasses
171// to implement each test's specific behavior, while centralizing the bulk
172// of the boilerplate. Note that it doesn't inherit the gtest testing
173// classes directly, so that tests can be parameterized differently.
174class EncoderTest {
175 protected:
John Koleszar706cafe2013-01-18 11:51:12 -0800176 explicit EncoderTest(const CodecFactory *codec)
177 : codec_(codec), abort_(false), init_flags_(0), frame_flags_(0),
178 last_pts_(0) {}
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
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800188 // Main loop
John Koleszarb9180fc2012-05-16 15:27:00 -0700189 virtual void RunLoop(VideoSource *video);
190
191 // Hook to be called at the beginning of a pass.
James Zerncae810a2014-08-22 11:58:48 -0700192 virtual void BeginPassHook(unsigned int /*pass*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700193
194 // Hook to be called at the end of a pass.
195 virtual void EndPassHook() {}
196
197 // Hook to be called before encoding a frame.
James Zerncae810a2014-08-22 11:58:48 -0700198 virtual void PreEncodeFrameHook(VideoSource* /*video*/) {}
199 virtual void PreEncodeFrameHook(VideoSource* /*video*/,
200 Encoder* /*encoder*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700201
202 // Hook to be called on every compressed data packet.
James Zerncae810a2014-08-22 11:58:48 -0700203 virtual void FramePktHook(const vpx_codec_cx_pkt_t* /*pkt*/) {}
John Koleszarb9180fc2012-05-16 15:27:00 -0700204
Adrian Grangee6109db2012-10-02 11:27:29 -0700205 // Hook to be called on every PSNR packet.
James Zerncae810a2014-08-22 11:58:48 -0700206 virtual void PSNRPktHook(const vpx_codec_cx_pkt_t* /*pkt*/) {}
Adrian Grangee6109db2012-10-02 11:27:29 -0700207
John Koleszarb9180fc2012-05-16 15:27:00 -0700208 // Hook to determine whether the encode loop should continue.
James Zern1c05e9d2013-06-25 17:53:20 -0700209 virtual bool Continue() const {
210 return !(::testing::Test::HasFatalFailure() || abort_);
211 }
John Koleszarb9180fc2012-05-16 15:27:00 -0700212
John Koleszar706cafe2013-01-18 11:51:12 -0800213 const CodecFactory *codec_;
Deb Mukherjee01cafaa2013-01-15 06:43:35 -0800214 // Hook to determine whether to decode frame after encoding
215 virtual bool DoDecode() const { return 1; }
216
217 // Hook to handle encode/decode mismatch
218 virtual void MismatchHook(const vpx_image_t *img1,
219 const vpx_image_t *img2);
220
John Koleszar88f99f42013-02-06 12:44:20 -0800221 // Hook to be called on every decompressed frame.
James Zerncae810a2014-08-22 11:58:48 -0700222 virtual void DecompressedFrameHook(const vpx_image_t& /*img*/,
223 vpx_codec_pts_t /*pts*/) {}
John Koleszar88f99f42013-02-06 12:44:20 -0800224
Jim Bankoski943e4322014-07-17 06:31:50 -0700225 // Hook to be called to handle decode result. Return true to continue.
226 virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
James Zerncae810a2014-08-22 11:58:48 -0700227 const VideoSource& /*video*/,
Jim Bankoski943e4322014-07-17 06:31:50 -0700228 Decoder *decoder) {
229 EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
230 return VPX_CODEC_OK == res_dec;
231 }
232
John Koleszar522d4bf2013-03-05 12:23:34 -0800233 // Hook that can modify the encoder's output data
James Zerncae810a2014-08-22 11:58:48 -0700234 virtual const vpx_codec_cx_pkt_t *MutateEncoderOutputHook(
John Koleszar522d4bf2013-03-05 12:23:34 -0800235 const vpx_codec_cx_pkt_t *pkt) {
236 return pkt;
237 }
238
John Koleszarb9180fc2012-05-16 15:27:00 -0700239 bool abort_;
240 vpx_codec_enc_cfg_t cfg_;
241 unsigned int passes_;
242 unsigned long deadline_;
243 TwopassStatsStore stats_;
Adrian Grange4206c6d2012-10-02 11:03:09 -0700244 unsigned long init_flags_;
245 unsigned long frame_flags_;
James Zern51ebb9a2012-08-08 14:16:08 -0700246 vpx_codec_pts_t last_pts_;
John Koleszarb9180fc2012-05-16 15:27:00 -0700247};
248
249} // namespace libvpx_test
250
John Koleszarb9180fc2012-05-16 15:27:00 -0700251#endif // TEST_ENCODE_TEST_DRIVER_H_