svc_test.cc 28.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/i420_video_source.h"
16
17
18

#include "vp9/decoder/vp9_decoder.h"

19
20
21
22
23
24
25
26
#include "vpx/svc_context.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"

namespace {

using libvpx_test::CodecFactory;
using libvpx_test::Decoder;
27
using libvpx_test::DxDataIterator;
28
29
30
31
32
33
34
35
36
37
using libvpx_test::VP9CodecFactory;

class SvcTest : public ::testing::Test {
 protected:
  static const uint32_t kWidth = 352;
  static const uint32_t kHeight = 288;

  SvcTest()
      : codec_iface_(0),
        test_file_name_("hantro_collage_w352h288.yuv"),
38
39
40
41
42
43
        codec_initialized_(false),
        decoder_(0) {
    memset(&svc_, 0, sizeof(svc_));
    memset(&codec_, 0, sizeof(codec_));
    memset(&codec_enc_, 0, sizeof(codec_enc_));
  }
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

  virtual ~SvcTest() {}

  virtual void SetUp() {
    svc_.log_level = SVC_LOG_DEBUG;
    svc_.log_print = 0;

    codec_iface_ = vpx_codec_vp9_cx();
    const vpx_codec_err_t res =
        vpx_codec_enc_config_default(codec_iface_, &codec_enc_, 0);
    EXPECT_EQ(VPX_CODEC_OK, res);

    codec_enc_.g_w = kWidth;
    codec_enc_.g_h = kHeight;
    codec_enc_.g_timebase.num = 1;
    codec_enc_.g_timebase.den = 60;
    codec_enc_.kf_min_dist = 100;
    codec_enc_.kf_max_dist = 100;

63
    vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t();
64
65
66
67
68
    VP9CodecFactory codec_factory;
    decoder_ = codec_factory.CreateDecoder(dec_cfg, 0);
  }

  virtual void TearDown() {
69
    ReleaseEncoder();
70
    delete(decoder_);
71
72
73
74
75
76
  }

  void InitializeEncoder() {
    const vpx_codec_err_t res =
        vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
    EXPECT_EQ(VPX_CODEC_OK, res);
77
    vpx_codec_control(&codec_, VP8E_SET_CPUUSED, 4);  // Make the test faster
78
79
80
81
82
    codec_initialized_ = true;
  }

  void ReleaseEncoder() {
    vpx_svc_release(&svc_);
83
    if (codec_initialized_) vpx_codec_destroy(&codec_);
84
85
86
    codec_initialized_ = false;
  }

87
88
89
90
91
92
93
94
95
96
97
98
99
100
  void GetStatsData(std::string *const stats_buf) {
    vpx_codec_iter_t iter = NULL;
    const vpx_codec_cx_pkt_t *cx_pkt;

    while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) {
      if (cx_pkt->kind == VPX_CODEC_STATS_PKT) {
        EXPECT_GT(cx_pkt->data.twopass_stats.sz, 0U);
        ASSERT_TRUE(cx_pkt->data.twopass_stats.buf != NULL);
        stats_buf->append(static_cast<char*>(cx_pkt->data.twopass_stats.buf),
                          cx_pkt->data.twopass_stats.sz);
      }
    }
  }

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  void Pass1EncodeNFrames(const int n, const int layers,
                          std::string *const stats_buf) {
    vpx_codec_err_t res;

    ASSERT_GT(n, 0);
    ASSERT_GT(layers, 0);
    svc_.spatial_layers = layers;
    codec_enc_.g_pass = VPX_RC_FIRST_PASS;
    InitializeEncoder();

    libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
                                       codec_enc_.g_timebase.den,
                                       codec_enc_.g_timebase.num, 0, 30);
    video.Begin();

    for (int i = 0; i < n; ++i) {
      res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
                           video.duration(), VPX_DL_GOOD_QUALITY);
      ASSERT_EQ(VPX_CODEC_OK, res);
120
      GetStatsData(stats_buf);
121
122
123
      video.Next();
    }

124
    // Flush encoder and test EOS packet.
