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