svc_test.cc 27.1 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
  svc_.spatial_layers = 2;
402
  InitializeEncoder();
403
404
}

405
406
TEST_F(SvcTest, InvalidOptions) {
  vpx_codec_err_t res = vpx_svc_set_options(&svc_, NULL);
407
408
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

409
410
411
  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_);
412
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
413
}
414

415
TEST_F(SvcTest, SetLayersOption) {
416
  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "spatial-layers=3");
417
  EXPECT_EQ(VPX_CODEC_OK, res);
418
  InitializeEncoder();
419
  EXPECT_EQ(3, svc_.spatial_layers);
420
}
421

422
TEST_F(SvcTest, SetMultipleOptions) {
423
  vpx_codec_err_t res =
424
      vpx_svc_set_options(&svc_, "spatial-layers=2 scale-factors=1/3,2/3");
425
  EXPECT_EQ(VPX_CODEC_OK, res);
426
  InitializeEncoder();
427
  EXPECT_EQ(2, svc_.spatial_layers);
428
}
429

430
431
432
433
434
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);
435
436
437
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

438
439
440
441
442
443
444
445
446
447
  res = vpx_svc_set_options(&svc_, "scale-factors=1/3, 3*3");
  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_, "scale-factors=1/3");
  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);

448
449
  res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
  EXPECT_EQ(VPX_CODEC_OK, res);
450
  InitializeEncoder();
451
}
452

453
454
TEST_F(SvcTest, SetQuantizersOption) {
  svc_.spatial_layers = 2;
455
  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "max-quantizers=nothing");
456
  EXPECT_EQ(VPX_CODEC_OK, res);
457
458
459
  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);

460
  res = vpx_svc_set_options(&svc_, "min-quantizers=nothing");
461
462
463
464
  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);

465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  res = vpx_svc_set_options(&svc_, "max-quantizers=40");
  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_, "min-quantizers=40");
  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_, "max-quantizers=30,30 min-quantizers=40,40");
  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_, "max-quantizers=40,40 min-quantizers=30,30");
481
  InitializeEncoder();
482
483
}

484
485
486
487
488
489
490
491
492
493
494
495
496
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");
497
  InitializeEncoder();
498
499
}

500
// Test that decoder can handle an SVC frame as the first frame in a sequence.
501
502
503
504
505
506
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);
507
508
}

509
510
511
512
513
514
515
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);
516
517
}

518
TEST_F(SvcTest, TwoPassEncode10Frames) {
519
520
  // First pass encode
  std::string stats_buf;
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  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;
539
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
540
541
542
543
544
545
  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);
}
546

547
TEST_F(SvcTest, TwoPassEncode2SpatialLayersDecodeBaseLayerOnly) {
548
549
550
  // First pass encode
  std::string stats_buf;
  Pass1EncodeNFrames(10, 2, &stats_buf);
551

552
553
  // Second pass encode
  codec_enc_.g_pass = VPX_RC_LAST_PASS;
554
  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
555
556
557
  vpx_fixed_buf outputs[10];
  memset(&outputs[0], 0, sizeof(outputs));
  Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
558
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, false);
559
560
561
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}
562

563
TEST_F(SvcTest, TwoPassEncode5SpatialLayersDecode54321Layers) {
564
565
566
  // First pass encode
  std::string stats_buf;
  Pass1EncodeNFrames(10, 5, &stats_buf);
567

568
569
570
571
572
573
574
575
  // 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);
576
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 4, false);
577
  DecodeNFrames(&outputs[0], 10);
578
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 3, false);
579
  DecodeNFrames(&outputs[0], 10);
580
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, false);
581
  DecodeNFrames(&outputs[0], 10);
582
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, false);
583
584
585
586
  DecodeNFrames(&outputs[0], 10);

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

588
589
590
591
592
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);
593

594
595
596
597
598
599
600
601
602
603
  // 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);
}
604

605
606
607
608
609
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);
610

611
612
613
614
615
616
617
618
  // 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);
619
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 20, 2, false);
620
  DecodeNFrames(&outputs[0], 20);
621
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 20, 1, false);
622
623
624
  DecodeNFrames(&outputs[0], 20);

  FreeBitstreamBuffers(&outputs[0], 20);
625
626
}

627
TEST_F(SvcTest, SetMultipleFrameContextsOption) {
628
629
630
631
632
633
634
635
636
637
638
639
  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();
}

640
TEST_F(SvcTest, TwoPassEncode2SpatialLayersWithMultipleFrameContexts) {
641
642
643
644
645
646
647
648
649
650
651
  // 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]);
652
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, true);
653
654
655
656
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

657
658
TEST_F(SvcTest,
       TwoPassEncode2SpatialLayersWithMultipleFrameContextsDecodeBaselayer) {
659
660
661
662
663
664
665
666
667
668
669
  // 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]);
670
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, true);
671
672
673
674
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

675
TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContexts) {
676
677
678
679
680
681
682
683
684
685
686
687
688
  // 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]);
689
  DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, true);
690
691
692
693
  DecodeNFrames(&outputs[0], 10);
  FreeBitstreamBuffers(&outputs[0], 10);
}

694
695
TEST_F(SvcTest,
       TwoPassEncode3SNRLayersWithMultipleFrameContextsDecode321Layer) {
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  // 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;
  }
717
  DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 3, true);
718
719
720
721
722
723
  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;
  }
724
  DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 2, true);
725
726
727
728
729
730
  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;
  }
731
  DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 1, true);
732
733
734
735
736
737
  DecodeNFrames(&outputs_new[0], 10);

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

738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
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
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);
}

827
}  // namespace