125
126
    res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(),
                         video.duration(), VPX_DL_GOOD_QUALITY);
127
128
    ASSERT_EQ(VPX_CODEC_OK, res);
    GetStatsData(stats_buf);
129
130
131
132
133
134
135

    ReleaseEncoder();
  }

  void StoreFrames(const size_t max_frame_received,
                   struct vpx_fixed_buf *const outputs,
                   size_t *const frame_received) {
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    vpx_codec_iter_t iter = NULL;
    const vpx_codec_cx_pkt_t *cx_pkt;

    while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) {
      if (cx_pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
        const size_t frame_size = cx_pkt->data.frame.sz;

        EXPECT_GT(frame_size, 0U);
        ASSERT_TRUE(cx_pkt->data.frame.buf != NULL);
        ASSERT_LT(*frame_received, max_frame_received);

        if (*frame_received == 0)
          EXPECT_EQ(1, !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY));

        outputs[*frame_received].buf = malloc(frame_size + 16);
        ASSERT_TRUE(outputs[*frame_received].buf != NULL);
        memcpy(outputs[*frame_received].buf, cx_pkt->data.frame.buf,
               frame_size);
        outputs[*frame_received].sz = frame_size;
        ++(*frame_received);
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
      }
    }
  }

  void Pass2EncodeNFrames(std::string *const stats_buf,
                          const int n, const int layers,
                          struct vpx_fixed_buf *const outputs) {
    vpx_codec_err_t res;
    size_t frame_received = 0;

    ASSERT_TRUE(outputs != NULL);
    ASSERT_GT(n, 0);
    ASSERT_GT(layers, 0);
    svc_.spatial_layers = layers;
    codec_enc_.rc_target_bitrate = 500;
    if (codec_enc_.g_pass == VPX_RC_LAST_PASS) {
      ASSERT_TRUE(stats_buf != NULL);
      ASSERT_GT(stats_buf->size(), 0U);
      codec_enc_.rc_twopass_stats_in.buf = &(*stats_buf)[0];
      codec_enc_.rc_twopass_stats_in.sz = stats_buf->size();
    }
    InitializeEncoder();

    libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
                                       codec_enc_.g_timebase.den,
                                       codec_enc_.g_timebase.num, 0, 30);
    video.Begin();

    for (int i = 0; i < n; ++i) {
      res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
                           video.duration(), VPX_DL_GOOD_QUALITY);
      ASSERT_EQ(VPX_CODEC_OK, res);
      StoreFrames(n, outputs, &frame_received);
      video.Next();
    }

192
    // Flush encoder.
193
194
195
196
197
    res = vpx_svc_encode(&svc_, &codec_, NULL, 0,
                         video.duration(), VPX_DL_GOOD_QUALITY);
    EXPECT_EQ(VPX_CODEC_OK, res);
    StoreFrames(n, outputs, &frame_received);

198
    EXPECT_EQ(frame_received, static_cast<size_t>(n));
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

    ReleaseEncoder();
  }

  void DecodeNFrames(const struct vpx_fixed_buf *const inputs, const int n) {
    int decoded_frames = 0;
    int received_frames = 0;

    ASSERT_TRUE(inputs != NULL);
    ASSERT_GT(n, 0);

    for (int i = 0; i < n; ++i) {
      ASSERT_TRUE(inputs[i].buf != NULL);
      ASSERT_GT(inputs[i].sz, 0U);
      const vpx_codec_err_t res_dec =
          decoder_->DecodeFrame(static_cast<const uint8_t *>(inputs[i].buf),
                                inputs[i].sz);
      ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
      ++decoded_frames;

      DxDataIterator dec_iter = decoder_->GetDxData();
220
      while (dec_iter.Next() != NULL) {
221
222
223
224
225
226
227
        ++received_frames;
      }
    }
    EXPECT_EQ(decoded_frames, n);
    EXPECT_EQ(received_frames, n);
  }

