datarate_test.cc 23.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
/*
 *  Copyright (c) 2012 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.
 */
10
#include "./vpx_config.h"
11
12
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
13
14
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
15
#include "test/util.h"
16
#include "test/y4m_video_source.h"
17

18
19
namespace {

20
class DatarateTestLarge : public ::libvpx_test::EncoderTest,
21
22
    public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
 public:
23
24
25
  DatarateTestLarge() : EncoderTest(GET_PARAM(0)) {}

  virtual ~DatarateTestLarge() {}
26

27
28
29
 protected:
  virtual void SetUp() {
    InitializeConfig();
30
    SetMode(GET_PARAM(1));
31
32
33
34
35
36
37
38
39
40
41
42
43
    ResetModel();
  }

  virtual void ResetModel() {
    last_pts_ = 0;
    bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
    frame_number_ = 0;
    first_drop_ = 0;
    bits_total_ = 0;
    duration_ = 0.0;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
44
45
46
47
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 1) {
      encoder->Control(VP8E_SET_NOISE_SENSITIVITY, denoiser_on_);
    }
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
    const vpx_rational_t tb = video->timebase();
    timebase_ = static_cast<double>(tb.num) / tb.den;
    duration_ = 0;
  }

  virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
    // Time since last timestamp = duration.
    vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;

    // TODO(jimbankoski): Remove these lines when the issue:
    // http://code.google.com/p/webm/issues/detail?id=496 is fixed.
    // For now the codec assumes buffer starts at starting buffer rate
    // plus one frame's time.
    if (last_pts_ == 0)
      duration = 1;

    // Add to the buffer the bits we'd expect from a constant bitrate server.
65
66
    bits_in_buffer_model_ += static_cast<int64_t>(
        duration * timebase_ * cfg_.rc_target_bitrate * 1000);
67
68
69
70

    /* Test the buffer model here before subtracting the frame. Do so because
     * the way the leaky bucket model works in libvpx is to allow the buffer to
     * empty - and then stop showing frames until we've got enough bits to
Marco Paniconi's avatar
Marco Paniconi committed
71
72
     * show one. As noted in comment below (issue 495), this does not currently
     * apply to key frames. For now exclude key frames in condition below. */
73
74
    const bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY)
                         ? true: false;
Marco Paniconi's avatar
Marco Paniconi committed
75
76
77
78
    if (!key_frame) {
      ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame "
          << pkt->data.frame.pts;
    }
79

80
    const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
81
82
83
84
85

    // Subtract from the buffer the bits associated with a played back frame.
    bits_in_buffer_model_ -= frame_size_in_bits;

    // Update the running total of bits for end of test datarate checks.
Yaowu Xu's avatar
Yaowu Xu committed
86
    bits_total_ += frame_size_in_bits;
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

    // If first drop not set and we have a drop set it to this time.
    if (!first_drop_ && duration > 1)
      first_drop_ = last_pts_ + 1;

    // Update the most recent pts.
    last_pts_ = pkt->data.frame.pts;

    // We update this so that we can calculate the datarate minus the last
    // frame encoded in the file.
    bits_in_last_frame_ = frame_size_in_bits;

    ++frame_number_;
  }

  virtual void EndPassHook(void) {
    if (bits_total_) {
104
      const double file_size_in_kb = bits_total_ / 1000.;  // bits per kilobit
105
106
107
108
109
110
111
112
113
114
115
116

      duration_ = (last_pts_ + 1) * timebase_;

      // Effective file datarate includes the time spent prebuffering.
      effective_datarate_ = (bits_total_ - bits_in_last_frame_) / 1000.0
          / (cfg_.rc_buf_initial_sz / 1000.0 + duration_);

      file_datarate_ = file_size_in_kb / duration_;
    }
  }

  vpx_codec_pts_t last_pts_;
117
  int64_t bits_in_buffer_model_;
118
119
120
121
122
123
124
  double timebase_;
  int frame_number_;
  vpx_codec_pts_t first_drop_;
  int64_t bits_total_;
  double duration_;
  double file_datarate_;
  double effective_datarate_;
125
  size_t bits_in_last_frame_;
126
  int denoiser_on_;
127
128
};

