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