228
229
230
231
  void DropLayersAndMakeItVP9Comaptible(struct vpx_fixed_buf *const inputs,
                                        const int num_super_frames,
                                        const int remained_spatial_layers,
                                        const bool is_multiple_frame_contexts) {
232
233
    ASSERT_TRUE(inputs != NULL);
    ASSERT_GT(num_super_frames, 0);
234
    ASSERT_GT(remained_spatial_layers, 0);
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

    for (int i = 0; i < num_super_frames; ++i) {
      uint32_t frame_sizes[8] = {0};
      int frame_count = 0;
      int frames_found = 0;
      int frame;
      ASSERT_TRUE(inputs[i].buf != NULL);
      ASSERT_GT(inputs[i].sz, 0U);

      vpx_codec_err_t res =
          vp9_parse_superframe_index(static_cast<const uint8_t*>(inputs[i].buf),
                                     inputs[i].sz, frame_sizes, &frame_count,
                                     NULL, NULL);
      ASSERT_EQ(VPX_CODEC_OK, res);

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
      if (frame_count == 0) {
        // There's no super frame but only a single frame.
        ASSERT_EQ(1, remained_spatial_layers);
        if (is_multiple_frame_contexts) {
          // Make a new super frame.
          uint8_t marker = 0xc1;
          unsigned int mask;
          int mag;

          // Choose the magnitude.
          for (mag = 0, mask = 0xff; mag < 4; ++mag) {
            if (inputs[i].sz < mask)
              break;
            mask <<= 8;
            mask |= 0xff;
          }
          marker |= mag << 3;
          int index_sz = 2 + (mag + 1) * 2;

          inputs[i].buf = realloc(inputs[i].buf, inputs[i].sz + index_sz + 16);
          ASSERT_TRUE(inputs[i].buf != NULL);
          uint8_t *frame_data = static_cast<uint8_t*>(inputs[i].buf);
          frame_data[0] &= ~2;      // Set the show_frame flag to 0.
          frame_data += inputs[i].sz;
          // Add an one byte frame with show_existing_frame.
          *frame_data++ = 0x88;

          // Write the super frame index.
          *frame_data++ = marker;

          frame_sizes[0] = inputs[i].sz;
          frame_sizes[1] = 1;
          for (int j = 0; j < 2; ++j) {
            unsigned int this_sz = frame_sizes[j];
            for (int k = 0; k <= mag; k++) {
              *frame_data++ = this_sz & 0xff;
              this_sz >>= 8;
            }
          }
          *frame_data++ = marker;
          inputs[i].sz += index_sz + 1;
291
        }
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
      } else {
        // Found a super frame.
        uint8_t *frame_data = static_cast<uint8_t*>(inputs[i].buf);
        uint8_t *frame_start = frame_data;
        for (frame = 0; frame < frame_count; ++frame) {
          // Looking for a visible frame.
          if (frame_data[0] & 0x02) {
            ++frames_found;
            if (frames_found == remained_spatial_layers)
              break;
          }
          frame_data += frame_sizes[frame];
        }
        ASSERT_LT(frame, frame_count) << "Couldn't find a visible frame. "
            << "remained_spatial_layers: " << remained_spatial_layers
            << "    super_frame: " << i
            << "    is_multiple_frame_context: " << is_multiple_frame_contexts;
        if (frame == frame_count - 1 && !is_multiple_frame_contexts)
          continue;

312
        frame_data += frame_sizes[frame];
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342

        // We need to add one more frame for multiple frame contexts.
        if (is_multiple_frame_contexts)
          ++frame;
        uint8_t marker =
            static_cast<const uint8_t*>(inputs[i].buf)[inputs[i].sz - 1];
        const uint32_t mag = ((marker >> 3) & 0x3) + 1;
        const size_t index_sz = 2 + mag * frame_count;
        const size_t new_index_sz = 2 + mag * (frame + 1);
        marker &= 0x0f8;
        marker |= frame;

        // Copy existing frame sizes.
        memmove(frame_data + (is_multiple_frame_contexts ? 2 : 1),
                frame_start + inputs[i].sz - index_sz + 1, new_index_sz - 2);
        if (is_multiple_frame_contexts) {
          // Add a one byte frame with flag show_existing_frame.
          *frame_data++ = 0x88 | (remained_spatial_layers - 1);
        }
        // New marker.
        frame_data[0] = marker;
        frame_data += (mag * (frame + 1) + 1);

        if (is_multiple_frame_contexts) {
          // Write the frame size for the one byte frame.
          frame_data -= mag;
          *frame_data++ = 1;
          for (uint32_t j = 1; j < mag; ++j) {
            *frame_data++ = 0;
          }
343
344
        }

345
346
        *frame_data++ = marker;
        inputs[i].sz = frame_data - frame_start;
347

348
349
350
351
352
353
        if (is_multiple_frame_contexts) {
          // Change the show frame flag to 0 for all frames.
          for (int j = 0; j < frame; ++j) {
            frame_start[0] &= ~2;
            frame_start += frame_sizes[j];
          }
354
355
        }
      }
356
357
358
359
360
361
362
363
364
365
366
367
    }
  }

  void FreeBitstreamBuffers(struct vpx_fixed_buf *const inputs, const int n) {
    ASSERT_TRUE(inputs != NULL);
    ASSERT_GT(n, 0);

    for (int i = 0; i < n; ++i) {
      free(inputs[i].buf);
      inputs[i].buf = NULL;
      inputs[i].sz = 0;
    }
368
369
370
371
372
373
374
  }

  SvcContext svc_;
  vpx_codec_ctx_t codec_;
  struct vpx_codec_enc_cfg codec_enc_;
  vpx_codec_iface_t *codec_iface_;
  std::string test_file_name_;