129
#if CONFIG_TEMPORAL_DENOISING
130
131
132
// Check basic datarate targeting, for a single bitrate, but loop over the
// various denoiser settings.
TEST_P(DatarateTestLarge, DenoiserLevels) {
133
134
135
136
137
138
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_dropframe_thresh = 1;
  cfg_.rc_max_quantizer = 56;
  cfg_.rc_end_usage = VPX_CBR;
  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 140);
139
140
141
142
143
144
145
146
147
148
  for (int j = 1; j < 5; ++j) {
    // Run over the denoiser levels.
    // For the temporal denoiser (#if CONFIG_TEMPORAL_DENOISING) the level j
    // refers to the 4 denoiser modes: denoiserYonly, denoiserOnYUV,
    // denoiserOnAggressive, and denoiserOnAdaptive.
    // For the spatial denoiser (if !CONFIG_TEMPORAL_DENOISING), the level j
    // refers to the blur thresholds: 20, 40, 60 80.
    // The j = 0 case (denoiser off) is covered in the tests below.
    denoiser_on_ = j;
    cfg_.rc_target_bitrate = 300;
149
150
151
152
153
154
155
156
157
    ResetModel();
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
    ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95)
        << " The datarate for the file exceeds the target!";

    ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3)
        << " The datarate for the file missed the target!";
  }
}
158
#endif  // CONFIG_TEMPORAL_DENOISING
159

160
TEST_P(DatarateTestLarge, BasicBufferModel) {
161
  denoiser_on_ = 0;
162
163
164
165
166
167
168
169
170
171
172
173
174
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_dropframe_thresh = 1;
  cfg_.rc_max_quantizer = 56;
  cfg_.rc_end_usage = VPX_CBR;
  // 2 pass cbr datarate control has a bug hidden by the small # of
  // frames selected in this encode. The problem is that even if the buffer is
  // negative we produce a keyframe on a cutscene. Ignoring datarate
  // constraints
  // TODO(jimbankoski): ( Fix when issue
  // http://code.google.com/p/webm/issues/detail?id=495 is addressed. )
  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 140);

Marco Paniconi's avatar
Marco Paniconi committed
175
176
177
178
179
180
  // There is an issue for low bitrates in real-time mode, where the
  // effective_datarate slightly overshoots the target bitrate.
  // This is same the issue as noted about (#495).
  // TODO(jimbankoski/marpan): Update test to run for lower bitrates (< 100),
  // when the issue is resolved.
  for (int i = 100; i < 800; i += 200) {
181
182
183
    cfg_.rc_target_bitrate = i;
    ResetModel();
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
184
    ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95)
185
186
187
188
189
190
191
        << " The datarate for the file exceeds the target!";

    ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3)
        << " The datarate for the file missed the target!";
  }
}

192
TEST_P(DatarateTestLarge, ChangingDropFrameThresh) {
193
  denoiser_on_ = 0;
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_max_quantizer = 36;
  cfg_.rc_end_usage = VPX_CBR;
  cfg_.rc_target_bitrate = 200;
  cfg_.kf_mode = VPX_KF_DISABLED;

  const int frame_count = 40;
  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, frame_count);

  // Here we check that the first dropped frame gets earlier and earlier
  // as the drop frame threshold is increased.

  const int kDropFrameThreshTestStep = 30;
  vpx_codec_pts_t last_drop = frame_count;
  for (int i = 1; i < 91; i += kDropFrameThreshTestStep) {
    cfg_.rc_dropframe_thresh = i;
    ResetModel();
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
    ASSERT_LE(first_drop_, last_drop)
        << " The first dropped frame for drop_thresh " << i
        << " > first dropped frame for drop_thresh "
        << i - kDropFrameThreshTestStep;
    last_drop = first_drop_;
  }
}

221
class DatarateTestVP9Large : public ::libvpx_test::EncoderTest,
Marco Paniconi's avatar
Marco Paniconi committed
222
223
    public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
 public:
224
  DatarateTestVP9Large() : EncoderTest(GET_PARAM(0)) {}
Marco Paniconi's avatar
Marco Paniconi committed
225

Marco Paniconi's avatar
Marco Paniconi committed
226
 protected:
227
  virtual ~DatarateTestVP9Large() {}
