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