375
  bool codec_initialized_;
376
377
378
379
  Decoder *decoder_;
};

TEST_F(SvcTest, SvcInit) {
380
381
  // test missing parameters
  vpx_codec_err_t res = vpx_svc_init(NULL, &codec_, codec_iface_, &codec_enc_);
382
383
384
385
386
387
388
389
390
391
392
393
394
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
  res = vpx_svc_init(&svc_, NULL, codec_iface_, &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
  res = vpx_svc_init(&svc_, &codec_, NULL, &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  res = vpx_svc_init(&svc_, &codec_, codec_iface_, NULL);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  svc_.spatial_layers = 6;  // too many layers
  res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

395
  svc_.spatial_layers = 0;  // use default layers
396
  InitializeEncoder();
397
398
399
400
  EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers);
}

TEST_F(SvcTest, InitTwoLayers) {
401
402
  svc_.spatial_layers = 2;
  vpx_svc_set_scale_factors(&svc_, "4/16,16*16");  // invalid scale values
403
  vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
404
405
406
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  vpx_svc_set_scale_factors(&svc_, "4/16,16/16");  // valid scale values
407
  InitializeEncoder();
408
409
}

410
411
TEST_F(SvcTest, InvalidOptions) {
  vpx_codec_err_t res = vpx_svc_set_options(&svc_, NULL);
412
413
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

414
415
416
  res = vpx_svc_set_options(&svc_, "not-an-option=1");
  EXPECT_EQ(VPX_CODEC_OK, res);
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
417
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
418
}
419

420
TEST_F(SvcTest, SetLayersOption) {
421
  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "spatial-layers=3");
422
  EXPECT_EQ(VPX_CODEC_OK, res);
423
  InitializeEncoder();
424
  EXPECT_EQ(3, svc_.spatial_layers);
425
}
426

427
TEST_F(SvcTest, SetMultipleOptions) {
428
  vpx_codec_err_t res =
429
      vpx_svc_set_options(&svc_, "spatial-layers=2 scale-factors=1/3,2/3");
430
  EXPECT_EQ(VPX_CODEC_OK, res);
431
  InitializeEncoder();
432
  EXPECT_EQ(2, svc_.spatial_layers);
433
}
434