Marco Paniconi's avatar
Marco Paniconi committed
228

Marco Paniconi's avatar
Marco Paniconi committed
229
230
231
232
233
234
235
236
237
  virtual void SetUp() {
    InitializeConfig();
    SetMode(GET_PARAM(1));
    set_cpu_used_ = GET_PARAM(2);
    ResetModel();
  }

  virtual void ResetModel() {
    last_pts_ = 0;
238
    bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
Marco Paniconi's avatar
Marco Paniconi committed
239
    frame_number_ = 0;
240
    tot_frame_number_ = 0;
241
242
    first_drop_ = 0;
    num_drops_ = 0;
JackyChen's avatar
JackyChen committed
243
244
    // Denoiser is off by default.
    denoiser_on_ = 0;
245
246
247
248
249
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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    // For testing up to 3 layers.
    for (int i = 0; i < 3; ++i) {
      bits_total_[i] = 0;
    }
  }

  //
  // Frame flags and layer id for temporal layers.
  //

  // For two layers, test pattern is:
  //   1     3
  // 0    2     .....
  // For three layers, test pattern is:
  //   1      3    5      7
  //      2           6
  // 0          4            ....
  // LAST is always update on base/layer 0, GOLDEN is updated on layer 1.
  // For this 3 layer example, the 2nd enhancement layer (layer 2) does not
  // update any reference frames.
  int SetFrameFlags(int frame_num, int num_temp_layers) {
    int frame_flags = 0;
    if (num_temp_layers == 2) {
      if (frame_num % 2 == 0) {
        // Layer 0: predict from L and ARF, update L.
        frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
                      VP8_EFLAG_NO_UPD_ARF;
      } else {
        // Layer 1: predict from L, G and ARF, and update G.
        frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
                      VP8_EFLAG_NO_UPD_ENTROPY;
      }
    } else if (num_temp_layers == 3) {
      if (frame_num % 4 == 0) {
        // Layer 0: predict from L and ARF; update L.
        frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
                      VP8_EFLAG_NO_REF_GF;
      } else if ((frame_num - 2) % 4 == 0) {
        // Layer 1: predict from L, G, ARF; update G.
        frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
      }  else if ((frame_num - 1) % 2 == 0) {
        // Layer 2: predict from L, G, ARF; update none.
        frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
                      VP8_EFLAG_NO_UPD_LAST;
      }
    }
    return frame_flags;
  }

  int SetLayerId(int frame_num, int num_temp_layers) {
    int layer_id = 0;
    if (num_temp_layers == 2) {
      if (frame_num % 2 == 0) {
        layer_id = 0;
      } else {
        layer_id = 1;
      }
    } else if (num_temp_layers == 3) {
      if (frame_num % 4 == 0) {
        layer_id = 0;
      } else if ((frame_num - 2) % 4 == 0) {
        layer_id = 1;
      } else if ((frame_num - 1) % 2 == 0) {
        layer_id = 2;
      }
    }
    return layer_id;
Marco Paniconi's avatar
Marco Paniconi committed
312
313
  }

Marco Paniconi's avatar
Marco Paniconi committed
314
  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
315
                                  ::libvpx_test::Encoder *encoder) {
Marco Paniconi's avatar
Marco Paniconi committed
316
    if (video->frame() == 1) {
Marco Paniconi's avatar
Marco Paniconi committed
317
      encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
JackyChen's avatar
JackyChen committed
318
      encoder->Control(VP9E_SET_NOISE_SENSITIVITY, denoiser_on_);
Marco Paniconi's avatar
Marco Paniconi committed
319
    }
320
321
322
323
324
325
326
327
328
329
330
331
332
    if (cfg_.ts_number_layers > 1) {
      if (video->frame() == 1) {
        encoder->Control(VP9E_SET_SVC, 1);
      }
      vpx_svc_layer_id_t layer_id = {0, 0};
      layer_id.spatial_layer_id = 0;
      frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
      layer_id.temporal_layer_id = SetLayerId(video->frame(),
                                              cfg_.ts_number_layers);
      if (video->frame() > 0) {
       encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id);
      }
    }
