1/*
2 *  Copyright (c) 2013 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 <string>
12#include "third_party/googletest/src/include/gtest/gtest.h"
13#include "test/codec_factory.h"
14#include "test/decode_test_driver.h"
15#include "test/i420_video_source.h"
16#include "vpx/svc_context.h"
17#include "vpx/vp8cx.h"
18#include "vpx/vpx_encoder.h"
19
20namespace {
21
22using libvpx_test::CodecFactory;
23using libvpx_test::Decoder;
24using libvpx_test::VP9CodecFactory;
25
26class SvcTest : public ::testing::Test {
27 protected:
28  static const uint32_t kWidth = 352;
29  static const uint32_t kHeight = 288;
30
31  SvcTest()
32      : codec_iface_(0),
33        test_file_name_("hantro_collage_w352h288.yuv"),
34        stats_file_name_("hantro_collage_w352h288.stat"),
35        codec_initialized_(false),
36        decoder_(0) {
37    memset(&svc_, 0, sizeof(svc_));
38    memset(&codec_, 0, sizeof(codec_));
39    memset(&codec_enc_, 0, sizeof(codec_enc_));
40  }
41
42  virtual ~SvcTest() {}
43
44  virtual void SetUp() {
45    svc_.encoding_mode = INTER_LAYER_PREDICTION_IP;
46    svc_.log_level = SVC_LOG_DEBUG;
47    svc_.log_print = 0;
48
49    codec_iface_ = vpx_codec_vp9_cx();
50    const vpx_codec_err_t res =
51        vpx_codec_enc_config_default(codec_iface_, &codec_enc_, 0);
52    EXPECT_EQ(VPX_CODEC_OK, res);
53
54    codec_enc_.g_w = kWidth;
55    codec_enc_.g_h = kHeight;
56    codec_enc_.g_timebase.num = 1;
57    codec_enc_.g_timebase.den = 60;
58    codec_enc_.kf_min_dist = 100;
59    codec_enc_.kf_max_dist = 100;
60
61    vpx_codec_dec_cfg_t dec_cfg = {0};
62    VP9CodecFactory codec_factory;
63    decoder_ = codec_factory.CreateDecoder(dec_cfg, 0);
64  }
65
66  virtual void TearDown() {
67    vpx_svc_release(&svc_);
68    delete(decoder_);
69    if (codec_initialized_) vpx_codec_destroy(&codec_);
70  }
71
72  SvcContext svc_;
73  vpx_codec_ctx_t codec_;
74  struct vpx_codec_enc_cfg codec_enc_;
75  vpx_codec_iface_t *codec_iface_;
76  std::string test_file_name_;
77  std::string stats_file_name_;
78  bool codec_initialized_;
79  Decoder *decoder_;
80};
81
82TEST_F(SvcTest, SvcInit) {
83  // test missing parameters
84  vpx_codec_err_t res = vpx_svc_init(NULL, &codec_, codec_iface_, &codec_enc_);
85  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
86  res = vpx_svc_init(&svc_, NULL, codec_iface_, &codec_enc_);
87  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
88  res = vpx_svc_init(&svc_, &codec_, NULL, &codec_enc_);
89  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
90
91  res = vpx_svc_init(&svc_, &codec_, codec_iface_, NULL);
92  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
93
94  svc_.spatial_layers = 6;  // too many layers
95  res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
96  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
97
98  svc_.spatial_layers = 0;  // use default layers
99  res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
100  EXPECT_EQ(VPX_CODEC_OK, res);
101  codec_initialized_ = true;
102  EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers);
103}
104
105TEST_F(SvcTest, InitTwoLayers) {
106  svc_.spatial_layers = 2;
107  vpx_svc_set_scale_factors(&svc_, "4/16,16*16");  // invalid scale values
108  vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
109  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
110
111  vpx_svc_set_scale_factors(&svc_, "4/16,16/16");  // valid scale values
112  res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
113  EXPECT_EQ(VPX_CODEC_OK, res);
114  codec_initialized_ = true;
115}
116
117TEST_F(SvcTest, InvalidOptions) {
118  vpx_codec_err_t res = vpx_svc_set_options(&svc_, NULL);
119  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
120
121  res = vpx_svc_set_options(&svc_, "not-an-option=1");
122  EXPECT_EQ(VPX_CODEC_OK, res);
123  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
124  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
125}
126
127TEST_F(SvcTest, SetLayersOption) {
128  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=3");
129  EXPECT_EQ(VPX_CODEC_OK, res);
130  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
131  EXPECT_EQ(VPX_CODEC_OK, res);
132  codec_initialized_ = true;
133  EXPECT_EQ(3, svc_.spatial_layers);
134}
135
136TEST_F(SvcTest, SetEncodingMode) {
137  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "encoding-mode=alt-ip");
138  EXPECT_EQ(VPX_CODEC_OK, res);
139  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
140  EXPECT_EQ(VPX_CODEC_OK, res);
141  codec_initialized_ = true;
142  EXPECT_EQ(ALT_INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
143}
144
145TEST_F(SvcTest, SetMultipleOptions) {
146  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=2 encoding-mode=ip");
147  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
148  EXPECT_EQ(VPX_CODEC_OK, res);
149  codec_initialized_ = true;
150  EXPECT_EQ(2, svc_.spatial_layers);
151  EXPECT_EQ(INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
152}
153
154TEST_F(SvcTest, SetScaleFactorsOption) {
155  svc_.spatial_layers = 2;
156  vpx_codec_err_t res =
157      vpx_svc_set_options(&svc_, "scale-factors=not-scale-factors");
158  EXPECT_EQ(VPX_CODEC_OK, res);
159  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
160  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
161
162  res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
163  EXPECT_EQ(VPX_CODEC_OK, res);
164  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
165  EXPECT_EQ(VPX_CODEC_OK, res);
166  codec_initialized_ = true;
167}
168
169TEST_F(SvcTest, SetQuantizersOption) {
170  svc_.spatial_layers = 2;
171  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "quantizers=not-quantizers");
172  EXPECT_EQ(VPX_CODEC_OK, res);
173  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
174  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
175
176  vpx_svc_set_options(&svc_, "quantizers=40,45");
177  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
178  EXPECT_EQ(VPX_CODEC_OK, res);
179  codec_initialized_ = true;
180}
181
182TEST_F(SvcTest, SetKeyFrameQuantizersOption) {
183  svc_.spatial_layers = 2;
184  vpx_codec_err_t res = vpx_svc_set_options(&svc_,
185                                       "quantizers-keyframe=not-quantizers");
186  EXPECT_EQ(VPX_CODEC_OK, res);
187  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
188  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
189
190  vpx_svc_set_options(&svc_, "quantizers-keyframe=40,45");
191  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
192  EXPECT_EQ(VPX_CODEC_OK, res);
193  codec_initialized_ = true;
194}
195
196TEST_F(SvcTest, SetQuantizers) {
197  vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30", 0);
198  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
199
200  res = vpx_svc_set_quantizers(&svc_, NULL, 0);
201  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
202
203  svc_.spatial_layers = 2;
204  res = vpx_svc_set_quantizers(&svc_, "40", 0);
205  EXPECT_EQ(VPX_CODEC_OK, res);
206  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
207  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
208
209  res = vpx_svc_set_quantizers(&svc_, "40,30", 0);
210  EXPECT_EQ(VPX_CODEC_OK, res);
211  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
212  EXPECT_EQ(VPX_CODEC_OK, res);
213  codec_initialized_ = true;
214}
215
216TEST_F(SvcTest, SetKeyFrameQuantizers) {
217  vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,31", 1);
218  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
219
220  res = vpx_svc_set_quantizers(&svc_, NULL, 1);
221  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
222
223  res = vpx_svc_set_quantizers(&svc_, "40,30", 1);
224  EXPECT_EQ(VPX_CODEC_OK, res);
225  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
226  EXPECT_EQ(VPX_CODEC_OK, res);
227  codec_initialized_ = true;
228}
229
230TEST_F(SvcTest, SetScaleFactors) {
231  vpx_codec_err_t res = vpx_svc_set_scale_factors(NULL, "4/16,16/16");
232  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
233
234  res = vpx_svc_set_scale_factors(&svc_, NULL);
235  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
236
237  svc_.spatial_layers = 2;
238  res = vpx_svc_set_scale_factors(&svc_, "4/16");
239  EXPECT_EQ(VPX_CODEC_OK, res);
240  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
241  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
242
243  res = vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
244  EXPECT_EQ(VPX_CODEC_OK, res);
245  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
246  EXPECT_EQ(VPX_CODEC_OK, res);
247  codec_initialized_ = true;
248}
249
250// Test that decoder can handle an SVC frame as the first frame in a sequence.
251TEST_F(SvcTest, FirstFrameHasLayers) {
252  svc_.spatial_layers = 2;
253  vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
254  vpx_svc_set_quantizers(&svc_, "40,30", 0);
255
256  vpx_codec_err_t res =
257      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
258  EXPECT_EQ(VPX_CODEC_OK, res);
259  codec_initialized_ = true;
260
261  libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
262                                     codec_enc_.g_timebase.den,
263                                     codec_enc_.g_timebase.num, 0, 30);
264  video.Begin();
265
266  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
267                       video.duration(), VPX_DL_GOOD_QUALITY);
268  EXPECT_EQ(VPX_CODEC_OK, res);
269
270  const vpx_codec_err_t res_dec = decoder_->DecodeFrame(
271      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
272      vpx_svc_get_frame_size(&svc_));
273
274  // this test fails with a decoder error
275  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
276}
277
278TEST_F(SvcTest, EncodeThreeFrames) {
279  svc_.spatial_layers = 2;
280  vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
281  vpx_svc_set_quantizers(&svc_, "40,30", 0);
282
283  vpx_codec_err_t res =
284      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
285  ASSERT_EQ(VPX_CODEC_OK, res);
286  codec_initialized_ = true;
287
288  libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
289                                     codec_enc_.g_timebase.den,
290                                     codec_enc_.g_timebase.num, 0, 30);
291  // FRAME 0
292  video.Begin();
293  // This frame is a keyframe.
294  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
295                       video.duration(), VPX_DL_GOOD_QUALITY);
296  ASSERT_EQ(VPX_CODEC_OK, res);
297  EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
298
299  vpx_codec_err_t res_dec = decoder_->DecodeFrame(
300      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
301      vpx_svc_get_frame_size(&svc_));
302  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
303
304  // FRAME 1
305  video.Next();
306  // This is a P-frame.
307  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
308                       video.duration(), VPX_DL_GOOD_QUALITY);
309  ASSERT_EQ(VPX_CODEC_OK, res);
310  EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
311
312  res_dec = decoder_->DecodeFrame(
313      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
314      vpx_svc_get_frame_size(&svc_));
315  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
316
317  // FRAME 2
318  video.Next();
319  // This is a P-frame.
320  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
321                       video.duration(), VPX_DL_GOOD_QUALITY);
322  ASSERT_EQ(VPX_CODEC_OK, res);
323  EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
324
325  res_dec = decoder_->DecodeFrame(
326      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
327      vpx_svc_get_frame_size(&svc_));
328  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
329}
330
331TEST_F(SvcTest, GetLayerResolution) {
332  svc_.spatial_layers = 2;
333  vpx_svc_set_scale_factors(&svc_, "4/16,8/16");
334  vpx_svc_set_quantizers(&svc_, "40,30", 0);
335
336  vpx_codec_err_t res =
337      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
338  EXPECT_EQ(VPX_CODEC_OK, res);
339  codec_initialized_ = true;
340
341  // ensure that requested layer is a valid layer
342  uint32_t layer_width, layer_height;
343  res = vpx_svc_get_layer_resolution(&svc_, svc_.spatial_layers,
344                                     &layer_width, &layer_height);
345  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
346
347  res = vpx_svc_get_layer_resolution(NULL, 0, &layer_width, &layer_height);
348  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
349
350  res = vpx_svc_get_layer_resolution(&svc_, 0, NULL, &layer_height);
351  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
352
353  res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, NULL);
354  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
355
356  res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, &layer_height);
357  EXPECT_EQ(VPX_CODEC_OK, res);
358  EXPECT_EQ(kWidth * 4 / 16, layer_width);
359  EXPECT_EQ(kHeight * 4 / 16, layer_height);
360
361  res = vpx_svc_get_layer_resolution(&svc_, 1, &layer_width, &layer_height);
362  EXPECT_EQ(VPX_CODEC_OK, res);
363  EXPECT_EQ(kWidth * 8 / 16, layer_width);
364  EXPECT_EQ(kHeight * 8 / 16, layer_height);
365}
366
367TEST_F(SvcTest, FirstPassEncode) {
368  svc_.spatial_layers = 2;
369  codec_enc_.g_pass = VPX_RC_FIRST_PASS;
370  vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
371  vpx_svc_set_quantizers(&svc_, "40,30", 0);
372
373  vpx_codec_err_t res =
374      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
375  ASSERT_EQ(VPX_CODEC_OK, res);
376  codec_initialized_ = true;
377
378  libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
379                                     codec_enc_.g_timebase.den,
380                                     codec_enc_.g_timebase.num, 0, 30);
381  // FRAME 0
382  video.Begin();
383  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
384                       video.duration(), VPX_DL_GOOD_QUALITY);
385  ASSERT_EQ(VPX_CODEC_OK, res);
386  EXPECT_GT(vpx_svc_get_rc_stats_buffer_size(&svc_), 0U);
387
388  // FRAME 1
389  video.Next();
390  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
391                       video.duration(), VPX_DL_GOOD_QUALITY);
392  ASSERT_EQ(VPX_CODEC_OK, res);
393  EXPECT_GT(vpx_svc_get_rc_stats_buffer_size(&svc_), 0U);
394
395  // Flush encoder and test EOS packet
396  res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(),
397                       video.duration(), VPX_DL_GOOD_QUALITY);
398  ASSERT_EQ(VPX_CODEC_OK, res);
399  EXPECT_GT(vpx_svc_get_rc_stats_buffer_size(&svc_), 0U);
400}
401
402TEST_F(SvcTest, SecondPassEncode) {
403  svc_.spatial_layers = 2;
404  codec_enc_.g_pass = VPX_RC_LAST_PASS;
405
406  FILE *const stats_file = libvpx_test::OpenTestDataFile(stats_file_name_);
407  ASSERT_TRUE(stats_file != NULL) << "Stats file open failed. Filename: "
408      << stats_file;
409
410  struct vpx_fixed_buf stats_buf;
411  fseek(stats_file, 0, SEEK_END);
412  stats_buf.sz = static_cast<size_t>(ftell(stats_file));
413  fseek(stats_file, 0, SEEK_SET);
414
415  stats_buf.buf = malloc(stats_buf.sz);
416  ASSERT_TRUE(stats_buf.buf != NULL);
417  const size_t bytes_read = fread(stats_buf.buf, 1, stats_buf.sz, stats_file);
418  ASSERT_EQ(bytes_read, stats_buf.sz);
419  fclose(stats_file);
420  codec_enc_.rc_twopass_stats_in = stats_buf;
421
422  vpx_codec_err_t res =
423      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
424  ASSERT_EQ(VPX_CODEC_OK, res);
425  codec_initialized_ = true;
426
427  libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
428                                     codec_enc_.g_timebase.den,
429                                     codec_enc_.g_timebase.num, 0, 30);
430  // FRAME 0
431  video.Begin();
432  // This frame is a keyframe.
433  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
434                       video.duration(), VPX_DL_GOOD_QUALITY);
435  ASSERT_EQ(VPX_CODEC_OK, res);
436  EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
437
438  vpx_codec_err_t res_dec = decoder_->DecodeFrame(
439      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
440      vpx_svc_get_frame_size(&svc_));
441  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
442
443  // FRAME 1
444  video.Next();
445  // This is a P-frame.
446  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
447                       video.duration(), VPX_DL_GOOD_QUALITY);
448  ASSERT_EQ(VPX_CODEC_OK, res);
449  EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
450
451  res_dec = decoder_->DecodeFrame(
452      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
453      vpx_svc_get_frame_size(&svc_));
454  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
455
456  // FRAME 2
457  video.Next();
458  // This is a P-frame.
459  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
460                       video.duration(), VPX_DL_GOOD_QUALITY);
461  ASSERT_EQ(VPX_CODEC_OK, res);
462  EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
463
464  res_dec = decoder_->DecodeFrame(
465      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
466      vpx_svc_get_frame_size(&svc_));
467  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
468
469  free(stats_buf.buf);
470}
471
472}  // namespace
473