435
436
437
438
439
TEST_F(SvcTest, SetScaleFactorsOption) {
  svc_.spatial_layers = 2;
  vpx_codec_err_t res =
      vpx_svc_set_options(&svc_, "scale-factors=not-scale-factors");
  EXPECT_EQ(VPX_CODEC_OK, res);
440
441
442
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

443
444
  res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
  EXPECT_EQ(VPX_CODEC_OK, res);
445
  InitializeEncoder();
446
}
447

448
449
450
451
TEST_F(SvcTest, SetQuantizersOption) {
  svc_.spatial_layers = 2;
  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "quantizers=not-quantizers");
  EXPECT_EQ(VPX_CODEC_OK, res);
452
453
454
455
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  vpx_svc_set_options(&svc_, "quantizers=40,45");
456
  InitializeEncoder();
457
458
}

459
460
461
462
463
464
465
466
467
468
469
470
471
TEST_F(SvcTest, SetAutoAltRefOption) {
  svc_.spatial_layers = 5;
  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "auto-alt-refs=none");
  EXPECT_EQ(VPX_CODEC_OK, res);
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  res = vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1,1,0");
  EXPECT_EQ(VPX_CODEC_OK, res);
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
472
  InitializeEncoder();
473
474
}

475
TEST_F(SvcTest, SetQuantizers) {
476
  vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30");
477
478
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

479
  res = vpx_svc_set_quantizers(&svc_, NULL);
480
481
482
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  svc_.spatial_layers = 2;
483
  res = vpx_svc_set_quantizers(&svc_, "40");
484
485
  EXPECT_EQ(VPX_CODEC_OK, res);
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
486
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
487

488
  res = vpx_svc_set_quantizers(&svc_, "40,30");
489
  EXPECT_EQ(VPX_CODEC_OK, res);
490
  InitializeEncoder();
491
492
493
494
495
496
497
498
499
500
}

TEST_F(SvcTest, SetScaleFactors) {
  vpx_codec_err_t res = vpx_svc_set_scale_factors(NULL, "4/16,16/16");
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  res = vpx_svc_set_scale_factors(&svc_, NULL);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  svc_.spatial_layers = 2;
501
  res = vpx_svc_set_scale_factors(&svc_, "4/16");
502
503
  EXPECT_EQ(VPX_CODEC_OK, res);
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
504
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
505

506
  res = vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
507
  EXPECT_EQ(VPX_CODEC_OK, res);
508
  InitializeEncoder();
509
510
}

511
// Test that decoder can handle an SVC frame as the first frame in a sequence.
512
513
514
515
516
517
TEST_F(SvcTest, OnePassEncodeOneFrame) {
  codec_enc_.g_pass = VPX_RC_ONE_PASS;
  vpx_fixed_buf output = {0};
  Pass2EncodeNFrames(NULL, 1, 2, &output);
  DecodeNFrames(&output, 1);
  FreeBitstreamBuffers(&output, 1);
518
519
}

520
521
522
523
524
525
526
TEST_F(SvcTest, OnePassEncodeThreeFrames) {
  codec_enc_.g_pass = VPX_RC_ONE_PASS;
  vpx_fixed_buf outputs[3];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(NULL, 3, 2, &outputs[0]);
  DecodeNFrames(&outputs[0], 3);
  FreeBitstreamBuffers(&outputs[0], 3);
527
528
529
530
531
}

TEST_F(SvcTest, GetLayerResolution) {
  svc_.spatial_layers = 2;
  vpx_svc_set_scale_factors(&svc_, "4/16,8/16");
532
  vpx_svc_set_quantizers(&svc_, "40,30");
533

534
  InitializeEncoder();
535
536
537

  // ensure that requested layer is a valid layer
  uint32_t layer_width, layer_height;
538
  vpx_codec_err_t res = vpx_svc_get_layer_resolution(&svc_, svc_.spatial_layers,
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
                                     &layer_width, &layer_height);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  res = vpx_svc_get_layer_resolution(NULL, 0, &layer_width, &layer_height);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  res = vpx_svc_get_layer_resolution(&svc_, 0, NULL, &layer_height);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, NULL);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, &layer_height);
  EXPECT_EQ(VPX_CODEC_OK, res);
  EXPECT_EQ(kWidth * 4 / 16, layer_width);
  EXPECT_EQ(kHeight * 4 / 16, layer_height);

  res = vpx_svc_get_layer_resolution(&svc_, 1, &layer_width, &layer_height);
  EXPECT_EQ(VPX_CODEC_OK, res);
  EXPECT_EQ(kWidth * 8 / 16, layer_width);
  EXPECT_EQ(kHeight * 8 / 16, layer_height);
}