Marco Paniconi's avatar
Marco Paniconi committed
333
334
335
336
337
    const vpx_rational_t tb = video->timebase();
    timebase_ = static_cast<double>(tb.num) / tb.den;
    duration_ = 0;
  }

338

Marco Paniconi's avatar
Marco Paniconi committed
339
  virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
340
341
342
    // Time since last timestamp = duration.
    vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;

343
344
345
346
347
348
349
350
351
352
353
354
355
    if (duration > 1) {
      // If first drop not set and we have a drop set it to this time.
      if (!first_drop_)
        first_drop_ = last_pts_ + 1;
      // Update the number of frame drops.
      num_drops_ += static_cast<int>(duration - 1);
      // Update counter for total number of frames (#frames input to encoder).
      // Needed for setting the proper layer_id below.
      tot_frame_number_ += static_cast<int>(duration - 1);
    }

    int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers);

356
    // Add to the buffer the bits we'd expect from a constant bitrate server.
357
358
    bits_in_buffer_model_ += static_cast<int64_t>(
        duration * timebase_ * cfg_.rc_target_bitrate * 1000);
359
360
361
362
363

    // Buffer should not go negative.
    ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame "
        << pkt->data.frame.pts;

364
    const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
365
366
367
368
369
370

    // Update the total encoded bits. For temporal layers, update the cumulative
    // encoded bits per layer.
    for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) {
      bits_total_[i] += frame_size_in_bits;
    }
371

Marco Paniconi's avatar
Marco Paniconi committed
372
373
374
    // Update the most recent pts.
    last_pts_ = pkt->data.frame.pts;
    ++frame_number_;
375
    ++tot_frame_number_;
Marco Paniconi's avatar
Marco Paniconi committed
376
377
378
  }

  virtual void EndPassHook(void) {
379
380
    for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
        ++layer) {
Marco Paniconi's avatar
Marco Paniconi committed
381
      duration_ = (last_pts_ + 1) * timebase_;
382
383
384
385
      if (bits_total_[layer]) {
        // Effective file datarate:
        effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
      }
Marco Paniconi's avatar
Marco Paniconi committed
386
387
    }
  }
Marco Paniconi's avatar
Marco Paniconi committed
388
389
390

  vpx_codec_pts_t last_pts_;
  double timebase_;
391
392
  int frame_number_;      // Counter for number of non-dropped/encoded frames.
  int tot_frame_number_;  // Counter for total number of input frames.
393
  int64_t bits_total_[3];
Marco Paniconi's avatar
Marco Paniconi committed
394
  double duration_;
395
  double effective_datarate_[3];
Marco Paniconi's avatar
Marco Paniconi committed
396
  int set_cpu_used_;
397
398
  int64_t bits_in_buffer_model_;
  vpx_codec_pts_t first_drop_;
399
  int num_drops_;
JackyChen's avatar
JackyChen committed
400
  int denoiser_on_;
Marco Paniconi's avatar
Marco Paniconi committed
401
402
};

403
// Check basic rate targeting,
404
TEST_P(DatarateTestVP9Large, BasicRateTargeting) {
405
406
407
408
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 500;
  cfg_.rc_buf_sz = 1000;
  cfg_.rc_dropframe_thresh = 1;
Marco Paniconi's avatar
Marco Paniconi committed
409
410
411
  cfg_.rc_min_quantizer = 0;
  cfg_.rc_max_quantizer = 63;
  cfg_.rc_end_usage = VPX_CBR;
412
  cfg_.g_lag_in_frames = 0;
Marco Paniconi's avatar
Marco Paniconi committed
413
414
415

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 140);
Marco Paniconi's avatar
Marco Paniconi committed
416
  for (int i = 150; i < 800; i += 200) {
Marco Paniconi's avatar
Marco Paniconi committed
417
418
419
    cfg_.rc_target_bitrate = i;
    ResetModel();
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
420
421
422
423
    ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
        << " The datarate for the file is lower than target by too much!";
    ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
        << " The datarate for the file is greater than target by too much!";
Marco Paniconi's avatar
Marco Paniconi committed
424
425
  }
}
426

