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