562
TEST_F(SvcTest, TwoPassEncode10Frames) {
563
564
  // First pass encode
  std::string stats_buf;
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  Pass1EncodeNFrames(10, 2, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

TEST_F(SvcTest, TwoPassEncode20FramesWithAltRef) {
  // First pass encode
  std::string stats_buf;
  Pass1EncodeNFrames(20, 2, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
583
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
584
585
586
587
588
589
  vpx_fixed_buf outputs[20];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]);
  DecodeNFrames(&outputs[0], 20);
  FreeBitstreamBuffers(&outputs[0], 20);
}
590

591
TEST_F(SvcTest, TwoPassEncode2SpatialLayersDecodeBaseLayerOnly) {
592
593
594
  // First pass encode
  std::string stats_buf;
  Pass1EncodeNFrames(10, 2, &stats_buf);
595

596
597
  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
598
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
599
600
601
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
602
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, false);
603
604
605
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}
606

607
TEST_F(SvcTest, TwoPassEncode5SpatialLayersDecode54321Layers) {
608
609
610
  // First pass encode
  std::string stats_buf;
  Pass1EncodeNFrames(10, 5, &stats_buf);
611

612
613
614
615
616
617
618
619
  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]);

  DecodeNFrames(&outputs[0], 10);
620
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 4, false);
621
  DecodeNFrames(&outputs[0], 10);
622
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 3, false);
623
  DecodeNFrames(&outputs[0], 10);
624
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, false);
625
  DecodeNFrames(&outputs[0], 10);
626
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, false);
627
628
629
630
  DecodeNFrames(&outputs[0], 10);

  FreeBitstreamBuffers(&outputs[0], 10);
}
631

632
633
634
635
636
TEST_F(SvcTest, TwoPassEncode2SNRLayers) {
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1");
  Pass1EncodeNFrames(20, 2, &stats_buf);
637

638
639
640
641
642
643
644
645
646
647
  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  vpx_svc_set_options(&svc_,
                      "auto-alt-refs=1,1 scale-factors=1/1,1/1");
  vpx_fixed_buf outputs[20];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]);
  DecodeNFrames(&outputs[0], 20);
  FreeBitstreamBuffers(&outputs[0], 20);
}
648

649
650
651
652
653
TEST_F(SvcTest, TwoPassEncode3SNRLayersDecode321Layers) {
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
  Pass1EncodeNFrames(20, 3, &stats_buf);
654

655
656
657
658
659
660
661
662
  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  vpx_svc_set_options(&svc_,
                      "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1");
  vpx_fixed_buf outputs[20];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]);
  DecodeNFrames(&outputs[0], 20);
663
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 20, 2, false);
664
  DecodeNFrames(&outputs[0], 20);
665
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 20, 1, false);
666
667
668
  DecodeNFrames(&outputs[0], 20);

  FreeBitstreamBuffers(&outputs[0], 20);
669
670
}

671
TEST_F(SvcTest, SetMultipleFrameContextsOption) {
672
673
674
675
676
677
678
679
680
681
682
683
  svc_.spatial_layers = 5;
  vpx_codec_err_t res =
      vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
  EXPECT_EQ(VPX_CODEC_OK, res);
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

  svc_.spatial_layers = 2;
  res = vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
  InitializeEncoder();
}