427
// Check basic rate targeting,
428
TEST_P(DatarateTestVP9Large, BasicRateTargeting444) {
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  ::libvpx_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 140);

  cfg_.g_profile = 1;
  cfg_.g_timebase = video.timebase();

  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 500;
  cfg_.rc_buf_sz = 1000;
  cfg_.rc_dropframe_thresh = 1;
  cfg_.rc_min_quantizer = 0;
  cfg_.rc_max_quantizer = 63;
  cfg_.rc_end_usage = VPX_CBR;

  for (int i = 250; i < 900; i += 200) {
    cfg_.rc_target_bitrate = i;
    ResetModel();
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
    ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate),
447
              effective_datarate_[0] * 0.85)
448
449
        << " The datarate for the file exceeds the target by too much!";
    ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate),
450
              effective_datarate_[0] * 1.15)
451
452
453
454
455
        << " The datarate for the file missed the target!"
        << cfg_.rc_target_bitrate << " "<< effective_datarate_;
  }
}

456
457
458
459
// Check that (1) the first dropped frame gets earlier and earlier
// as the drop frame threshold is increased, and (2) that the total number of
// frame drops does not decrease as we increase frame drop threshold.
// Use a lower qp-max to force some frame drops.
460
TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) {
461
462
463
464
465
466
467
468
469
470
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 500;
  cfg_.rc_buf_sz = 1000;
  cfg_.rc_undershoot_pct = 20;
  cfg_.rc_undershoot_pct = 20;
  cfg_.rc_dropframe_thresh = 10;
  cfg_.rc_min_quantizer = 0;
  cfg_.rc_max_quantizer = 50;
  cfg_.rc_end_usage = VPX_CBR;
  cfg_.rc_target_bitrate = 200;
471
  cfg_.g_lag_in_frames = 0;
472
473
474
475
476

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 140);

  const int kDropFrameThreshTestStep = 30;
477
  vpx_codec_pts_t last_drop = 140;
478
479
480
481
482
  int last_num_drops = 0;
  for (int i = 10; i < 100; i += kDropFrameThreshTestStep) {
    cfg_.rc_dropframe_thresh = i;
    ResetModel();
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
483
484
485
486
    ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
        << " The datarate for the file is lower than target by too much!";
    ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
        << " The datarate for the file is greater than target by too much!";
487
488
489
490
491
492
493
494
495
496
497
498
499
    ASSERT_LE(first_drop_, last_drop)
        << " The first dropped frame for drop_thresh " << i
        << " > first dropped frame for drop_thresh "
        << i - kDropFrameThreshTestStep;
    ASSERT_GE(num_drops_, last_num_drops)
        << " The number of dropped frames for drop_thresh " << i
        << " < number of dropped frames for drop_thresh "
        << i - kDropFrameThreshTestStep;
    last_drop = first_drop_;
    last_num_drops = num_drops_;
  }
}

500
// Check basic rate targeting for 2 temporal layers.
501
TEST_P(DatarateTestVP9Large, BasicRateTargeting2TemporalLayers) {
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 500;
  cfg_.rc_buf_sz = 1000;
  cfg_.rc_dropframe_thresh = 1;
  cfg_.rc_min_quantizer = 0;
  cfg_.rc_max_quantizer = 63;
  cfg_.rc_end_usage = VPX_CBR;
  cfg_.g_lag_in_frames = 0;

  // 2 Temporal layers, no spatial layers: Framerate decimation (2, 1).
  cfg_.ss_number_layers = 1;
  cfg_.ts_number_layers = 2;
  cfg_.ts_rate_decimator[0] = 2;
  cfg_.ts_rate_decimator[1] = 1;

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 200);
  for (int i = 200; i <= 800; i += 200) {
    cfg_.rc_target_bitrate = i;
    ResetModel();
    // 60-40 bitrate allocation for 2 temporal layers.
    cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
    cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
    for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
      ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
          << " The datarate for the file is lower than target by too much, "
              "for layer: " << j;
      ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
          << " The datarate for the file is greater than target by too much, "
              "for layer: " << j;
    }
  }
}

