• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "third_party/googletest/src/include/gtest/gtest.h"
12 #include "test/codec_factory.h"
13 #include "test/encode_test_driver.h"
14 #include "test/i420_video_source.h"
15 #include "test/util.h"
16 
17 namespace {
18 
19 const int kMaxErrorFrames = 12;
20 const int kMaxDroppableFrames = 12;
21 
22 class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
23     public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, bool> {
24  protected:
ErrorResilienceTestLarge()25   ErrorResilienceTestLarge()
26       : EncoderTest(GET_PARAM(0)),
27         svc_support_(GET_PARAM(2)),
28         psnr_(0.0),
29         nframes_(0),
30         mismatch_psnr_(0.0),
31         mismatch_nframes_(0),
32         encoding_mode_(GET_PARAM(1)) {
33     Reset();
34   }
35 
~ErrorResilienceTestLarge()36   virtual ~ErrorResilienceTestLarge() {}
37 
Reset()38   void Reset() {
39     error_nframes_ = 0;
40     droppable_nframes_ = 0;
41     pattern_switch_ = 0;
42   }
43 
SetUp()44   virtual void SetUp() {
45     InitializeConfig();
46     SetMode(encoding_mode_);
47   }
48 
BeginPassHook(unsigned int)49   virtual void BeginPassHook(unsigned int /*pass*/) {
50     psnr_ = 0.0;
51     nframes_ = 0;
52     mismatch_psnr_ = 0.0;
53     mismatch_nframes_ = 0;
54   }
55 
PSNRPktHook(const vpx_codec_cx_pkt_t * pkt)56   virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
57     psnr_ += pkt->data.psnr.psnr[0];
58     nframes_++;
59   }
60 
61   //
62   // Frame flags and layer id for temporal layers.
63   // For two layers, test pattern is:
64   //   1     3
65   // 0    2     .....
66   // LAST is updated on base/layer 0, GOLDEN  updated on layer 1.
67   // Non-zero pattern_switch parameter means pattern will switch to
68   // not using LAST for frame_num >= pattern_switch.
SetFrameFlags(int frame_num,int num_temp_layers,int pattern_switch)69   int SetFrameFlags(int frame_num,
70                     int num_temp_layers,
71                     int pattern_switch) {
72     int frame_flags = 0;
73     if (num_temp_layers == 2) {
74         if (frame_num % 2 == 0) {
75           if (frame_num < pattern_switch || pattern_switch == 0) {
76             // Layer 0: predict from LAST and ARF, update LAST.
77             frame_flags = VP8_EFLAG_NO_REF_GF |
78                           VP8_EFLAG_NO_UPD_GF |
79                           VP8_EFLAG_NO_UPD_ARF;
80           } else {
81             // Layer 0: predict from GF and ARF, update GF.
82             frame_flags = VP8_EFLAG_NO_REF_LAST |
83                           VP8_EFLAG_NO_UPD_LAST |
84                           VP8_EFLAG_NO_UPD_ARF;
85           }
86         } else {
87           if (frame_num < pattern_switch || pattern_switch == 0) {
88             // Layer 1: predict from L, GF, and ARF, update GF.
89             frame_flags = VP8_EFLAG_NO_UPD_ARF |
90                           VP8_EFLAG_NO_UPD_LAST;
91           } else {
92             // Layer 1: predict from GF and ARF, update GF.
93             frame_flags = VP8_EFLAG_NO_REF_LAST |
94                           VP8_EFLAG_NO_UPD_LAST |
95                           VP8_EFLAG_NO_UPD_ARF;
96           }
97         }
98     }
99     return frame_flags;
100   }
101 
PreEncodeFrameHook(libvpx_test::VideoSource * video,::libvpx_test::Encoder * encoder)102   virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
103                                   ::libvpx_test::Encoder *encoder) {
104     frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST |
105                       VP8_EFLAG_NO_UPD_GF |
106                       VP8_EFLAG_NO_UPD_ARF);
107     // For temporal layer case.
108     if (cfg_.ts_number_layers > 1) {
109       frame_flags_ = SetFrameFlags(video->frame(),
110                                    cfg_.ts_number_layers,
111                                    pattern_switch_);
112       for (unsigned int i = 0; i < droppable_nframes_; ++i) {
113         if (droppable_frames_[i] == video->frame()) {
114           std::cout << "Encoding droppable frame: "
115                     << droppable_frames_[i] << "\n";
116         }
117       }
118     } else {
119        if (droppable_nframes_ > 0 &&
120          (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) {
121          for (unsigned int i = 0; i < droppable_nframes_; ++i) {
122            if (droppable_frames_[i] == video->frame()) {
123              std::cout << "Encoding droppable frame: "
124                        << droppable_frames_[i] << "\n";
125              frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST |
126                               VP8_EFLAG_NO_UPD_GF |
127                               VP8_EFLAG_NO_UPD_ARF);
128              return;
129            }
130          }
131        }
132     }
133   }
134 
GetAveragePsnr() const135   double GetAveragePsnr() const {
136     if (nframes_)
137       return psnr_ / nframes_;
138     return 0.0;
139   }
140 
GetAverageMismatchPsnr() const141   double GetAverageMismatchPsnr() const {
142     if (mismatch_nframes_)
143       return mismatch_psnr_ / mismatch_nframes_;
144     return 0.0;
145   }
146 
DoDecode() const147   virtual bool DoDecode() const {
148     if (error_nframes_ > 0 &&
149         (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) {
150       for (unsigned int i = 0; i < error_nframes_; ++i) {
151         if (error_frames_[i] == nframes_ - 1) {
152           std::cout << "             Skipping decoding frame: "
153                     << error_frames_[i] << "\n";
154           return 0;
155         }
156       }
157     }
158     return 1;
159   }
160 
MismatchHook(const vpx_image_t * img1,const vpx_image_t * img2)161   virtual void MismatchHook(const vpx_image_t *img1,
162                             const vpx_image_t *img2) {
163     double mismatch_psnr = compute_psnr(img1, img2);
164     mismatch_psnr_ += mismatch_psnr;
165     ++mismatch_nframes_;
166     // std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n";
167   }
168 
SetErrorFrames(int num,unsigned int * list)169   void SetErrorFrames(int num, unsigned int *list) {
170     if (num > kMaxErrorFrames)
171       num = kMaxErrorFrames;
172     else if (num < 0)
173       num = 0;
174     error_nframes_ = num;
175     for (unsigned int i = 0; i < error_nframes_; ++i)
176       error_frames_[i] = list[i];
177   }
178 
SetDroppableFrames(int num,unsigned int * list)179   void SetDroppableFrames(int num, unsigned int *list) {
180     if (num > kMaxDroppableFrames)
181       num = kMaxDroppableFrames;
182     else if (num < 0)
183       num = 0;
184     droppable_nframes_ = num;
185     for (unsigned int i = 0; i < droppable_nframes_; ++i)
186       droppable_frames_[i] = list[i];
187   }
188 
GetMismatchFrames()189   unsigned int GetMismatchFrames() {
190     return mismatch_nframes_;
191   }
192 
SetPatternSwitch(int frame_switch)193   void SetPatternSwitch(int frame_switch) {
194      pattern_switch_ = frame_switch;
195    }
196 
197   bool svc_support_;
198 
199  private:
200   double psnr_;
201   unsigned int nframes_;
202   unsigned int error_nframes_;
203   unsigned int droppable_nframes_;
204   unsigned int pattern_switch_;
205   double mismatch_psnr_;
206   unsigned int mismatch_nframes_;
207   unsigned int error_frames_[kMaxErrorFrames];
208   unsigned int droppable_frames_[kMaxDroppableFrames];
209   libvpx_test::TestMode encoding_mode_;
210 };
211 
TEST_P(ErrorResilienceTestLarge,OnVersusOff)212 TEST_P(ErrorResilienceTestLarge, OnVersusOff) {
213   const vpx_rational timebase = { 33333333, 1000000000 };
214   cfg_.g_timebase = timebase;
215   cfg_.rc_target_bitrate = 2000;
216   cfg_.g_lag_in_frames = 10;
217 
218   init_flags_ = VPX_CODEC_USE_PSNR;
219 
220   libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
221                                      timebase.den, timebase.num, 0, 30);
222 
223   // Error resilient mode OFF.
224   cfg_.g_error_resilient = 0;
225   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
226   const double psnr_resilience_off = GetAveragePsnr();
227   EXPECT_GT(psnr_resilience_off, 25.0);
228 
229   // Error resilient mode ON.
230   cfg_.g_error_resilient = 1;
231   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
232   const double psnr_resilience_on = GetAveragePsnr();
233   EXPECT_GT(psnr_resilience_on, 25.0);
234 
235   // Test that turning on error resilient mode hurts by 10% at most.
236   if (psnr_resilience_off > 0.0) {
237     const double psnr_ratio = psnr_resilience_on / psnr_resilience_off;
238     EXPECT_GE(psnr_ratio, 0.9);
239     EXPECT_LE(psnr_ratio, 1.1);
240   }
241 }
242 
243 // Check for successful decoding and no encoder/decoder mismatch
244 // if we lose (i.e., drop before decoding) a set of droppable
245 // frames (i.e., frames that don't update any reference buffers).
246 // Check both isolated and consecutive loss.
TEST_P(ErrorResilienceTestLarge,DropFramesWithoutRecovery)247 TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) {
248   const vpx_rational timebase = { 33333333, 1000000000 };
249   cfg_.g_timebase = timebase;
250   cfg_.rc_target_bitrate = 500;
251   // FIXME(debargha): Fix this to work for any lag.
252   // Currently this test only works for lag = 0
253   cfg_.g_lag_in_frames = 0;
254 
255   init_flags_ = VPX_CODEC_USE_PSNR;
256 
257   libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
258                                      timebase.den, timebase.num, 0, 40);
259 
260   // Error resilient mode ON.
261   cfg_.g_error_resilient = 1;
262   cfg_.kf_mode = VPX_KF_DISABLED;
263 
264   // Set an arbitrary set of error frames same as droppable frames.
265   // In addition to isolated loss/drop, add a long consecutive series
266   // (of size 9) of dropped frames.
267   unsigned int num_droppable_frames = 11;
268   unsigned int droppable_frame_list[] = {5, 16, 22, 23, 24, 25, 26, 27, 28,
269                                          29, 30};
270   SetDroppableFrames(num_droppable_frames, droppable_frame_list);
271   SetErrorFrames(num_droppable_frames, droppable_frame_list);
272   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
273   // Test that no mismatches have been found
274   std::cout << "             Mismatch frames: "
275             << GetMismatchFrames() << "\n";
276   EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
277 
278   // Reset previously set of error/droppable frames.
279   Reset();
280 
281 #if 0
282   // TODO(jkoleszar): This test is disabled for the time being as too
283   // sensitive. It's not clear how to set a reasonable threshold for
284   // this behavior.
285 
286   // Now set an arbitrary set of error frames that are non-droppable
287   unsigned int num_error_frames = 3;
288   unsigned int error_frame_list[] = {3, 10, 20};
289   SetErrorFrames(num_error_frames, error_frame_list);
290   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
291 
292   // Test that dropping an arbitrary set of inter frames does not hurt too much
293   // Note the Average Mismatch PSNR is the average of the PSNR between
294   // decoded frame and encoder's version of the same frame for all frames
295   // with mismatch.
296   const double psnr_resilience_mismatch = GetAverageMismatchPsnr();
297   std::cout << "             Mismatch PSNR: "
298             << psnr_resilience_mismatch << "\n";
299   EXPECT_GT(psnr_resilience_mismatch, 20.0);
300 #endif
301 }
302 
303 // Check for successful decoding and no encoder/decoder mismatch
304 // if we lose (i.e., drop before decoding) the enhancement layer frames for a
305 // two layer temporal pattern. The base layer does not predict from the top
306 // layer, so successful decoding is expected.
307 TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) {
308   // This test doesn't run if SVC is not supported.
309   if (!svc_support_)
310     return;
311 
312   const vpx_rational timebase = { 33333333, 1000000000 };
313   cfg_.g_timebase = timebase;
314   cfg_.rc_target_bitrate = 500;
315   cfg_.g_lag_in_frames = 0;
316 
317   cfg_.rc_end_usage = VPX_CBR;
318   // 2 Temporal layers, no spatial layers, CBR mode.
319   cfg_.ss_number_layers = 1;
320   cfg_.ts_number_layers = 2;
321   cfg_.ts_rate_decimator[0] = 2;
322   cfg_.ts_rate_decimator[1] = 1;
323   cfg_.ts_periodicity = 2;
324   cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
325   cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
326 
327   init_flags_ = VPX_CODEC_USE_PSNR;
328 
329   libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
330                                      timebase.den, timebase.num, 0, 40);
331 
332   // Error resilient mode ON.
333   cfg_.g_error_resilient = 1;
334   cfg_.kf_mode = VPX_KF_DISABLED;
335   SetPatternSwitch(0);
336 
337   // The odd frames are the enhancement layer for 2 layer pattern, so set
338   // those frames as droppable. Drop the last 7 frames.
339   unsigned int num_droppable_frames = 7;
340   unsigned int droppable_frame_list[] = {27, 29, 31, 33, 35, 37, 39};
341   SetDroppableFrames(num_droppable_frames, droppable_frame_list);
342   SetErrorFrames(num_droppable_frames, droppable_frame_list);
343   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
344   // Test that no mismatches have been found
345   std::cout << "             Mismatch frames: "
346             << GetMismatchFrames() << "\n";
347   EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
348 
349   // Reset previously set of error/droppable frames.
350   Reset();
351 }
352 
353 // Check for successful decoding and no encoder/decoder mismatch
354 // for a two layer temporal pattern, where at some point in the
355 // sequence, the LAST ref is not used anymore.
356 TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) {
357   // This test doesn't run if SVC is not supported.
358   if (!svc_support_)
359     return;
360 
361   const vpx_rational timebase = { 33333333, 1000000000 };
362   cfg_.g_timebase = timebase;
363   cfg_.rc_target_bitrate = 500;
364   cfg_.g_lag_in_frames = 0;
365 
366   cfg_.rc_end_usage = VPX_CBR;
367   // 2 Temporal layers, no spatial layers, CBR mode.
368   cfg_.ss_number_layers = 1;
369   cfg_.ts_number_layers = 2;
370   cfg_.ts_rate_decimator[0] = 2;
371   cfg_.ts_rate_decimator[1] = 1;
372   cfg_.ts_periodicity = 2;
373   cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
374   cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
375 
376   init_flags_ = VPX_CODEC_USE_PSNR;
377 
378   libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
379                                      timebase.den, timebase.num, 0, 100);
380 
381   // Error resilient mode ON.
382   cfg_.g_error_resilient = 1;
383   cfg_.kf_mode = VPX_KF_DISABLED;
384   SetPatternSwitch(60);
385 
386   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
387   // Test that no mismatches have been found
388   std::cout << "             Mismatch frames: "
389             << GetMismatchFrames() << "\n";
390   EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
391 
392   // Reset previously set of error/droppable frames.
393   Reset();
394 }
395 
396 class ErrorResilienceTestLargeCodecControls : public ::libvpx_test::EncoderTest,
397     public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
398  protected:
ErrorResilienceTestLargeCodecControls()399   ErrorResilienceTestLargeCodecControls()
400       : EncoderTest(GET_PARAM(0)),
401         encoding_mode_(GET_PARAM(1)) {
402     Reset();
403   }
404 
~ErrorResilienceTestLargeCodecControls()405   virtual ~ErrorResilienceTestLargeCodecControls() {}
406 
Reset()407   void Reset() {
408     last_pts_ = 0;
409     tot_frame_number_ = 0;
410     // For testing up to 3 layers.
411     for (int i = 0; i < 3; ++i) {
412       bits_total_[i] = 0;
413     }
414     duration_ = 0.0;
415   }
416 
SetUp()417   virtual void SetUp() {
418     InitializeConfig();
419     SetMode(encoding_mode_);
420   }
421 
422   //
423   // Frame flags and layer id for temporal layers.
424   //
425 
426   // For two layers, test pattern is:
427   //   1     3
428   // 0    2     .....
429   // For three layers, test pattern is:
430   //   1      3    5      7
431   //      2           6
432   // 0          4            ....
433   // LAST is always update on base/layer 0, GOLDEN is updated on layer 1,
434   // and ALTREF is updated on top layer for 3 layer pattern.
SetFrameFlags(int frame_num,int num_temp_layers)435   int SetFrameFlags(int frame_num, int num_temp_layers) {
436     int frame_flags = 0;
437     if (num_temp_layers == 2) {
438       if (frame_num % 2 == 0) {
439         // Layer 0: predict from L and ARF, update L.
440         frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
441                       VP8_EFLAG_NO_UPD_ARF;
442       } else {
443         // Layer 1: predict from L, G and ARF, and update G.
444         frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
445                       VP8_EFLAG_NO_UPD_ENTROPY;
446       }
447     } else if (num_temp_layers == 3) {
448       if (frame_num % 4 == 0) {
449         // Layer 0: predict from L, update L.
450         frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
451                       VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
452       } else if ((frame_num - 2) % 4 == 0) {
453         // Layer 1: predict from L, G,  update G.
454         frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
455                       VP8_EFLAG_NO_REF_ARF;
456       }  else if ((frame_num - 1) % 2 == 0) {
457         // Layer 2: predict from L, G, ARF; update ARG.
458         frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
459       }
460     }
461     return frame_flags;
462   }
463 
SetLayerId(int frame_num,int num_temp_layers)464   int SetLayerId(int frame_num, int num_temp_layers) {
465     int layer_id = 0;
466     if (num_temp_layers == 2) {
467       if (frame_num % 2 == 0) {
468         layer_id = 0;
469       } else {
470          layer_id = 1;
471       }
472     } else if (num_temp_layers == 3) {
473       if (frame_num % 4 == 0) {
474         layer_id = 0;
475       } else if ((frame_num - 2) % 4 == 0) {
476         layer_id = 1;
477       } else if ((frame_num - 1) % 2 == 0) {
478         layer_id = 2;
479       }
480     }
481     return layer_id;
482   }
483 
PreEncodeFrameHook(libvpx_test::VideoSource * video,libvpx_test::Encoder * encoder)484   virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
485                                   libvpx_test::Encoder *encoder) {
486     if (cfg_.ts_number_layers > 1) {
487         int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers);
488         int frame_flags = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
489         if (video->frame() > 0) {
490           encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
491           encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags);
492         }
493        const vpx_rational_t tb = video->timebase();
494        timebase_ = static_cast<double>(tb.num) / tb.den;
495        duration_ = 0;
496        return;
497     }
498   }
499 
FramePktHook(const vpx_codec_cx_pkt_t * pkt)500   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
501     // Time since last timestamp = duration.
502     vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
503     if (duration > 1) {
504       // Update counter for total number of frames (#frames input to encoder).
505       // Needed for setting the proper layer_id below.
506       tot_frame_number_ += static_cast<int>(duration - 1);
507     }
508     int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers);
509     const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
510     // Update the total encoded bits. For temporal layers, update the cumulative
511     // encoded bits per layer.
512     for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) {
513       bits_total_[i] += frame_size_in_bits;
514     }
515     // Update the most recent pts.
516     last_pts_ = pkt->data.frame.pts;
517     ++tot_frame_number_;
518   }
519 
EndPassHook(void)520   virtual void EndPassHook(void) {
521     duration_ = (last_pts_ + 1) * timebase_;
522     if (cfg_.ts_number_layers  > 1) {
523       for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
524           ++layer) {
525         if (bits_total_[layer]) {
526           // Effective file datarate:
527           effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
528         }
529       }
530     }
531   }
532 
533   double effective_datarate_[3];
534    private:
535     libvpx_test::TestMode encoding_mode_;
536     vpx_codec_pts_t last_pts_;
537     double timebase_;
538     int64_t bits_total_[3];
539     double duration_;
540     int tot_frame_number_;
541   };
542 
543 // Check two codec controls used for:
544 // (1) for setting temporal layer id, and (2) for settings encoder flags.
545 // This test invokes those controls for each frame, and verifies encoder/decoder
546 // mismatch and basic rate control response.
547 // TODO(marpan): Maybe move this test to datarate_test.cc.
TEST_P(ErrorResilienceTestLargeCodecControls,CodecControl3TemporalLayers)548 TEST_P(ErrorResilienceTestLargeCodecControls, CodecControl3TemporalLayers) {
549   cfg_.rc_buf_initial_sz = 500;
550   cfg_.rc_buf_optimal_sz = 500;
551   cfg_.rc_buf_sz = 1000;
552   cfg_.rc_dropframe_thresh = 1;
553   cfg_.rc_min_quantizer = 2;
554   cfg_.rc_max_quantizer = 56;
555   cfg_.rc_end_usage = VPX_CBR;
556   cfg_.rc_dropframe_thresh = 1;
557   cfg_.g_lag_in_frames = 0;
558   cfg_.kf_mode = VPX_KF_DISABLED;
559   cfg_.g_error_resilient = 1;
560 
561   // 3 Temporal layers. Framerate decimation (4, 2, 1).
562   cfg_.ts_number_layers = 3;
563   cfg_.ts_rate_decimator[0] = 4;
564   cfg_.ts_rate_decimator[1] = 2;
565   cfg_.ts_rate_decimator[2] = 1;
566   cfg_.ts_periodicity = 4;
567   cfg_.ts_layer_id[0] = 0;
568   cfg_.ts_layer_id[1] = 2;
569   cfg_.ts_layer_id[2] = 1;
570   cfg_.ts_layer_id[3] = 2;
571 
572   ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
573                                        30, 1, 0, 200);
574   for (int i = 200; i <= 800; i += 200) {
575     cfg_.rc_target_bitrate = i;
576     Reset();
577     // 40-20-40 bitrate allocation for 3 temporal layers.
578     cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
579     cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
580     cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
581     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
582     for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
583       ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75)
584           << " The datarate for the file is lower than target by too much, "
585               "for layer: " << j;
586       ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25)
587           << " The datarate for the file is greater than target by too much, "
588               "for layer: " << j;
589     }
590   }
591 }
592 
593 VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES,
594                           ::testing::Values(true));
595 VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLargeCodecControls,
596                           ONE_PASS_TEST_MODES);
597 VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES,
598                           ::testing::Values(true));
599 // SVC-related tests don't run for VP10 since SVC is not supported.
600 VP10_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES,
601                            ::testing::Values(false));
602 }  // namespace
603