684
TEST_F(SvcTest, TwoPassEncode2SpatialLayersWithMultipleFrameContexts) {
685
686
687
688
689
690
691
692
693
694
695
  // First pass encode
  std::string stats_buf;
  Pass1EncodeNFrames(10, 2, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  codec_enc_.g_error_resilient = 0;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
696
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, true);
697
698
699
700
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

701
702
TEST_F(SvcTest,
       TwoPassEncode2SpatialLayersWithMultipleFrameContextsDecodeBaselayer) {
703
704
705
706
707
708
709
710
711
712
713
  // First pass encode
  std::string stats_buf;
  Pass1EncodeNFrames(10, 2, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  codec_enc_.g_error_resilient = 0;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
714
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, true);
715
716
717
718
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

719
TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContexts) {
720
721
722
723
724
725
726
727
728
729
730
731
732
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1");
  Pass1EncodeNFrames(10, 2, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  codec_enc_.g_error_resilient = 0;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 scale-factors=1/1,1/1 "
                      "multi-frame-contexts=1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
733
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, true);
734
735
736
737
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

738
739
TEST_F(SvcTest,
       TwoPassEncode3SNRLayersWithMultipleFrameContextsDecode321Layer) {
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
  Pass1EncodeNFrames(10, 3, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  codec_enc_.g_error_resilient = 0;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1 "
                      "multi-frame-contexts=1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 3, &outputs[0]);

  vpx_fixed_buf outputs_new[10];
  for (int i = 0; i < 10; ++i) {
    outputs_new[i].buf = malloc(outputs[i].sz + 16);
    ASSERT_TRUE(outputs_new[i].buf != NULL);
    memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
    outputs_new[i].sz = outputs[i].sz;
  }
761
  DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 3, true);
762
763
764
765
766
767
  DecodeNFrames(&outputs_new[0], 10);

  for (int i = 0; i < 10; ++i) {
    memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
    outputs_new[i].sz = outputs[i].sz;
  }
768
  DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 2, true);
769
770
771
772
773
774
  DecodeNFrames(&outputs_new[0], 10);

  for (int i = 0; i < 10; ++i) {
    memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
    outputs_new[i].sz = outputs[i].sz;
  }
775
  DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 1, true);
776
777
778
779
780
781
  DecodeNFrames(&outputs_new[0], 10);

  FreeBitstreamBuffers(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs_new[0], 10);
}

782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
TEST_F(SvcTest, TwoPassEncode2TemporalLayers) {
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1");
  svc_.temporal_layers = 2;
  Pass1EncodeNFrames(10, 1, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  svc_.temporal_layers = 2;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithMultipleFrameContexts) {
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1");
  svc_.temporal_layers = 2;
  Pass1EncodeNFrames(10, 1, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  svc_.temporal_layers = 2;
  codec_enc_.g_error_resilient = 0;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 "
                      "multi-frame-contexts=1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, true);
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

TEST_F(SvcTest, TwoPassEncode2TemporalLayersDecodeBaseLayer) {
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1");
  svc_.temporal_layers = 2;
  Pass1EncodeNFrames(10, 1, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  svc_.temporal_layers = 2;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);

  vpx_fixed_buf base_layer[5];
  for (int i = 0; i < 5; ++i)
    base_layer[i] = outputs[i * 2];

  DecodeNFrames(&base_layer[0], 5);
  FreeBitstreamBuffers(&outputs[0], 10);
}

TEST_F(SvcTest,
       TwoPassEncode2TemporalLayersWithMultipleFrameContextsDecodeBaseLayer) {
  // First pass encode
  std::string stats_buf;
  vpx_svc_set_options(&svc_, "scale-factors=1/1");
  svc_.temporal_layers = 2;
  Pass1EncodeNFrames(10, 1, &stats_buf);

  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
  svc_.temporal_layers = 2;
  codec_enc_.g_error_resilient = 0;
  vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 "
                      "multi-frame-contexts=1");
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, true);

  vpx_fixed_buf base_layer[5];
  for (int i = 0; i < 5; ++i)
    base_layer[i] = outputs[i * 2];

  DecodeNFrames(&base_layer[0], 5);
  FreeBitstreamBuffers(&outputs[0], 10);
}

871
}  // namespace