// Check basic rate targeting for 3 temporal layers.
538
TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayers) {
539
540
541
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 500;
  cfg_.rc_buf_sz = 1000;
542
  cfg_.rc_dropframe_thresh = 1;
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  cfg_.rc_min_quantizer = 0;
  cfg_.rc_max_quantizer = 63;
  cfg_.rc_end_usage = VPX_CBR;
  cfg_.g_lag_in_frames = 0;

  // 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
  cfg_.ss_number_layers = 1;
  cfg_.ts_number_layers = 3;
  cfg_.ts_rate_decimator[0] = 4;
  cfg_.ts_rate_decimator[1] = 2;
  cfg_.ts_rate_decimator[2] = 1;

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 200);
  for (int i = 200; i <= 800; i += 200) {
    cfg_.rc_target_bitrate = i;
    ResetModel();
    // 40-20-40 bitrate allocation for 3 temporal layers.
    cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
    cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
    cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
    for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
Yaowu Xu's avatar
Yaowu Xu committed
566
567
568
      // TODO(yaowu): Work out more stable rc control strategy and
      //              Adjust the thresholds to be tighter than .75.
      ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75)
569
570
          << " The datarate for the file is lower than target by too much, "
              "for layer: " << j;
Yaowu Xu's avatar
Yaowu Xu committed
571
572
573
      // TODO(yaowu): Work out more stable rc control strategy and
      //              Adjust the thresholds to be tighter than 1.25.
      ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25)
574
575
576
577
578
          << " The datarate for the file is greater than target by too much, "
              "for layer: " << j;
    }
  }
}
579
580
581
582

// Check basic rate targeting for 3 temporal layers, with frame dropping.
// Only for one (low) bitrate with lower max_quantizer, and somewhat higher
// frame drop threshold, to force frame dropping.
583
TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayersFrameDropping) {
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 500;
  cfg_.rc_buf_sz = 1000;
  // Set frame drop threshold and rc_max_quantizer to force some frame drops.
  cfg_.rc_dropframe_thresh = 20;
  cfg_.rc_max_quantizer = 45;
  cfg_.rc_min_quantizer = 0;
  cfg_.rc_end_usage = VPX_CBR;
  cfg_.g_lag_in_frames = 0;

  // 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
  cfg_.ss_number_layers = 1;
  cfg_.ts_number_layers = 3;
  cfg_.ts_rate_decimator[0] = 4;
  cfg_.ts_rate_decimator[1] = 2;
  cfg_.ts_rate_decimator[2] = 1;

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 200);
  cfg_.rc_target_bitrate = 200;
  ResetModel();
  // 40-20-40 bitrate allocation for 3 temporal layers.
  cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
  cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
  cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
  for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
    ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
        << " The datarate for the file is lower than target by too much, "
            "for layer: " << j;
    ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
        << " The datarate for the file is greater than target by too much, "
            "for layer: " << j;
    // Expect some frame drops in this test: for this 200 frames test,
618
    // expect at least 10% and not more than 60% drops.
619
    ASSERT_GE(num_drops_, 20);
620
    ASSERT_LE(num_drops_, 130);
621
622
623
  }
}

JackyChen's avatar
JackyChen committed
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
#if CONFIG_VP9_TEMPORAL_DENOISING
// Check basic datarate targeting, for a single bitrate, when denoiser is on.
TEST_P(DatarateTestVP9Large, DenoiserLevels) {
  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 500;
  cfg_.rc_buf_sz = 1000;
  cfg_.rc_dropframe_thresh = 1;
  cfg_.rc_min_quantizer = 2;
  cfg_.rc_max_quantizer = 56;
  cfg_.rc_end_usage = VPX_CBR;
  cfg_.g_lag_in_frames = 0;

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 140);

  // For the temporal denoiser (#if CONFIG_VP9_TEMPORAL_DENOISING),
  // there is only one denoiser mode: denoiserYonly(which is 1),
  // but may add more modes in the future.
  cfg_.rc_target_bitrate = 300;
  ResetModel();
  // Turn on the denoiser.
  denoiser_on_ = 1;
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
  ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
      << " The datarate for the file is lower than target by too much!";
  ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
      << " The datarate for the file is greater than target by too much!";
}
652
#endif  // CONFIG_VP9_TEMPORAL_DENOISING
JackyChen's avatar
JackyChen committed
653

654
VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES);
655
// TODO(jingning) Add kRealTime back.
656
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large,
657
                          ::testing::Values(::libvpx_test::kOnePassGood),
658
                          ::testing::Range(2, 7));
659
}  // namespace