xref: /aosp_15_r20/external/libvpx/test/encode_api_test.cc (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1 /*
2  *  Copyright (c) 2016 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 
11 #include <cassert>
12 #include <climits>
13 #include <cstdint>
14 #include <cstdio>
15 #include <cstdlib>
16 #include <cstring>
17 #include <initializer_list>
18 #include <vector>
19 
20 #include "gtest/gtest.h"
21 #include "test/acm_random.h"
22 #include "test/video_source.h"
23 #include "test/y4m_video_source.h"
24 
25 #include "./vpx_config.h"
26 #include "vpx/vp8cx.h"
27 #include "vpx/vpx_codec.h"
28 #include "vpx/vpx_encoder.h"
29 #include "vpx/vpx_image.h"
30 
31 namespace {
32 
33 vpx_codec_iface_t *kCodecIfaces[] = {
34 #if CONFIG_VP8_ENCODER
35   &vpx_codec_vp8_cx_algo,
36 #endif
37 #if CONFIG_VP9_ENCODER
38   &vpx_codec_vp9_cx_algo,
39 #endif
40 };
41 
IsVP9(vpx_codec_iface_t * iface)42 bool IsVP9(vpx_codec_iface_t *iface) {
43   static const char kVP9Name[] = "WebM Project VP9";
44   return strncmp(kVP9Name, vpx_codec_iface_name(iface), sizeof(kVP9Name) - 1) ==
45          0;
46 }
47 
Memset16(void * dest,int val,size_t length)48 void *Memset16(void *dest, int val, size_t length) {
49   uint16_t *dest16 = reinterpret_cast<uint16_t *>(dest);
50   for (size_t i = 0; i < length; i++) {
51     *dest16++ = val;
52   }
53   return dest;
54 }
55 
CreateImage(vpx_bit_depth_t bit_depth,vpx_img_fmt_t fmt,unsigned int width,unsigned int height)56 vpx_image_t *CreateImage(vpx_bit_depth_t bit_depth, vpx_img_fmt_t fmt,
57                          unsigned int width, unsigned int height) {
58   assert(fmt != VPX_IMG_FMT_NV12);
59   if (bit_depth > VPX_BITS_8) {
60     fmt = static_cast<vpx_img_fmt_t>(fmt | VPX_IMG_FMT_HIGHBITDEPTH);
61   }
62   vpx_image_t *image = vpx_img_alloc(nullptr, fmt, width, height, 1);
63   if (!image) return image;
64 
65   const int val = 1 << (bit_depth - 1);
66   const unsigned int uv_h =
67       (image->d_h + image->y_chroma_shift) >> image->y_chroma_shift;
68   const unsigned int uv_w =
69       (image->d_w + image->x_chroma_shift) >> image->x_chroma_shift;
70   if (bit_depth > VPX_BITS_8) {
71     for (unsigned int i = 0; i < image->d_h; ++i) {
72       Memset16(image->planes[0] + i * image->stride[0], val, image->d_w);
73     }
74     for (unsigned int i = 0; i < uv_h; ++i) {
75       Memset16(image->planes[1] + i * image->stride[1], val, uv_w);
76       Memset16(image->planes[2] + i * image->stride[2], val, uv_w);
77     }
78   } else {
79     for (unsigned int i = 0; i < image->d_h; ++i) {
80       memset(image->planes[0] + i * image->stride[0], val, image->d_w);
81     }
82     for (unsigned int i = 0; i < uv_h; ++i) {
83       memset(image->planes[1] + i * image->stride[1], val, uv_w);
84       memset(image->planes[2] + i * image->stride[2], val, uv_w);
85     }
86   }
87 
88   return image;
89 }
90 
InitCodec(vpx_codec_iface_t & iface,int width,int height,vpx_codec_ctx_t * enc,vpx_codec_enc_cfg_t * cfg)91 void InitCodec(vpx_codec_iface_t &iface, int width, int height,
92                vpx_codec_ctx_t *enc, vpx_codec_enc_cfg_t *cfg) {
93   cfg->g_w = width;
94   cfg->g_h = height;
95   cfg->g_lag_in_frames = 0;
96   cfg->g_pass = VPX_RC_ONE_PASS;
97   ASSERT_EQ(vpx_codec_enc_init(enc, &iface, cfg, 0), VPX_CODEC_OK);
98 
99   ASSERT_EQ(vpx_codec_control_(enc, VP8E_SET_CPUUSED, 2), VPX_CODEC_OK);
100 }
101 
102 // Encodes 1 frame of size |cfg.g_w| x |cfg.g_h| setting |enc|'s configuration
103 // to |cfg|.
EncodeWithConfig(const vpx_codec_enc_cfg_t & cfg,vpx_codec_ctx_t * enc)104 void EncodeWithConfig(const vpx_codec_enc_cfg_t &cfg, vpx_codec_ctx_t *enc) {
105   libvpx_test::DummyVideoSource video;
106   video.SetSize(cfg.g_w, cfg.g_h);
107   video.Begin();
108   EXPECT_EQ(vpx_codec_enc_config_set(enc, &cfg), VPX_CODEC_OK)
109       << vpx_codec_error_detail(enc);
110 
111   EXPECT_EQ(vpx_codec_encode(enc, video.img(), video.pts(), video.duration(),
112                              /*flags=*/0, VPX_DL_GOOD_QUALITY),
113             VPX_CODEC_OK)
114       << vpx_codec_error_detail(enc);
115 }
116 
TEST(EncodeAPI,InvalidParams)117 TEST(EncodeAPI, InvalidParams) {
118   uint8_t buf[1] = { 0 };
119   vpx_image_t img;
120   vpx_codec_ctx_t enc;
121   vpx_codec_enc_cfg_t cfg;
122 
123   EXPECT_EQ(&img, vpx_img_wrap(&img, VPX_IMG_FMT_I420, 1, 1, 1, buf));
124 
125   EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
126             vpx_codec_enc_init(nullptr, nullptr, nullptr, 0));
127   EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
128             vpx_codec_enc_init(&enc, nullptr, nullptr, 0));
129   EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
130             vpx_codec_encode(nullptr, nullptr, 0, 0, 0, 0));
131   EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
132             vpx_codec_encode(nullptr, &img, 0, 0, 0, 0));
133   EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_destroy(nullptr));
134   EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
135             vpx_codec_enc_config_default(nullptr, nullptr, 0));
136   EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
137             vpx_codec_enc_config_default(nullptr, &cfg, 0));
138   EXPECT_NE(vpx_codec_error(nullptr), nullptr);
139 
140   for (const auto *iface : kCodecIfaces) {
141     SCOPED_TRACE(vpx_codec_iface_name(iface));
142     EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
143               vpx_codec_enc_init(nullptr, iface, nullptr, 0));
144     EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
145               vpx_codec_enc_init(&enc, iface, nullptr, 0));
146     EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
147               vpx_codec_enc_config_default(iface, &cfg, 1));
148 
149     EXPECT_EQ(VPX_CODEC_OK, vpx_codec_enc_config_default(iface, &cfg, 0));
150     EXPECT_EQ(VPX_CODEC_OK, vpx_codec_enc_init(&enc, iface, &cfg, 0));
151     EXPECT_EQ(VPX_CODEC_OK, vpx_codec_encode(&enc, nullptr, 0, 0, 0, 0));
152 
153     EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&enc));
154   }
155 }
156 
TEST(EncodeAPI,HighBitDepthCapability)157 TEST(EncodeAPI, HighBitDepthCapability) {
158 // VP8 should not claim VP9 HBD as a capability.
159 #if CONFIG_VP8_ENCODER
160   const vpx_codec_caps_t vp8_caps = vpx_codec_get_caps(&vpx_codec_vp8_cx_algo);
161   EXPECT_EQ(vp8_caps & VPX_CODEC_CAP_HIGHBITDEPTH, 0);
162 #endif
163 
164 #if CONFIG_VP9_ENCODER
165   const vpx_codec_caps_t vp9_caps = vpx_codec_get_caps(&vpx_codec_vp9_cx_algo);
166 #if CONFIG_VP9_HIGHBITDEPTH
167   EXPECT_EQ(vp9_caps & VPX_CODEC_CAP_HIGHBITDEPTH, VPX_CODEC_CAP_HIGHBITDEPTH);
168 #else
169   EXPECT_EQ(vp9_caps & VPX_CODEC_CAP_HIGHBITDEPTH, 0);
170 #endif
171 #endif
172 }
173 
174 #if CONFIG_VP8_ENCODER
TEST(EncodeAPI,ImageSizeSetting)175 TEST(EncodeAPI, ImageSizeSetting) {
176   const int width = 711;
177   const int height = 360;
178   const int bps = 12;
179   vpx_image_t img;
180   vpx_codec_ctx_t enc;
181   vpx_codec_enc_cfg_t cfg;
182   uint8_t *img_buf = reinterpret_cast<uint8_t *>(
183       calloc(width * height * bps / 8, sizeof(*img_buf)));
184   vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &cfg, 0);
185 
186   cfg.g_w = width;
187   cfg.g_h = height;
188 
189   vpx_img_wrap(&img, VPX_IMG_FMT_I420, width, height, 1, img_buf);
190 
191   vpx_codec_enc_init(&enc, vpx_codec_vp8_cx(), &cfg, 0);
192 
193   EXPECT_EQ(VPX_CODEC_OK, vpx_codec_encode(&enc, &img, 0, 1, 0, 0));
194 
195   free(img_buf);
196 
197   vpx_codec_destroy(&enc);
198 }
199 
200 // Verifies the fix for a float-cast-overflow in vp8_change_config().
201 //
202 // Causes cpi->framerate to become the largest possible value (10,000,000) in
203 // VP8 by setting cfg.g_timebase to 1/10000000 and passing a duration of 1 to
204 // vpx_codec_encode().
TEST(EncodeAPI,HugeFramerateVp8)205 TEST(EncodeAPI, HugeFramerateVp8) {
206   vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
207   vpx_codec_enc_cfg_t cfg;
208   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
209   cfg.g_w = 271;
210   cfg.g_h = 1080;
211   cfg.g_timebase.num = 1;
212   // Largest value (VP8's TICKS_PER_SEC) such that frame duration is nonzero (1
213   // tick).
214   cfg.g_timebase.den = 10000000;
215   cfg.g_pass = VPX_RC_ONE_PASS;
216   cfg.g_lag_in_frames = 0;
217   cfg.rc_end_usage = VPX_CBR;
218 
219   vpx_codec_ctx_t enc;
220   // Before we encode the first frame, cpi->framerate is set to a guess (the
221   // reciprocal of cfg.g_timebase). If this guess doesn't seem reasonable
222   // (> 180), cpi->framerate is set to 30.
223   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
224 
225   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, -12), VPX_CODEC_OK);
226 
227   vpx_image_t *const image =
228       vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1);
229   ASSERT_NE(image, nullptr);
230 
231   for (unsigned int i = 0; i < image->d_h; ++i) {
232     memset(image->planes[0] + i * image->stride[0], 128, image->d_w);
233   }
234   const unsigned int uv_h = (image->d_h + 1) / 2;
235   const unsigned int uv_w = (image->d_w + 1) / 2;
236   for (unsigned int i = 0; i < uv_h; ++i) {
237     memset(image->planes[1] + i * image->stride[1], 128, uv_w);
238     memset(image->planes[2] + i * image->stride[2], 128, uv_w);
239   }
240 
241   // Encode a frame.
242   // Up to this point cpi->framerate is 30. Now pass a duration of only 1. This
243   // causes cpi->framerate to become 10,000,000.
244   ASSERT_EQ(vpx_codec_encode(&enc, image, 0, 1, 0, VPX_DL_REALTIME),
245             VPX_CODEC_OK);
246 
247   // Change to the same config. Since cpi->framerate is now huge, when it is
248   // used to calculate raw_target_rate (bit rate of uncompressed frames), the
249   // result is likely to overflow an unsigned int.
250   ASSERT_EQ(vpx_codec_enc_config_set(&enc, &cfg), VPX_CODEC_OK);
251 
252   vpx_img_free(image);
253   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
254 }
255 
256 // A test that reproduces https://crbug.com/webm/1831.
TEST(EncodeAPI,RandomPixelsVp8)257 TEST(EncodeAPI, RandomPixelsVp8) {
258   // Initialize libvpx encoder
259   vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
260   vpx_codec_enc_cfg_t cfg;
261   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
262 
263   cfg.rc_target_bitrate = 2000;
264   cfg.g_w = 1280;
265   cfg.g_h = 720;
266 
267   vpx_codec_ctx_t enc;
268   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
269 
270   // Generate random frame data and encode
271   libvpx_test::RandomVideoSource video;
272   video.SetSize(cfg.g_w, cfg.g_h);
273   video.SetImageFormat(VPX_IMG_FMT_I420);
274   video.Begin();
275   ASSERT_EQ(vpx_codec_encode(&enc, video.img(), video.pts(), video.duration(),
276                              /*flags=*/0, VPX_DL_BEST_QUALITY),
277             VPX_CODEC_OK);
278 
279   // Destroy libvpx encoder
280   vpx_codec_destroy(&enc);
281 }
282 
TEST(EncodeAPI,ChangeToL1T3AndSetBitrateVp8)283 TEST(EncodeAPI, ChangeToL1T3AndSetBitrateVp8) {
284   // Initialize libvpx encoder
285   vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
286   vpx_codec_enc_cfg_t cfg;
287   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
288 
289   cfg.g_threads = 1;
290   cfg.g_profile = 0;
291   cfg.g_w = 1;
292   cfg.g_h = 64;
293   cfg.g_bit_depth = VPX_BITS_8;
294   cfg.g_input_bit_depth = 8;
295   cfg.g_timebase.num = 1;
296   cfg.g_timebase.den = 1000000;
297   cfg.g_pass = VPX_RC_ONE_PASS;
298   cfg.g_lag_in_frames = 0;
299   cfg.rc_dropframe_thresh = 0;  // Don't drop frames
300   cfg.rc_resize_allowed = 0;
301   cfg.rc_end_usage = VPX_VBR;
302   cfg.rc_target_bitrate = 10;
303   cfg.rc_min_quantizer = 2;
304   cfg.rc_max_quantizer = 58;
305   cfg.kf_mode = VPX_KF_AUTO;
306   cfg.kf_min_dist = 0;
307   cfg.kf_max_dist = 10000;
308 
309   vpx_codec_ctx_t enc;
310   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
311 
312   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK);
313 
314   // Generate random frame data and encode
315   uint8_t img[1 * 64 * 3 / 2];
316   libvpx_test::ACMRandom rng;
317   for (size_t i = 0; i < sizeof(img); ++i) {
318     img[i] = rng.Rand8();
319   }
320   vpx_image_t img_wrapper;
321   ASSERT_EQ(
322       vpx_img_wrap(&img_wrapper, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1, img),
323       &img_wrapper);
324   vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF;
325   ASSERT_EQ(
326       vpx_codec_encode(&enc, &img_wrapper, 0, 500000, flags, VPX_DL_REALTIME),
327       VPX_CODEC_OK);
328   ASSERT_EQ(vpx_codec_encode(&enc, nullptr, -1, 0, 0, 0), VPX_CODEC_OK);
329 
330   cfg.rc_target_bitrate = 4294967;
331   // Set the scalability mode to L1T3.
332   cfg.ts_number_layers = 3;
333   cfg.ts_periodicity = 4;
334   cfg.ts_layer_id[0] = 0;
335   cfg.ts_layer_id[1] = 2;
336   cfg.ts_layer_id[2] = 1;
337   cfg.ts_layer_id[3] = 2;
338   cfg.ts_rate_decimator[0] = 4;
339   cfg.ts_rate_decimator[1] = 2;
340   cfg.ts_rate_decimator[2] = 1;
341   // Bitrate allocation L0: 50% L1: 20% L2: 30%
342   cfg.layer_target_bitrate[0] = cfg.ts_target_bitrate[0] =
343       50 * cfg.rc_target_bitrate / 100;
344   cfg.layer_target_bitrate[1] = cfg.ts_target_bitrate[1] =
345       70 * cfg.rc_target_bitrate / 100;
346   cfg.layer_target_bitrate[2] = cfg.ts_target_bitrate[2] =
347       cfg.rc_target_bitrate;
348   cfg.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0212;
349   cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
350   ASSERT_EQ(vpx_codec_enc_config_set(&enc, &cfg), VPX_CODEC_OK);
351 
352   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_TEMPORAL_LAYER_ID, 2),
353             VPX_CODEC_OK);
354 
355   constexpr vpx_enc_frame_flags_t VP8_UPDATE_NOTHING =
356       VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
357   // Layer 2: only reference last frame, no updates
358   // It only depends on layer 0
359   flags = VP8_UPDATE_NOTHING | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF;
360   ASSERT_EQ(
361       vpx_codec_encode(&enc, &img_wrapper, 0, 500000, flags, VPX_DL_REALTIME),
362       VPX_CODEC_OK);
363 
364   // Destroy libvpx encoder
365   vpx_codec_destroy(&enc);
366 }
367 
368 // Emulates the WebCodecs VideoEncoder interface.
369 class VP8Encoder {
370  public:
VP8Encoder(int speed)371   explicit VP8Encoder(int speed) : speed_(speed) {}
372   ~VP8Encoder();
373 
374   void Configure(unsigned int threads, unsigned int width, unsigned int height,
375                  vpx_rc_mode end_usage, vpx_enc_deadline_t deadline);
376   void Encode(bool key_frame);
377 
378  private:
379   const int speed_;
380   bool initialized_ = false;
381   vpx_codec_enc_cfg_t cfg_;
382   vpx_codec_ctx_t enc_;
383   int frame_index_ = 0;
384   vpx_enc_deadline_t deadline_ = 0;
385 };
386 
~VP8Encoder()387 VP8Encoder::~VP8Encoder() {
388   if (initialized_) {
389     EXPECT_EQ(vpx_codec_destroy(&enc_), VPX_CODEC_OK);
390   }
391 }
392 
Configure(unsigned int threads,unsigned int width,unsigned int height,vpx_rc_mode end_usage,vpx_enc_deadline_t deadline)393 void VP8Encoder::Configure(unsigned int threads, unsigned int width,
394                            unsigned int height, vpx_rc_mode end_usage,
395                            vpx_enc_deadline_t deadline) {
396   deadline_ = deadline;
397 
398   if (!initialized_) {
399     vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
400     ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg_, /*usage=*/0),
401               VPX_CODEC_OK);
402     cfg_.g_threads = threads;
403     cfg_.g_w = width;
404     cfg_.g_h = height;
405     cfg_.g_timebase.num = 1;
406     cfg_.g_timebase.den = 1000 * 1000;  // microseconds
407     cfg_.g_pass = VPX_RC_ONE_PASS;
408     cfg_.g_lag_in_frames = 0;
409     cfg_.rc_end_usage = end_usage;
410     cfg_.rc_min_quantizer = 2;
411     cfg_.rc_max_quantizer = 58;
412     ASSERT_EQ(vpx_codec_enc_init(&enc_, iface, &cfg_, 0), VPX_CODEC_OK);
413     ASSERT_EQ(vpx_codec_control(&enc_, VP8E_SET_CPUUSED, speed_), VPX_CODEC_OK);
414     initialized_ = true;
415     return;
416   }
417 
418   cfg_.g_threads = threads;
419   cfg_.g_w = width;
420   cfg_.g_h = height;
421   cfg_.rc_end_usage = end_usage;
422   ASSERT_EQ(vpx_codec_enc_config_set(&enc_, &cfg_), VPX_CODEC_OK)
423       << vpx_codec_error_detail(&enc_);
424 }
425 
Encode(bool key_frame)426 void VP8Encoder::Encode(bool key_frame) {
427   assert(initialized_);
428   const vpx_codec_cx_pkt_t *pkt;
429   vpx_image_t *image =
430       CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg_.g_w, cfg_.g_h);
431   ASSERT_NE(image, nullptr);
432   const vpx_enc_frame_flags_t flags = key_frame ? VPX_EFLAG_FORCE_KF : 0;
433   ASSERT_EQ(vpx_codec_encode(&enc_, image, frame_index_, 1, flags, deadline_),
434             VPX_CODEC_OK);
435   ++frame_index_;
436   vpx_codec_iter_t iter = nullptr;
437   while ((pkt = vpx_codec_get_cx_data(&enc_, &iter)) != nullptr) {
438     ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
439     if (key_frame) {
440       ASSERT_EQ(pkt->data.frame.flags & VPX_FRAME_IS_KEY, VPX_FRAME_IS_KEY);
441     }
442   }
443   vpx_img_free(image);
444 }
445 
446 // This is the reproducer testcase for crbug.com/324459561. However,
447 // just running this test is not enough to reproduce the bug. We also
448 // need to send signals to the test.
TEST(EncodeAPI,Chromium324459561)449 TEST(EncodeAPI, Chromium324459561) {
450   VP8Encoder encoder(-12);
451 
452   encoder.Configure(11, 1685, 652, VPX_CBR, VPX_DL_REALTIME);
453 
454   encoder.Encode(true);
455   encoder.Encode(true);
456   encoder.Encode(true);
457 
458   encoder.Configure(0, 1685, 1, VPX_VBR, VPX_DL_REALTIME);
459 }
460 
TEST(EncodeAPI,VP8GlobalHeaders)461 TEST(EncodeAPI, VP8GlobalHeaders) {
462   constexpr int kWidth = 320;
463   constexpr int kHeight = 240;
464 
465   vpx_codec_enc_cfg_t cfg = {};
466   struct Encoder {
467     ~Encoder() { EXPECT_EQ(vpx_codec_destroy(&ctx), VPX_CODEC_OK); }
468     vpx_codec_ctx_t ctx = {};
469   } enc;
470 
471   ASSERT_EQ(vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &cfg, 0),
472             VPX_CODEC_OK);
473   ASSERT_NO_FATAL_FAILURE(
474       InitCodec(*vpx_codec_vp8_cx(), kWidth, kHeight, &enc.ctx, &cfg));
475   EXPECT_EQ(vpx_codec_get_global_headers(&enc.ctx), nullptr);
476   EXPECT_NO_FATAL_FAILURE(EncodeWithConfig(cfg, &enc.ctx));
477   EXPECT_EQ(vpx_codec_get_global_headers(&enc.ctx), nullptr);
478 }
479 
TEST(EncodeAPI,AomediaIssue3509VbrMinSection2PercentVP8)480 TEST(EncodeAPI, AomediaIssue3509VbrMinSection2PercentVP8) {
481   // Initialize libvpx encoder.
482   vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
483   vpx_codec_ctx_t enc;
484   vpx_codec_enc_cfg_t cfg;
485 
486   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
487 
488   cfg.g_w = 1920;
489   cfg.g_h = 1080;
490   cfg.g_lag_in_frames = 0;
491   cfg.rc_target_bitrate = 1000000;
492   // Set this to more than 1 percent to cause a signed integer overflow in the
493   // multiplication cpi->av_per_frame_bandwidth *
494   // cpi->oxcf.two_pass_vbrmin_section in vp8_new_framerate() if the
495   // multiplication is done in the `int` type.
496   cfg.rc_2pass_vbr_minsection_pct = 2;
497 
498   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
499 
500   // Create input image.
501   vpx_image_t *const image =
502       CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h);
503   ASSERT_NE(image, nullptr);
504 
505   // Encode frame.
506   // `duration` can go as high as 300, but the UBSan error is gone if
507   // `duration` is 301 or higher.
508   ASSERT_EQ(
509       vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
510       VPX_CODEC_OK);
511 
512   // Free resources.
513   vpx_img_free(image);
514   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
515 }
516 
TEST(EncodeAPI,AomediaIssue3509VbrMinSection101PercentVP8)517 TEST(EncodeAPI, AomediaIssue3509VbrMinSection101PercentVP8) {
518   // Initialize libvpx encoder.
519   vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
520   vpx_codec_ctx_t enc;
521   vpx_codec_enc_cfg_t cfg;
522 
523   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
524 
525   cfg.g_w = 1920;
526   cfg.g_h = 1080;
527   cfg.g_lag_in_frames = 0;
528   cfg.rc_target_bitrate = 1000000;
529   // Set this to more than 100 percent to cause an error when vbr_min_bits is
530   // cast to `int` in vp8_new_framerate() if vbr_min_bits is not clamped to
531   // INT_MAX.
532   cfg.rc_2pass_vbr_minsection_pct = 101;
533 
534   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
535 
536   // Create input image.
537   vpx_image_t *const image =
538       CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h);
539   ASSERT_NE(image, nullptr);
540 
541   // Encode frame.
542   // `duration` can go as high as 300, but the UBSan error is gone if
543   // `duration` is 301 or higher.
544   ASSERT_EQ(
545       vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
546       VPX_CODEC_OK);
547 
548   // Free resources.
549   vpx_img_free(image);
550   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
551 }
552 
TEST(EncodeAPI,OssFuzz69100)553 TEST(EncodeAPI, OssFuzz69100) {
554   // Initialize libvpx encoder.
555   vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
556   vpx_codec_ctx_t enc;
557   vpx_codec_enc_cfg_t cfg;
558 
559   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
560 
561   cfg.g_w = 64;
562   cfg.g_h = 64;
563   cfg.g_lag_in_frames = 25;
564   cfg.g_timebase.num = 1;
565   cfg.g_timebase.den = 6240592;
566   cfg.rc_target_bitrate = 1202607620;
567   cfg.kf_max_dist = 24377;
568 
569   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
570 
571   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, 1), VPX_CODEC_OK);
572   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_ARNR_MAXFRAMES, 0), VPX_CODEC_OK);
573   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_ARNR_STRENGTH, 3), VPX_CODEC_OK);
574   ASSERT_EQ(vpx_codec_control_(&enc, VP8E_SET_ARNR_TYPE, 3),
575             VPX_CODEC_OK);  // deprecated
576   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_NOISE_SENSITIVITY, 0),
577             VPX_CODEC_OK);
578   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_TOKEN_PARTITIONS, 0),
579             VPX_CODEC_OK);
580   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_STATIC_THRESHOLD, 0),
581             VPX_CODEC_OK);
582 
583   libvpx_test::RandomVideoSource video;
584   video.set_limit(30);
585   video.SetSize(cfg.g_w, cfg.g_h);
586   video.SetImageFormat(VPX_IMG_FMT_I420);
587   video.Begin();
588   do {
589     ASSERT_EQ(vpx_codec_encode(&enc, video.img(), video.pts(), video.duration(),
590                                /*flags=*/0, VPX_DL_GOOD_QUALITY),
591               VPX_CODEC_OK);
592     video.Next();
593   } while (video.img() != nullptr);
594 
595   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
596 }
597 
EncodeOssFuzz69906(int cpu_used,vpx_enc_deadline_t deadline)598 void EncodeOssFuzz69906(int cpu_used, vpx_enc_deadline_t deadline) {
599   char str[80];
600   snprintf(str, sizeof(str), "cpu_used: %d deadline: %d", cpu_used,
601            static_cast<int>(deadline));
602   SCOPED_TRACE(str);
603 
604   // Initialize libvpx encoder.
605   vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
606   vpx_codec_ctx_t enc;
607   vpx_codec_enc_cfg_t cfg;
608 
609   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
610 
611   cfg.g_w = 4097;
612   cfg.g_h = 16;
613   cfg.rc_target_bitrate = 1237084865;
614   cfg.kf_max_dist = 4336;
615 
616   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
617 
618   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, cpu_used), VPX_CODEC_OK);
619   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_ARNR_MAXFRAMES, 0), VPX_CODEC_OK);
620   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_ARNR_STRENGTH, 3), VPX_CODEC_OK);
621   ASSERT_EQ(vpx_codec_control_(&enc, VP8E_SET_ARNR_TYPE, 3),
622             VPX_CODEC_OK);  // deprecated
623   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_NOISE_SENSITIVITY, 0),
624             VPX_CODEC_OK);
625   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_TOKEN_PARTITIONS, 0),
626             VPX_CODEC_OK);
627   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_STATIC_THRESHOLD, 0),
628             VPX_CODEC_OK);
629 
630   libvpx_test::Y4mVideoSource video("repro-oss-fuzz-69906.y4m", /*start=*/0,
631                                     /*limit=*/3);
632   video.Begin();
633   do {
634     ASSERT_EQ(vpx_codec_encode(&enc, video.img(), video.pts(), video.duration(),
635                                /*flags=*/0, deadline),
636               VPX_CODEC_OK);
637     video.Next();
638   } while (video.img() != nullptr);
639 
640   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
641 }
642 
TEST(EncodeAPI,OssFuzz69906)643 TEST(EncodeAPI, OssFuzz69906) {
644   // Note the original bug report was for speed 1, good quality. The remainder
645   // of the settings are for added coverage.
646   for (int cpu_used = 0; cpu_used <= 5; ++cpu_used) {
647     EncodeOssFuzz69906(cpu_used, VPX_DL_GOOD_QUALITY);
648   }
649 
650   for (int cpu_used = -16; cpu_used <= -5; ++cpu_used) {
651     EncodeOssFuzz69906(cpu_used, VPX_DL_REALTIME);
652   }
653 }
654 #endif  // CONFIG_VP8_ENCODER
655 
656 // Set up 2 spatial streams with 2 temporal layers per stream, and generate
657 // invalid configuration by setting the temporal layer rate allocation
658 // (ts_target_bitrate[]) to 0 for both layers. This should fail independent of
659 // CONFIG_MULTI_RES_ENCODING.
TEST(EncodeAPI,MultiResEncode)660 TEST(EncodeAPI, MultiResEncode) {
661   const int width = 1280;
662   const int height = 720;
663   const int width_down = width / 2;
664   const int height_down = height / 2;
665   const int target_bitrate = 1000;
666   const int framerate = 30;
667 
668   for (const auto *iface : kCodecIfaces) {
669     vpx_codec_ctx_t enc[2];
670     vpx_codec_enc_cfg_t cfg[2];
671     vpx_rational_t dsf[2] = { { 2, 1 }, { 2, 1 } };
672 
673     memset(enc, 0, sizeof(enc));
674 
675     for (int i = 0; i < 2; i++) {
676       vpx_codec_enc_config_default(iface, &cfg[i], 0);
677     }
678 
679     /* Highest-resolution encoder settings */
680     cfg[0].g_w = width;
681     cfg[0].g_h = height;
682     cfg[0].rc_dropframe_thresh = 0;
683     cfg[0].rc_end_usage = VPX_CBR;
684     cfg[0].rc_resize_allowed = 0;
685     cfg[0].rc_min_quantizer = 2;
686     cfg[0].rc_max_quantizer = 56;
687     cfg[0].rc_undershoot_pct = 100;
688     cfg[0].rc_overshoot_pct = 15;
689     cfg[0].rc_buf_initial_sz = 500;
690     cfg[0].rc_buf_optimal_sz = 600;
691     cfg[0].rc_buf_sz = 1000;
692     cfg[0].g_error_resilient = 1; /* Enable error resilient mode */
693     cfg[0].g_lag_in_frames = 0;
694 
695     cfg[0].kf_mode = VPX_KF_AUTO;
696     cfg[0].kf_min_dist = 3000;
697     cfg[0].kf_max_dist = 3000;
698 
699     cfg[0].rc_target_bitrate = target_bitrate; /* Set target bitrate */
700     cfg[0].g_timebase.num = 1;                 /* Set fps */
701     cfg[0].g_timebase.den = framerate;
702 
703     memcpy(&cfg[1], &cfg[0], sizeof(cfg[0]));
704     cfg[1].rc_target_bitrate = 500;
705     cfg[1].g_w = width_down;
706     cfg[1].g_h = height_down;
707 
708     for (int i = 0; i < 2; i++) {
709       cfg[i].ts_number_layers = 2;
710       cfg[i].ts_periodicity = 2;
711       cfg[i].ts_rate_decimator[0] = 2;
712       cfg[i].ts_rate_decimator[1] = 1;
713       cfg[i].ts_layer_id[0] = 0;
714       cfg[i].ts_layer_id[1] = 1;
715       // Invalid parameters.
716       cfg[i].ts_target_bitrate[0] = 0;
717       cfg[i].ts_target_bitrate[1] = 0;
718     }
719 
720     // VP9 should report incapable, VP8 invalid for all configurations.
721     EXPECT_EQ(IsVP9(iface) ? VPX_CODEC_INCAPABLE : VPX_CODEC_INVALID_PARAM,
722               vpx_codec_enc_init_multi(&enc[0], iface, &cfg[0], 2, 0, &dsf[0]));
723 
724     for (int i = 0; i < 2; i++) {
725       vpx_codec_destroy(&enc[i]);
726     }
727   }
728 }
729 
TEST(EncodeAPI,SetRoi)730 TEST(EncodeAPI, SetRoi) {
731   static struct {
732     vpx_codec_iface_t *iface;
733     int ctrl_id;
734   } kCodecs[] = {
735 #if CONFIG_VP8_ENCODER
736     { &vpx_codec_vp8_cx_algo, VP8E_SET_ROI_MAP },
737 #endif
738 #if CONFIG_VP9_ENCODER
739     { &vpx_codec_vp9_cx_algo, VP9E_SET_ROI_MAP },
740 #endif
741   };
742   constexpr int kWidth = 64;
743   constexpr int kHeight = 64;
744 
745   for (const auto &codec : kCodecs) {
746     SCOPED_TRACE(vpx_codec_iface_name(codec.iface));
747     vpx_codec_ctx_t enc;
748     vpx_codec_enc_cfg_t cfg;
749 
750     EXPECT_EQ(vpx_codec_enc_config_default(codec.iface, &cfg, 0), VPX_CODEC_OK);
751     cfg.g_w = kWidth;
752     cfg.g_h = kHeight;
753     EXPECT_EQ(vpx_codec_enc_init(&enc, codec.iface, &cfg, 0), VPX_CODEC_OK);
754 
755     vpx_roi_map_t roi = {};
756     uint8_t roi_map[kWidth * kHeight] = {};
757     if (IsVP9(codec.iface)) {
758       roi.rows = (cfg.g_w + 7) >> 3;
759       roi.cols = (cfg.g_h + 7) >> 3;
760     } else {
761       roi.rows = (cfg.g_w + 15) >> 4;
762       roi.cols = (cfg.g_h + 15) >> 4;
763     }
764     EXPECT_EQ(vpx_codec_control_(&enc, codec.ctrl_id, &roi), VPX_CODEC_OK);
765 
766     roi.roi_map = roi_map;
767     // VP8 only. This value isn't range checked.
768     roi.static_threshold[1] = 1000;
769     roi.static_threshold[2] = UINT_MAX / 2 + 1;
770     roi.static_threshold[3] = UINT_MAX;
771 
772     for (const auto delta : { -63, -1, 0, 1, 63 }) {
773       for (int i = 0; i < 8; ++i) {
774         roi.delta_q[i] = delta;
775         roi.delta_lf[i] = delta;
776         // VP9 only.
777         roi.skip[i] ^= 1;
778         roi.ref_frame[i] = (roi.ref_frame[i] + 1) % 4;
779         EXPECT_EQ(vpx_codec_control_(&enc, codec.ctrl_id, &roi), VPX_CODEC_OK);
780       }
781     }
782 
783     vpx_codec_err_t expected_error;
784     for (const auto delta : { -64, 64, INT_MIN, INT_MAX }) {
785       expected_error = VPX_CODEC_INVALID_PARAM;
786       for (int i = 0; i < 8; ++i) {
787         roi.delta_q[i] = delta;
788         // The max segment count for VP8 is 4, the remainder of the entries are
789         // ignored.
790         if (i >= 4 && !IsVP9(codec.iface)) expected_error = VPX_CODEC_OK;
791 
792         EXPECT_EQ(vpx_codec_control_(&enc, codec.ctrl_id, &roi), expected_error)
793             << "delta_q[" << i << "]: " << delta;
794         roi.delta_q[i] = 0;
795 
796         roi.delta_lf[i] = delta;
797         EXPECT_EQ(vpx_codec_control_(&enc, codec.ctrl_id, &roi), expected_error)
798             << "delta_lf[" << i << "]: " << delta;
799         roi.delta_lf[i] = 0;
800       }
801     }
802 
803     // VP8 should ignore skip[] and ref_frame[] values.
804     expected_error =
805         IsVP9(codec.iface) ? VPX_CODEC_INVALID_PARAM : VPX_CODEC_OK;
806     for (const auto skip : { -2, 2, INT_MIN, INT_MAX }) {
807       for (int i = 0; i < 8; ++i) {
808         roi.skip[i] = skip;
809         EXPECT_EQ(vpx_codec_control_(&enc, codec.ctrl_id, &roi), expected_error)
810             << "skip[" << i << "]: " << skip;
811         roi.skip[i] = 0;
812       }
813     }
814 
815     // VP9 allows negative values to be used to disable segmentation.
816     for (int ref_frame = -3; ref_frame < 0; ++ref_frame) {
817       for (int i = 0; i < 8; ++i) {
818         roi.ref_frame[i] = ref_frame;
819         EXPECT_EQ(vpx_codec_control_(&enc, codec.ctrl_id, &roi), VPX_CODEC_OK)
820             << "ref_frame[" << i << "]: " << ref_frame;
821         roi.ref_frame[i] = 0;
822       }
823     }
824 
825     for (const auto ref_frame : { 4, INT_MIN, INT_MAX }) {
826       for (int i = 0; i < 8; ++i) {
827         roi.ref_frame[i] = ref_frame;
828         EXPECT_EQ(vpx_codec_control_(&enc, codec.ctrl_id, &roi), expected_error)
829             << "ref_frame[" << i << "]: " << ref_frame;
830         roi.ref_frame[i] = 0;
831       }
832     }
833 
834     EXPECT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
835   }
836 }
837 
TEST(EncodeAPI,ConfigChangeThreadCount)838 TEST(EncodeAPI, ConfigChangeThreadCount) {
839   constexpr int kWidth = 1920;
840   constexpr int kHeight = 1080;
841 
842   for (const auto *iface : kCodecIfaces) {
843     SCOPED_TRACE(vpx_codec_iface_name(iface));
844     for (int i = 0; i < (IsVP9(iface) ? 2 : 1); ++i) {
845       vpx_codec_enc_cfg_t cfg = {};
846       struct Encoder {
847         ~Encoder() { EXPECT_EQ(vpx_codec_destroy(&ctx), VPX_CODEC_OK); }
848         vpx_codec_ctx_t ctx = {};
849       } enc;
850 
851       ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
852       EXPECT_NO_FATAL_FAILURE(
853           InitCodec(*iface, kWidth, kHeight, &enc.ctx, &cfg));
854       if (IsVP9(iface)) {
855         EXPECT_EQ(vpx_codec_control_(&enc.ctx, VP9E_SET_TILE_COLUMNS, 6),
856                   VPX_CODEC_OK);
857         EXPECT_EQ(vpx_codec_control_(&enc.ctx, VP9E_SET_ROW_MT, i),
858                   VPX_CODEC_OK);
859       }
860 
861       for (const auto threads : { 1, 4, 8, 6, 2, 1 }) {
862         cfg.g_threads = threads;
863         EXPECT_NO_FATAL_FAILURE(EncodeWithConfig(cfg, &enc.ctx))
864             << "iteration: " << i << " threads: " << threads;
865       }
866     }
867   }
868 }
869 
TEST(EncodeAPI,ConfigResizeChangeThreadCount)870 TEST(EncodeAPI, ConfigResizeChangeThreadCount) {
871   constexpr int kInitWidth = 1024;
872   constexpr int kInitHeight = 1024;
873 
874   for (const auto *iface : kCodecIfaces) {
875     SCOPED_TRACE(vpx_codec_iface_name(iface));
876     for (int i = 0; i < (IsVP9(iface) ? 2 : 1); ++i) {
877       vpx_codec_enc_cfg_t cfg = {};
878       struct Encoder {
879         ~Encoder() { EXPECT_EQ(vpx_codec_destroy(&ctx), VPX_CODEC_OK); }
880         vpx_codec_ctx_t ctx = {};
881       } enc;
882 
883       ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
884       // Start in threaded mode to ensure resolution and thread related
885       // allocations are updated correctly across changes in resolution and
886       // thread counts. See https://crbug.com/1486441.
887       cfg.g_threads = 4;
888       EXPECT_NO_FATAL_FAILURE(
889           InitCodec(*iface, kInitWidth, kInitHeight, &enc.ctx, &cfg));
890       if (IsVP9(iface)) {
891         EXPECT_EQ(vpx_codec_control_(&enc.ctx, VP9E_SET_TILE_COLUMNS, 6),
892                   VPX_CODEC_OK);
893         EXPECT_EQ(vpx_codec_control_(&enc.ctx, VP9E_SET_ROW_MT, i),
894                   VPX_CODEC_OK);
895       }
896 
897       cfg.g_w = 1000;
898       cfg.g_h = 608;
899       EXPECT_EQ(vpx_codec_enc_config_set(&enc.ctx, &cfg), VPX_CODEC_OK)
900           << vpx_codec_error_detail(&enc.ctx);
901 
902       cfg.g_w = 1000;
903       cfg.g_h = 720;
904 
905       for (const auto threads : { 1, 4, 8, 6, 2, 1 }) {
906         cfg.g_threads = threads;
907         EXPECT_NO_FATAL_FAILURE(EncodeWithConfig(cfg, &enc.ctx))
908             << "iteration: " << i << " threads: " << threads;
909       }
910     }
911   }
912 }
913 
TEST(EncodeAPI,ConfigResizeBiggerAfterInit)914 TEST(EncodeAPI, ConfigResizeBiggerAfterInit) {
915   for (const auto *iface : kCodecIfaces) {
916     SCOPED_TRACE(vpx_codec_iface_name(iface));
917     vpx_codec_enc_cfg_t cfg;
918     vpx_codec_ctx_t enc;
919 
920     ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
921     EXPECT_NO_FATAL_FAILURE(InitCodec(*iface, 1, 1, &enc, &cfg));
922 
923     cfg.g_w = 1920;
924     cfg.g_h = 1;
925     EXPECT_EQ(vpx_codec_enc_config_set(&enc, &cfg),
926               IsVP9(iface) ? VPX_CODEC_OK : VPX_CODEC_INVALID_PARAM);
927 
928     EXPECT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
929   }
930 }
931 
TEST(EncodeAPI,ConfigResizeBiggerAfterEncode)932 TEST(EncodeAPI, ConfigResizeBiggerAfterEncode) {
933   for (const auto *iface : kCodecIfaces) {
934     SCOPED_TRACE(vpx_codec_iface_name(iface));
935     vpx_codec_enc_cfg_t cfg;
936     vpx_codec_ctx_t enc;
937 
938     ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
939     EXPECT_NO_FATAL_FAILURE(InitCodec(*iface, 1, 1, &enc, &cfg));
940     EXPECT_NO_FATAL_FAILURE(EncodeWithConfig(cfg, &enc));
941 
942     cfg.g_w = 1920;
943     cfg.g_h = 1;
944     EXPECT_EQ(vpx_codec_enc_config_set(&enc, &cfg),
945               IsVP9(iface) ? VPX_CODEC_OK : VPX_CODEC_INVALID_PARAM);
946 
947     cfg.g_w = 1920;
948     cfg.g_h = 1080;
949     EXPECT_EQ(vpx_codec_enc_config_set(&enc, &cfg),
950               IsVP9(iface) ? VPX_CODEC_OK : VPX_CODEC_INVALID_PARAM);
951 
952     EXPECT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
953   }
954 }
955 
TEST(EncodeAPI,PtsSmallerThanInitialPts)956 TEST(EncodeAPI, PtsSmallerThanInitialPts) {
957   for (const auto *iface : kCodecIfaces) {
958     // Initialize libvpx encoder.
959     vpx_codec_ctx_t enc;
960     vpx_codec_enc_cfg_t cfg;
961 
962     ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
963 
964     ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
965 
966     // Create input image.
967     vpx_image_t *const image =
968         CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h);
969     ASSERT_NE(image, nullptr);
970 
971     // Encode frame.
972     ASSERT_EQ(vpx_codec_encode(&enc, image, 12, 1, 0, VPX_DL_BEST_QUALITY),
973               VPX_CODEC_OK);
974     ASSERT_EQ(vpx_codec_encode(&enc, image, 13, 1, 0, VPX_DL_BEST_QUALITY),
975               VPX_CODEC_OK);
976     // pts (10) is smaller than the initial pts (12).
977     ASSERT_EQ(vpx_codec_encode(&enc, image, 10, 1, 0, VPX_DL_BEST_QUALITY),
978               VPX_CODEC_INVALID_PARAM);
979 
980     // Free resources.
981     vpx_img_free(image);
982     ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
983   }
984 }
985 
TEST(EncodeAPI,PtsOrDurationTooBig)986 TEST(EncodeAPI, PtsOrDurationTooBig) {
987   for (const auto *iface : kCodecIfaces) {
988     // Initialize libvpx encoder.
989     vpx_codec_ctx_t enc;
990     vpx_codec_enc_cfg_t cfg;
991 
992     ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
993 
994     ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
995 
996     // Create input image.
997     vpx_image_t *const image =
998         CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h);
999     ASSERT_NE(image, nullptr);
1000 
1001     // Encode frame.
1002     ASSERT_EQ(vpx_codec_encode(&enc, image, 0, 1, 0, VPX_DL_BEST_QUALITY),
1003               VPX_CODEC_OK);
1004 #if ULONG_MAX > INT64_MAX
1005     // duration is too big.
1006     ASSERT_EQ(vpx_codec_encode(&enc, image, 0, (1ul << 63), 0, 2),
1007               VPX_CODEC_INVALID_PARAM);
1008 #endif
1009     // pts, when converted to ticks, is too big.
1010     ASSERT_EQ(vpx_codec_encode(&enc, image, INT64_MAX / 1000000 + 1, 1, 0,
1011                                VPX_DL_BEST_QUALITY),
1012               VPX_CODEC_INVALID_PARAM);
1013 #if ULONG_MAX > INT64_MAX
1014     // duration is too big.
1015     ASSERT_EQ(
1016         vpx_codec_encode(&enc, image, 0, (1ul << 63), 0, VPX_DL_BEST_QUALITY),
1017         VPX_CODEC_INVALID_PARAM);
1018     // pts + duration is too big.
1019     ASSERT_EQ(
1020         vpx_codec_encode(&enc, image, 1, INT64_MAX, 0, VPX_DL_BEST_QUALITY),
1021         VPX_CODEC_INVALID_PARAM);
1022 #endif
1023     // pts + duration, when converted to ticks, is too big.
1024 #if ULONG_MAX > INT64_MAX
1025     ASSERT_EQ(vpx_codec_encode(&enc, image, 0, 0xbd6b566b15c7, 0,
1026                                VPX_DL_BEST_QUALITY),
1027               VPX_CODEC_INVALID_PARAM);
1028 #endif
1029     ASSERT_EQ(vpx_codec_encode(&enc, image, INT64_MAX / 1000000, 1, 0,
1030                                VPX_DL_BEST_QUALITY),
1031               VPX_CODEC_INVALID_PARAM);
1032 
1033     // Free resources.
1034     vpx_img_free(image);
1035     ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
1036   }
1037 }
1038 
1039 #if CONFIG_VP9_ENCODER
1040 // Frame size needed to trigger the overflow exceeds the max buffer allowed on
1041 // 32-bit systems defined by VPX_MAX_ALLOCABLE_MEMORY
1042 #if VPX_ARCH_X86_64 || VPX_ARCH_AARCH64
TEST(EncodeAPI,ConfigLargeTargetBitrateVp9)1043 TEST(EncodeAPI, ConfigLargeTargetBitrateVp9) {
1044 #ifdef CHROMIUM
1045   GTEST_SKIP() << "Under Chromium's configuration the allocator is unable"
1046                   "to provide the space required for the frames below.";
1047 #else
1048   constexpr int kWidth = 12383;
1049   constexpr int kHeight = 8192;
1050   constexpr auto *iface = &vpx_codec_vp9_cx_algo;
1051   SCOPED_TRACE(vpx_codec_iface_name(iface));
1052   vpx_codec_enc_cfg_t cfg = {};
1053   struct Encoder {
1054     ~Encoder() { EXPECT_EQ(vpx_codec_destroy(&ctx), VPX_CODEC_OK); }
1055     vpx_codec_ctx_t ctx = {};
1056   } enc;
1057 
1058   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
1059   // The following setting will cause avg_frame_bandwidth in rate control to be
1060   // larger than INT_MAX
1061   cfg.rc_target_bitrate = INT_MAX;
1062   // Framerate 0.1 (equivalent to timebase 10) is the smallest framerate allowed
1063   // by libvpx
1064   cfg.g_timebase.den = 1;
1065   cfg.g_timebase.num = 10;
1066   EXPECT_NO_FATAL_FAILURE(InitCodec(*iface, kWidth, kHeight, &enc.ctx, &cfg))
1067       << "target bitrate: " << cfg.rc_target_bitrate << " framerate: "
1068       << static_cast<double>(cfg.g_timebase.den) / cfg.g_timebase.num;
1069 #endif  // defined(CHROMIUM)
1070 }
1071 #endif  // VPX_ARCH_X86_64 || VPX_ARCH_AARCH64
1072 
1073 // Emulates the WebCodecs VideoEncoder interface.
1074 class VP9Encoder {
1075  public:
VP9Encoder(int speed)1076   explicit VP9Encoder(int speed)
1077       : speed_(speed), row_mt_(0), bit_depth_(VPX_BITS_8),
1078         fmt_(VPX_IMG_FMT_I420) {}
1079   // The image format `fmt` must not have the VPX_IMG_FMT_HIGHBITDEPTH bit set.
1080   // If bit_depth > 8, we will set the VPX_IMG_FMT_HIGHBITDEPTH bit before
1081   // passing the image format to vpx_img_alloc().
VP9Encoder(int speed,unsigned int row_mt,vpx_bit_depth_t bit_depth,vpx_img_fmt_t fmt)1082   VP9Encoder(int speed, unsigned int row_mt, vpx_bit_depth_t bit_depth,
1083              vpx_img_fmt_t fmt)
1084       : speed_(speed), row_mt_(row_mt), bit_depth_(bit_depth), fmt_(fmt) {}
1085   ~VP9Encoder();
1086 
1087   void Configure(unsigned int threads, unsigned int width, unsigned int height,
1088                  vpx_rc_mode end_usage, vpx_enc_deadline_t deadline);
1089   void Encode(bool key_frame);
1090 
1091  private:
1092   const int speed_;
1093   const unsigned int row_mt_;
1094   const vpx_bit_depth_t bit_depth_;
1095   const vpx_img_fmt_t fmt_;
1096   bool initialized_ = false;
1097   vpx_codec_enc_cfg_t cfg_;
1098   vpx_codec_ctx_t enc_;
1099   int frame_index_ = 0;
1100   vpx_enc_deadline_t deadline_ = 0;
1101 };
1102 
~VP9Encoder()1103 VP9Encoder::~VP9Encoder() {
1104   if (initialized_) {
1105     EXPECT_EQ(vpx_codec_destroy(&enc_), VPX_CODEC_OK);
1106   }
1107 }
1108 
Configure(unsigned int threads,unsigned int width,unsigned int height,vpx_rc_mode end_usage,vpx_enc_deadline_t deadline)1109 void VP9Encoder::Configure(unsigned int threads, unsigned int width,
1110                            unsigned int height, vpx_rc_mode end_usage,
1111                            vpx_enc_deadline_t deadline) {
1112   deadline_ = deadline;
1113 
1114   if (!initialized_) {
1115     ASSERT_EQ(fmt_ & VPX_IMG_FMT_HIGHBITDEPTH, 0);
1116     const bool high_bit_depth = bit_depth_ > VPX_BITS_8;
1117     const bool is_420 = fmt_ == VPX_IMG_FMT_I420;
1118     vpx_codec_iface_t *const iface = vpx_codec_vp9_cx();
1119     ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg_, /*usage=*/0),
1120               VPX_CODEC_OK);
1121     cfg_.g_threads = threads;
1122     // In profiles 0 and 2, only 4:2:0 format is allowed. In profiles 1 and 3,
1123     // all other subsampling formats are allowed. In profiles 0 and 1, only bit
1124     // depth 8 is allowed. In profiles 2 and 3, only bit depths 10 and 12 are
1125     // allowed.
1126     cfg_.g_profile = 2 * high_bit_depth + !is_420;
1127     cfg_.g_w = width;
1128     cfg_.g_h = height;
1129     cfg_.g_bit_depth = bit_depth_;
1130     cfg_.g_input_bit_depth = bit_depth_;
1131     cfg_.g_timebase.num = 1;
1132     cfg_.g_timebase.den = 1000 * 1000;  // microseconds
1133     cfg_.g_pass = VPX_RC_ONE_PASS;
1134     cfg_.g_lag_in_frames = 0;
1135     cfg_.rc_end_usage = end_usage;
1136     cfg_.rc_min_quantizer = 2;
1137     cfg_.rc_max_quantizer = 58;
1138     ASSERT_EQ(
1139         vpx_codec_enc_init(&enc_, iface, &cfg_,
1140                            high_bit_depth ? VPX_CODEC_USE_HIGHBITDEPTH : 0),
1141         VPX_CODEC_OK);
1142     ASSERT_EQ(vpx_codec_control(&enc_, VP8E_SET_CPUUSED, speed_), VPX_CODEC_OK);
1143     ASSERT_EQ(vpx_codec_control(&enc_, VP9E_SET_ROW_MT, row_mt_), VPX_CODEC_OK);
1144     initialized_ = true;
1145     return;
1146   }
1147 
1148   cfg_.g_threads = threads;
1149   cfg_.g_w = width;
1150   cfg_.g_h = height;
1151   cfg_.rc_end_usage = end_usage;
1152   ASSERT_EQ(vpx_codec_enc_config_set(&enc_, &cfg_), VPX_CODEC_OK)
1153       << vpx_codec_error_detail(&enc_);
1154 }
1155 
Encode(bool key_frame)1156 void VP9Encoder::Encode(bool key_frame) {
1157   assert(initialized_);
1158   const vpx_codec_cx_pkt_t *pkt;
1159   vpx_image_t *image = CreateImage(bit_depth_, fmt_, cfg_.g_w, cfg_.g_h);
1160   ASSERT_NE(image, nullptr);
1161   const vpx_enc_frame_flags_t frame_flags = key_frame ? VPX_EFLAG_FORCE_KF : 0;
1162   ASSERT_EQ(
1163       vpx_codec_encode(&enc_, image, frame_index_, 1, frame_flags, deadline_),
1164       VPX_CODEC_OK);
1165   ++frame_index_;
1166   vpx_codec_iter_t iter = nullptr;
1167   while ((pkt = vpx_codec_get_cx_data(&enc_, &iter)) != nullptr) {
1168     ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
1169   }
1170   vpx_img_free(image);
1171 }
1172 
1173 // This is a test case from clusterfuzz.
TEST(EncodeAPI,PrevMiCheckNullptr)1174 TEST(EncodeAPI, PrevMiCheckNullptr) {
1175   VP9Encoder encoder(0);
1176   encoder.Configure(0, 1554, 644, VPX_VBR, VPX_DL_REALTIME);
1177 
1178   // First step: encode, without forcing KF.
1179   encoder.Encode(false);
1180   // Second step: change config
1181   encoder.Configure(0, 1131, 644, VPX_CBR, VPX_DL_GOOD_QUALITY);
1182   // Third step: encode, without forcing KF
1183   encoder.Encode(false);
1184 }
1185 
1186 // This is a test case from clusterfuzz: based on b/310477034.
1187 // Encode a few frames with multiple change config calls
1188 // with different frame sizes.
TEST(EncodeAPI,MultipleChangeConfigResize)1189 TEST(EncodeAPI, MultipleChangeConfigResize) {
1190   VP9Encoder encoder(3);
1191 
1192   // Set initial config.
1193   encoder.Configure(3, 41, 1, VPX_VBR, VPX_DL_REALTIME);
1194 
1195   // Encode first frame.
1196   encoder.Encode(true);
1197 
1198   // Change config.
1199   encoder.Configure(16, 31, 1, VPX_VBR, VPX_DL_GOOD_QUALITY);
1200 
1201   // Change config again.
1202   encoder.Configure(0, 17, 1, VPX_CBR, VPX_DL_REALTIME);
1203 
1204   // Encode 2nd frame with new config, set delta frame.
1205   encoder.Encode(false);
1206 
1207   // Encode 3rd frame with same config, set delta frame.
1208   encoder.Encode(false);
1209 }
1210 
1211 // This is a test case from clusterfuzz: based on b/310663186.
1212 // Encode set of frames while varying the deadline on the fly from
1213 // good to realtime to best and back to realtime.
TEST(EncodeAPI,DynamicDeadlineChange)1214 TEST(EncodeAPI, DynamicDeadlineChange) {
1215   // Use realtime speed: 5 to 9.
1216   VP9Encoder encoder(5);
1217 
1218   // Set initial config, in particular set deadline to GOOD mode.
1219   encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_GOOD_QUALITY);
1220 
1221   // Encode 1st frame.
1222   encoder.Encode(true);
1223 
1224   // Encode 2nd frame, delta frame.
1225   encoder.Encode(false);
1226 
1227   // Change config: change deadline to REALTIME.
1228   encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_REALTIME);
1229 
1230   // Encode 3rd frame with new config, set key frame.
1231   encoder.Encode(true);
1232 
1233   // Encode 4th frame with same config, delta frame.
1234   encoder.Encode(false);
1235 
1236   // Encode 5th frame with same config, key frame.
1237   encoder.Encode(true);
1238 
1239   // Change config: change deadline to BEST.
1240   encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_BEST_QUALITY);
1241 
1242   // Encode 6th frame with new config, set delta frame.
1243   encoder.Encode(false);
1244 
1245   // Change config: change deadline to REALTIME.
1246   encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_REALTIME);
1247 
1248   // Encode 7th frame with new config, set delta frame.
1249   encoder.Encode(false);
1250 
1251   // Encode 8th frame with new config, set key frame.
1252   encoder.Encode(true);
1253 
1254   // Encode 9th frame with new config, set delta frame.
1255   encoder.Encode(false);
1256 }
1257 
TEST(EncodeAPI,Buganizer310340241)1258 TEST(EncodeAPI, Buganizer310340241) {
1259   VP9Encoder encoder(-6);
1260 
1261   // Set initial config, in particular set deadline to GOOD mode.
1262   encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_GOOD_QUALITY);
1263 
1264   // Encode 1st frame.
1265   encoder.Encode(true);
1266 
1267   // Encode 2nd frame, delta frame.
1268   encoder.Encode(false);
1269 
1270   // Change config: change deadline to REALTIME.
1271   encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_REALTIME);
1272 
1273   // Encode 3rd frame with new config, set key frame.
1274   encoder.Encode(true);
1275 }
1276 
1277 // This is a test case from clusterfuzz: based on b/312517065.
TEST(EncodeAPI,Buganizer312517065)1278 TEST(EncodeAPI, Buganizer312517065) {
1279   VP9Encoder encoder(4);
1280   encoder.Configure(0, 1060, 437, VPX_CBR, VPX_DL_REALTIME);
1281   encoder.Encode(true);
1282   encoder.Configure(10, 33, 437, VPX_VBR, VPX_DL_GOOD_QUALITY);
1283   encoder.Encode(false);
1284   encoder.Configure(6, 327, 269, VPX_VBR, VPX_DL_GOOD_QUALITY);
1285   encoder.Configure(15, 1060, 437, VPX_CBR, VPX_DL_REALTIME);
1286   encoder.Encode(false);
1287 }
1288 
1289 // This is a test case from clusterfuzz: based on b/311489136.
1290 // Encode a few frames with multiple change config calls
1291 // with different frame sizes.
TEST(EncodeAPI,Buganizer311489136)1292 TEST(EncodeAPI, Buganizer311489136) {
1293   VP9Encoder encoder(1);
1294 
1295   // Set initial config.
1296   encoder.Configure(12, 1678, 620, VPX_VBR, VPX_DL_GOOD_QUALITY);
1297 
1298   // Encode first frame.
1299   encoder.Encode(true);
1300 
1301   // Change config.
1302   encoder.Configure(3, 1678, 202, VPX_CBR, VPX_DL_GOOD_QUALITY);
1303 
1304   // Encode 2nd frame with new config, set delta frame.
1305   encoder.Encode(false);
1306 
1307   // Change config again.
1308   encoder.Configure(8, 1037, 476, VPX_CBR, VPX_DL_REALTIME);
1309 
1310   // Encode 3rd frame with new config, set delta frame.
1311   encoder.Encode(false);
1312 
1313   // Change config again.
1314   encoder.Configure(0, 580, 620, VPX_CBR, VPX_DL_GOOD_QUALITY);
1315 
1316   // Encode 4th frame with same config, set delta frame.
1317   encoder.Encode(false);
1318 }
1319 
1320 // This is a test case from clusterfuzz: based on b/312656387.
1321 // Encode a few frames with multiple change config calls
1322 // with different frame sizes.
TEST(EncodeAPI,Buganizer312656387)1323 TEST(EncodeAPI, Buganizer312656387) {
1324   VP9Encoder encoder(1);
1325 
1326   // Set initial config.
1327   encoder.Configure(16, 1, 1024, VPX_CBR, VPX_DL_REALTIME);
1328 
1329   // Change config.
1330   encoder.Configure(15, 1, 1024, VPX_VBR, VPX_DL_REALTIME);
1331 
1332   // Encode first frame.
1333   encoder.Encode(true);
1334 
1335   // Change config again.
1336   encoder.Configure(14, 1, 595, VPX_VBR, VPX_DL_GOOD_QUALITY);
1337 
1338   // Encode 2nd frame with new config.
1339   encoder.Encode(true);
1340 
1341   // Change config again.
1342   encoder.Configure(2, 1, 1024, VPX_VBR, VPX_DL_GOOD_QUALITY);
1343 
1344   // Encode 3rd frame with new config, set delta frame.
1345   encoder.Encode(false);
1346 }
1347 
1348 // This is a test case from clusterfuzz: based on b/310329177.
1349 // Encode a few frames with multiple change config calls
1350 // with different frame sizes.
TEST(EncodeAPI,Buganizer310329177)1351 TEST(EncodeAPI, Buganizer310329177) {
1352   VP9Encoder encoder(6);
1353 
1354   // Set initial config.
1355   encoder.Configure(10, 41, 1, VPX_VBR, VPX_DL_REALTIME);
1356 
1357   // Encode first frame.
1358   encoder.Encode(true);
1359 
1360   // Change config.
1361   encoder.Configure(16, 1, 1, VPX_VBR, VPX_DL_REALTIME);
1362 
1363   // Encode 2nd frame with new config, set delta frame.
1364   encoder.Encode(false);
1365 }
1366 
1367 // This is a test case from clusterfuzz: based on b/311394513.
1368 // Encode a few frames with multiple change config calls
1369 // with different frame sizes.
TEST(EncodeAPI,Buganizer311394513)1370 TEST(EncodeAPI, Buganizer311394513) {
1371   VP9Encoder encoder(-7);
1372 
1373   // Set initial config.
1374   encoder.Configure(0, 5, 9, VPX_VBR, VPX_DL_REALTIME);
1375 
1376   // Encode first frame.
1377   encoder.Encode(false);
1378 
1379   // Change config.
1380   encoder.Configure(5, 2, 1, VPX_VBR, VPX_DL_REALTIME);
1381 
1382   // Encode 2nd frame with new config.
1383   encoder.Encode(true);
1384 }
1385 
TEST(EncodeAPI,Buganizer311985118)1386 TEST(EncodeAPI, Buganizer311985118) {
1387   VP9Encoder encoder(0);
1388 
1389   // Set initial config, in particular set deadline to GOOD mode.
1390   encoder.Configure(12, 1678, 620, VPX_VBR, VPX_DL_GOOD_QUALITY);
1391 
1392   // Encode 1st frame.
1393   encoder.Encode(false);
1394 
1395   // Change config: change threads and width.
1396   encoder.Configure(0, 1574, 620, VPX_VBR, VPX_DL_GOOD_QUALITY);
1397 
1398   // Change config: change threads, width and height.
1399   encoder.Configure(16, 837, 432, VPX_VBR, VPX_DL_GOOD_QUALITY);
1400 
1401   // Encode 2nd frame.
1402   encoder.Encode(false);
1403 }
1404 
1405 // This is a test case from clusterfuzz: based on b/314857577.
1406 // Encode a few frames with multiple change config calls
1407 // with different frame sizes.
TEST(EncodeAPI,Buganizer314857577)1408 TEST(EncodeAPI, Buganizer314857577) {
1409   VP9Encoder encoder(4);
1410 
1411   // Set initial config.
1412   encoder.Configure(12, 1060, 437, VPX_VBR, VPX_DL_REALTIME);
1413 
1414   // Encode first frame.
1415   encoder.Encode(false);
1416 
1417   // Change config.
1418   encoder.Configure(16, 1060, 1, VPX_CBR, VPX_DL_REALTIME);
1419 
1420   // Encode 2nd frame with new config.
1421   encoder.Encode(false);
1422 
1423   // Encode 3rd frame with new config.
1424   encoder.Encode(true);
1425 
1426   // Change config.
1427   encoder.Configure(15, 33, 437, VPX_VBR, VPX_DL_GOOD_QUALITY);
1428 
1429   // Encode 4th frame with new config.
1430   encoder.Encode(true);
1431 
1432   // Encode 5th frame with new config.
1433   encoder.Encode(false);
1434 
1435   // Change config.
1436   encoder.Configure(5, 327, 269, VPX_VBR, VPX_DL_REALTIME);
1437 
1438   // Change config.
1439   encoder.Configure(15, 1060, 437, VPX_CBR, VPX_DL_REALTIME);
1440 
1441   // Encode 6th frame with new config.
1442   encoder.Encode(false);
1443 
1444   // Encode 7th frame with new config.
1445   encoder.Encode(false);
1446 
1447   // Change config.
1448   encoder.Configure(4, 1060, 437, VPX_VBR, VPX_DL_REALTIME);
1449 
1450   // Encode 8th frame with new config.
1451   encoder.Encode(false);
1452 }
1453 
TEST(EncodeAPI,Buganizer312875957PredBufferStride)1454 TEST(EncodeAPI, Buganizer312875957PredBufferStride) {
1455   VP9Encoder encoder(-1);
1456 
1457   encoder.Configure(12, 1678, 620, VPX_VBR, VPX_DL_REALTIME);
1458   encoder.Encode(true);
1459   encoder.Encode(false);
1460   encoder.Configure(0, 456, 486, VPX_VBR, VPX_DL_REALTIME);
1461   encoder.Encode(true);
1462   encoder.Configure(0, 1678, 620, VPX_CBR, 1000000);
1463   encoder.Encode(false);
1464   encoder.Encode(false);
1465 }
1466 
1467 // This is a test case from clusterfuzz: based on b/311294795
1468 // Encode a few frames with multiple change config calls
1469 // with different frame sizes.
TEST(EncodeAPI,Buganizer311294795)1470 TEST(EncodeAPI, Buganizer311294795) {
1471   VP9Encoder encoder(1);
1472 
1473   // Set initial config.
1474   encoder.Configure(12, 1678, 620, VPX_VBR, VPX_DL_REALTIME);
1475 
1476   // Encode first frame.
1477   encoder.Encode(false);
1478 
1479   // Change config.
1480   encoder.Configure(16, 632, 620, VPX_VBR, VPX_DL_GOOD_QUALITY);
1481 
1482   // Encode 2nd frame with new config
1483   encoder.Encode(true);
1484 
1485   // Change config.
1486   encoder.Configure(16, 1678, 342, VPX_VBR, VPX_DL_GOOD_QUALITY);
1487 
1488   // Encode 3rd frame with new config.
1489   encoder.Encode(false);
1490 
1491   // Change config.
1492   encoder.Configure(0, 1574, 618, VPX_VBR, VPX_DL_REALTIME);
1493   // Encode more frames with new config.
1494   encoder.Encode(false);
1495   encoder.Encode(false);
1496 }
1497 
TEST(EncodeAPI,Buganizer317105128)1498 TEST(EncodeAPI, Buganizer317105128) {
1499   VP9Encoder encoder(-9);
1500   encoder.Configure(0, 1, 1, VPX_CBR, VPX_DL_GOOD_QUALITY);
1501   encoder.Configure(16, 1920, 1, VPX_CBR, VPX_DL_REALTIME);
1502 }
1503 
TEST(EncodeAPI,Buganizer319964497)1504 TEST(EncodeAPI, Buganizer319964497) {
1505   VP9Encoder encoder(7);
1506   encoder.Configure(/*threads=*/1, /*width=*/320, /*height=*/240, VPX_VBR,
1507                     VPX_DL_REALTIME);
1508   encoder.Encode(/*key_frame=*/true);
1509   encoder.Encode(/*key_frame=*/true);
1510   encoder.Encode(/*key_frame=*/false);
1511   encoder.Configure(/*threads=*/1, /*width=*/1, /*height=*/1, VPX_VBR,
1512                     VPX_DL_REALTIME);
1513   encoder.Encode(/*key_frame=*/false);
1514   encoder.Configure(/*threads=*/1, /*width=*/2, /*height=*/2, VPX_CBR,
1515                     VPX_DL_REALTIME);
1516   encoder.Encode(/*key_frame=*/false);
1517 }
1518 
TEST(EncodeAPI,Buganizer329088759RowMT0)1519 TEST(EncodeAPI, Buganizer329088759RowMT0) {
1520   VP9Encoder encoder(8, 0, VPX_BITS_8, VPX_IMG_FMT_I444);
1521   encoder.Configure(/*threads=*/8, /*width=*/1686, /*height=*/398, VPX_VBR,
1522                     VPX_DL_REALTIME);
1523   encoder.Encode(/*key_frame=*/true);
1524   encoder.Encode(/*key_frame=*/false);
1525   encoder.Configure(/*threads=*/0, /*width=*/1686, /*height=*/1, VPX_VBR,
1526                     VPX_DL_REALTIME);
1527   encoder.Encode(/*key_frame=*/true);
1528   encoder.Configure(/*threads=*/0, /*width=*/1482, /*height=*/113, VPX_CBR,
1529                     VPX_DL_REALTIME);
1530   encoder.Encode(/*key_frame=*/true);
1531   encoder.Configure(/*threads=*/0, /*width=*/881, /*height=*/59, VPX_CBR,
1532                     VPX_DL_REALTIME);
1533   encoder.Configure(/*threads=*/13, /*width=*/1271, /*height=*/385, VPX_CBR,
1534                     VPX_DL_REALTIME);
1535   encoder.Encode(/*key_frame=*/false);
1536   encoder.Configure(/*threads=*/2, /*width=*/1, /*height=*/62, VPX_VBR,
1537                     VPX_DL_REALTIME);
1538 }
1539 
TEST(EncodeAPI,Buganizer329088759RowMT1)1540 TEST(EncodeAPI, Buganizer329088759RowMT1) {
1541   VP9Encoder encoder(8, 1, VPX_BITS_8, VPX_IMG_FMT_I444);
1542   encoder.Configure(/*threads=*/8, /*width=*/1686, /*height=*/398, VPX_VBR,
1543                     VPX_DL_REALTIME);
1544   encoder.Encode(/*key_frame=*/true);
1545   encoder.Encode(/*key_frame=*/false);
1546   // Needs to set threads to non-zero to repro the issue.
1547   encoder.Configure(/*threads=*/2, /*width=*/1686, /*height=*/1, VPX_VBR,
1548                     VPX_DL_REALTIME);
1549   encoder.Encode(/*key_frame=*/true);
1550   encoder.Configure(/*threads=*/2, /*width=*/1482, /*height=*/113, VPX_CBR,
1551                     VPX_DL_REALTIME);
1552   encoder.Encode(/*key_frame=*/true);
1553   encoder.Configure(/*threads=*/2, /*width=*/881, /*height=*/59, VPX_CBR,
1554                     VPX_DL_REALTIME);
1555   encoder.Configure(/*threads=*/13, /*width=*/1271, /*height=*/385, VPX_CBR,
1556                     VPX_DL_REALTIME);
1557   encoder.Encode(/*key_frame=*/false);
1558   encoder.Configure(/*threads=*/2, /*width=*/1, /*height=*/62, VPX_VBR,
1559                     VPX_DL_REALTIME);
1560 }
1561 
TEST(EncodeAPI,Buganizer331086799)1562 TEST(EncodeAPI, Buganizer331086799) {
1563   VP9Encoder encoder(6, 1, VPX_BITS_8, VPX_IMG_FMT_I420);
1564   encoder.Configure(0, 1385, 1, VPX_CBR, VPX_DL_REALTIME);
1565   encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_REALTIME);
1566   encoder.Encode(false);
1567   encoder.Configure(16, 1385, 1, VPX_VBR, VPX_DL_GOOD_QUALITY);
1568   encoder.Encode(false);
1569   encoder.Encode(false);
1570   encoder.Configure(0, 1, 1, VPX_CBR, VPX_DL_REALTIME);
1571   encoder.Encode(true);
1572 }
1573 
TEST(EncodeAPI,Buganizer331108729)1574 TEST(EncodeAPI, Buganizer331108729) {
1575   VP9Encoder encoder(1, 1, VPX_BITS_8, VPX_IMG_FMT_I422);
1576   encoder.Configure(0, 1919, 260, VPX_VBR, VPX_DL_REALTIME);
1577   encoder.Configure(9, 440, 1, VPX_CBR, VPX_DL_GOOD_QUALITY);
1578   encoder.Encode(true);
1579   encoder.Configure(8, 1919, 260, VPX_VBR, VPX_DL_REALTIME);
1580   encoder.Encode(false);
1581 }
1582 
TEST(EncodeAPI,Buganizer331108922BitDepth8)1583 TEST(EncodeAPI, Buganizer331108922BitDepth8) {
1584   VP9Encoder encoder(9, 1, VPX_BITS_8, VPX_IMG_FMT_I420);
1585   encoder.Configure(/*threads=*/1, /*width=*/1, /*height=*/1080, VPX_VBR,
1586                     VPX_DL_REALTIME);
1587   encoder.Encode(/*key_frame=*/false);
1588   encoder.Configure(/*threads=*/0, /*width=*/1, /*height=*/1080, VPX_CBR,
1589                     VPX_DL_GOOD_QUALITY);
1590   encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/394, VPX_CBR,
1591                     VPX_DL_REALTIME);
1592   encoder.Encode(/*key_frame=*/false);
1593   encoder.Encode(/*key_frame=*/true);
1594   encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/798, VPX_CBR,
1595                     VPX_DL_REALTIME);
1596   encoder.Encode(/*key_frame=*/false);
1597 }
1598 
1599 #if CONFIG_VP9_HIGHBITDEPTH
TEST(EncodeAPI,Buganizer329674887RowMT0BitDepth12)1600 TEST(EncodeAPI, Buganizer329674887RowMT0BitDepth12) {
1601   VP9Encoder encoder(8, 0, VPX_BITS_12, VPX_IMG_FMT_I444);
1602   encoder.Configure(/*threads=*/2, /*width=*/1030, /*height=*/583, VPX_VBR,
1603                     VPX_DL_REALTIME);
1604   encoder.Encode(/*key_frame=*/true);
1605   encoder.Configure(/*threads=*/0, /*width=*/1030, /*height=*/1, VPX_CBR,
1606                     VPX_DL_REALTIME);
1607   encoder.Encode(/*key_frame=*/true);
1608   encoder.Configure(/*threads=*/0, /*width=*/548, /*height=*/322, VPX_VBR,
1609                     VPX_DL_REALTIME);
1610   encoder.Encode(/*key_frame=*/false);
1611   encoder.Configure(/*threads=*/16, /*width=*/24, /*height=*/583, VPX_CBR,
1612                     VPX_DL_GOOD_QUALITY);
1613 }
1614 
TEST(EncodeAPI,Buganizer329179808RowMT0BitDepth10)1615 TEST(EncodeAPI, Buganizer329179808RowMT0BitDepth10) {
1616   VP9Encoder encoder(4, 0, VPX_BITS_10, VPX_IMG_FMT_I444);
1617   encoder.Configure(/*threads=*/16, /*width=*/1488, /*height=*/5, VPX_VBR,
1618                     VPX_DL_REALTIME);
1619   encoder.Encode(/*key_frame=*/true);
1620   encoder.Configure(/*threads=*/16, /*width=*/839, /*height=*/1, VPX_CBR,
1621                     VPX_DL_REALTIME);
1622   encoder.Encode(/*key_frame=*/false);
1623   encoder.Configure(/*threads=*/11, /*width=*/657, /*height=*/5, VPX_CBR,
1624                     VPX_DL_REALTIME);
1625   encoder.Encode(/*key_frame=*/false);
1626 }
1627 
TEST(EncodeAPI,Buganizer329179808RowMT1BitDepth10)1628 TEST(EncodeAPI, Buganizer329179808RowMT1BitDepth10) {
1629   VP9Encoder encoder(4, 1, VPX_BITS_10, VPX_IMG_FMT_I444);
1630   encoder.Configure(/*threads=*/16, /*width=*/1488, /*height=*/5, VPX_VBR,
1631                     VPX_DL_REALTIME);
1632   encoder.Encode(/*key_frame=*/true);
1633   encoder.Configure(/*threads=*/16, /*width=*/839, /*height=*/1, VPX_CBR,
1634                     VPX_DL_REALTIME);
1635   encoder.Encode(/*key_frame=*/false);
1636   encoder.Configure(/*threads=*/11, /*width=*/657, /*height=*/5, VPX_CBR,
1637                     VPX_DL_REALTIME);
1638   encoder.Encode(/*key_frame=*/false);
1639 }
1640 
TEST(EncodeAPI,Buganizer331108922BitDepth12)1641 TEST(EncodeAPI, Buganizer331108922BitDepth12) {
1642   VP9Encoder encoder(9, 1, VPX_BITS_12, VPX_IMG_FMT_I444);
1643   encoder.Configure(/*threads=*/1, /*width=*/1, /*height=*/1080, VPX_VBR,
1644                     VPX_DL_REALTIME);
1645   encoder.Encode(/*key_frame=*/false);
1646   encoder.Configure(/*threads=*/0, /*width=*/1, /*height=*/1080, VPX_CBR,
1647                     VPX_DL_GOOD_QUALITY);
1648   encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/394, VPX_CBR,
1649                     VPX_DL_REALTIME);
1650   encoder.Encode(/*key_frame=*/false);
1651   encoder.Encode(/*key_frame=*/true);
1652   encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/798, VPX_CBR,
1653                     VPX_DL_REALTIME);
1654   encoder.Encode(/*key_frame=*/false);
1655 }
1656 #endif  // CONFIG_VP9_HIGHBITDEPTH
1657 
TEST(EncodeAPI,VP9GlobalHeaders)1658 TEST(EncodeAPI, VP9GlobalHeaders) {
1659   constexpr int kWidth = 320;
1660   constexpr int kHeight = 240;
1661 
1662   libvpx_test::DummyVideoSource video;
1663   video.SetSize(kWidth, kHeight);
1664 
1665 #if CONFIG_VP9_HIGHBITDEPTH
1666   const int profiles[] = { 0, 1, 2, 3 };
1667 #else
1668   const int profiles[] = { 0, 1 };
1669 #endif
1670   char str[80];
1671   for (const int profile : profiles) {
1672     std::vector<vpx_bit_depth_t> bitdepths;
1673     std::vector<vpx_img_fmt_t> formats;
1674     switch (profile) {
1675       case 0:
1676         bitdepths = { VPX_BITS_8 };
1677         formats = { VPX_IMG_FMT_I420 };
1678         break;
1679       case 1:
1680         bitdepths = { VPX_BITS_8 };
1681         formats = { VPX_IMG_FMT_I422, VPX_IMG_FMT_I444 };
1682         break;
1683 #if CONFIG_VP9_HIGHBITDEPTH
1684       case 2:
1685         bitdepths = { VPX_BITS_10, VPX_BITS_12 };
1686         formats = { VPX_IMG_FMT_I42016 };
1687         break;
1688       case 3:
1689         bitdepths = { VPX_BITS_10, VPX_BITS_12 };
1690         formats = { VPX_IMG_FMT_I42216, VPX_IMG_FMT_I44416 };
1691         break;
1692 #endif
1693     }
1694 
1695     for (const auto format : formats) {
1696       for (const auto bitdepth : bitdepths) {
1697         snprintf(str, sizeof(str), "profile: %d bitdepth: %d format: %d",
1698                  profile, bitdepth, format);
1699         SCOPED_TRACE(str);
1700 
1701         vpx_codec_enc_cfg_t cfg = {};
1702         struct Encoder {
1703           ~Encoder() { EXPECT_EQ(vpx_codec_destroy(&ctx), VPX_CODEC_OK); }
1704           vpx_codec_ctx_t ctx = {};
1705         } enc;
1706         vpx_codec_ctx_t *const ctx = &enc.ctx;
1707 
1708         ASSERT_EQ(vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &cfg, 0),
1709                   VPX_CODEC_OK);
1710         cfg.g_w = kWidth;
1711         cfg.g_h = kHeight;
1712         cfg.g_lag_in_frames = 0;
1713         cfg.g_pass = VPX_RC_ONE_PASS;
1714         cfg.g_profile = profile;
1715         cfg.g_bit_depth = bitdepth;
1716         ASSERT_EQ(
1717             vpx_codec_enc_init(ctx, vpx_codec_vp9_cx(), &cfg,
1718                                bitdepth == 8 ? 0 : VPX_CODEC_USE_HIGHBITDEPTH),
1719             VPX_CODEC_OK);
1720         ASSERT_EQ(vpx_codec_control_(ctx, VP8E_SET_CPUUSED, 2), VPX_CODEC_OK);
1721         ASSERT_EQ(vpx_codec_control_(ctx, VP9E_SET_TARGET_LEVEL, 62),
1722                   VPX_CODEC_OK);
1723 
1724         vpx_fixed_buf_t *global_headers = vpx_codec_get_global_headers(ctx);
1725         EXPECT_NE(global_headers, nullptr);
1726         EXPECT_EQ(global_headers->sz, size_t{ 9 });
1727 
1728         video.SetImageFormat(format);
1729         video.Begin();
1730         EXPECT_EQ(
1731             vpx_codec_encode(ctx, video.img(), video.pts(), video.duration(),
1732                              /*flags=*/0, VPX_DL_GOOD_QUALITY),
1733             VPX_CODEC_OK)
1734             << vpx_codec_error_detail(ctx);
1735 
1736         global_headers = vpx_codec_get_global_headers(ctx);
1737         EXPECT_NE(global_headers, nullptr);
1738         EXPECT_EQ(global_headers->sz, size_t{ 12 });
1739         uint8_t chroma_subsampling;
1740         if ((format & VPX_IMG_FMT_I420) == VPX_IMG_FMT_I420) {
1741           chroma_subsampling = 1;
1742         } else if ((format & VPX_IMG_FMT_I422) == VPX_IMG_FMT_I422) {
1743           chroma_subsampling = 2;
1744         } else {  // VPX_IMG_FMT_I444
1745           chroma_subsampling = 3;
1746         }
1747         const uint8_t expected_headers[] = { 1,
1748                                              1,
1749                                              static_cast<uint8_t>(profile),
1750                                              2,
1751                                              1,
1752                                              /*level,*/ 3,
1753                                              1,
1754                                              static_cast<uint8_t>(bitdepth),
1755                                              4,
1756                                              1,
1757                                              chroma_subsampling };
1758         const uint8_t *actual_headers =
1759             reinterpret_cast<const uint8_t *>(global_headers->buf);
1760         for (int i = 0; i < 5; ++i) {
1761           EXPECT_EQ(expected_headers[i], actual_headers[i]) << "index: " << i;
1762         }
1763         EXPECT_NE(actual_headers[6], 0);  // level
1764         for (int i = 5; i < 11; ++i) {
1765           EXPECT_EQ(expected_headers[i], actual_headers[i + 1])
1766               << "index: " << i + 1;
1767         }
1768       }
1769     }
1770   }
1771 }
1772 
TEST(EncodeAPI,AomediaIssue3509VbrMinSection2PercentVP9)1773 TEST(EncodeAPI, AomediaIssue3509VbrMinSection2PercentVP9) {
1774   // Initialize libvpx encoder.
1775   vpx_codec_iface_t *const iface = vpx_codec_vp9_cx();
1776   vpx_codec_ctx_t enc;
1777   vpx_codec_enc_cfg_t cfg;
1778 
1779   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
1780 
1781   cfg.g_w = 1920;
1782   cfg.g_h = 1080;
1783   cfg.g_lag_in_frames = 0;
1784   cfg.rc_target_bitrate = 1000000;
1785   // Set this to more than 1 percent to cause a signed integer overflow in the
1786   // multiplication rc->avg_frame_bandwidth * oxcf->rc_cfg.vbrmin_section in
1787   // vp9_rc_update_framerate() if the multiplication is done in the `int` type.
1788   cfg.rc_2pass_vbr_minsection_pct = 2;
1789 
1790   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
1791 
1792   // Create input image.
1793   vpx_image_t *const image =
1794       CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h);
1795   ASSERT_NE(image, nullptr);
1796 
1797   // Encode frame.
1798   // `duration` can go as high as 300, but the UBSan error is gone if
1799   // `duration` is 301 or higher.
1800   ASSERT_EQ(
1801       vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
1802       VPX_CODEC_OK);
1803 
1804   // Free resources.
1805   vpx_img_free(image);
1806   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
1807 }
1808 
TEST(EncodeAPI,AomediaIssue3509VbrMinSection101PercentVP9)1809 TEST(EncodeAPI, AomediaIssue3509VbrMinSection101PercentVP9) {
1810   // Initialize libvpx encoder.
1811   vpx_codec_iface_t *const iface = vpx_codec_vp9_cx();
1812   vpx_codec_ctx_t enc;
1813   vpx_codec_enc_cfg_t cfg;
1814 
1815   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
1816 
1817   cfg.g_w = 1920;
1818   cfg.g_h = 1080;
1819   cfg.g_lag_in_frames = 0;
1820   cfg.rc_target_bitrate = 1000000;
1821   // Set this to more than 100 percent to cause an error when vbr_min_bits is
1822   // cast to `int` in vp9_rc_update_framerate() if vbr_min_bits is not clamped
1823   // to INT_MAX.
1824   cfg.rc_2pass_vbr_minsection_pct = 101;
1825 
1826   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
1827 
1828   // Create input image.
1829   vpx_image_t *const image =
1830       CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h);
1831   ASSERT_NE(image, nullptr);
1832 
1833   // Encode frame.
1834   // `duration` can go as high as 300, but the UBSan error is gone if
1835   // `duration` is 301 or higher.
1836   ASSERT_EQ(
1837       vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
1838       VPX_CODEC_OK);
1839 
1840   // Free resources.
1841   vpx_img_free(image);
1842   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
1843 }
1844 
TEST(EncodeAPI,Chromium352414650)1845 TEST(EncodeAPI, Chromium352414650) {
1846   // Initialize libvpx encoder.
1847   vpx_codec_iface_t *const iface = vpx_codec_vp9_cx();
1848   vpx_codec_ctx_t enc;
1849   vpx_codec_enc_cfg_t cfg;
1850 
1851   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
1852 
1853   cfg.g_w = 1024;
1854   cfg.g_h = 1024;
1855   cfg.g_profile = 0;
1856   cfg.g_pass = VPX_RC_ONE_PASS;
1857   cfg.g_lag_in_frames = 0;
1858   cfg.rc_max_quantizer = 58;
1859   cfg.rc_min_quantizer = 2;
1860   cfg.g_threads = 4;
1861   cfg.rc_resize_allowed = 0;
1862   cfg.rc_dropframe_thresh = 0;
1863   cfg.g_timebase.num = 1;
1864   cfg.g_timebase.den = 1000000;
1865   cfg.kf_min_dist = 0;
1866   cfg.kf_max_dist = 10000;
1867   cfg.rc_end_usage = VPX_CBR;
1868   cfg.rc_target_bitrate = 754974;
1869   cfg.ts_number_layers = 3;
1870   cfg.ts_periodicity = 4;
1871   cfg.ts_layer_id[0] = 0;
1872   cfg.ts_layer_id[1] = 2;
1873   cfg.ts_layer_id[2] = 1;
1874   cfg.ts_layer_id[3] = 2;
1875   cfg.ts_rate_decimator[0] = 4;
1876   cfg.ts_rate_decimator[1] = 2;
1877   cfg.ts_rate_decimator[2] = 1;
1878   cfg.layer_target_bitrate[0] = 2147483;
1879   cfg.layer_target_bitrate[1] = 3006476;
1880   cfg.layer_target_bitrate[2] = 4294967;
1881   cfg.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0212;
1882   cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
1883 
1884   ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
1885 
1886   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, 7), VPX_CODEC_OK);
1887   ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_TILE_COLUMNS, 2), VPX_CODEC_OK);
1888   ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_ROW_MT, 1), VPX_CODEC_OK);
1889 
1890   vpx_svc_extra_cfg_t svc_cfg = {};
1891   svc_cfg.max_quantizers[0] = svc_cfg.max_quantizers[1] =
1892       svc_cfg.max_quantizers[2] = 58;
1893   svc_cfg.min_quantizers[0] = svc_cfg.min_quantizers[1] =
1894       svc_cfg.min_quantizers[2] = 2;
1895   svc_cfg.scaling_factor_num[0] = svc_cfg.scaling_factor_num[1] =
1896       svc_cfg.scaling_factor_num[2] = 1;
1897   svc_cfg.scaling_factor_den[0] = svc_cfg.scaling_factor_den[1] =
1898       svc_cfg.scaling_factor_den[2] = 1;
1899   ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_SVC_PARAMETERS, &svc_cfg),
1900             VPX_CODEC_OK);
1901   ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_SVC, 1), VPX_CODEC_OK);
1902   ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_AQ_MODE, 3), VPX_CODEC_OK);
1903   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_STATIC_THRESHOLD, 1),
1904             VPX_CODEC_OK);
1905   ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_COLOR_SPACE, VPX_CS_SMPTE_170),
1906             VPX_CODEC_OK);
1907   ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_COLOR_RANGE, VPX_CR_STUDIO_RANGE),
1908             VPX_CODEC_OK);
1909 
1910   // Create input image.
1911   vpx_image_t *const image =
1912       CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h);
1913   ASSERT_NE(image, nullptr);
1914 
1915   // Encode frame.
1916   ASSERT_EQ(vpx_codec_encode(&enc, image, 0, /*duration=*/500000,
1917                              VPX_EFLAG_FORCE_KF, VPX_DL_REALTIME),
1918             VPX_CODEC_OK);
1919 
1920   // Free resources.
1921   vpx_img_free(image);
1922   ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
1923 }
1924 
1925 #endif  // CONFIG_VP9_ENCODER
1926 
1927 }  // namespace
1928