xref: /aosp_15_r20/external/libaom/test/error_resilience_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker #include "gtest/gtest.h"
13*77c1e3ccSAndroid Build Coastguard Worker #include "test/codec_factory.h"
14*77c1e3ccSAndroid Build Coastguard Worker #include "test/encode_test_driver.h"
15*77c1e3ccSAndroid Build Coastguard Worker #include "test/i420_video_source.h"
16*77c1e3ccSAndroid Build Coastguard Worker #include "test/util.h"
17*77c1e3ccSAndroid Build Coastguard Worker 
18*77c1e3ccSAndroid Build Coastguard Worker namespace {
19*77c1e3ccSAndroid Build Coastguard Worker 
20*77c1e3ccSAndroid Build Coastguard Worker const int kMaxErrorFrames = 12;
21*77c1e3ccSAndroid Build Coastguard Worker const int kMaxInvisibleErrorFrames = 12;
22*77c1e3ccSAndroid Build Coastguard Worker const int kMaxDroppableFrames = 12;
23*77c1e3ccSAndroid Build Coastguard Worker const int kMaxErrorResilientFrames = 12;
24*77c1e3ccSAndroid Build Coastguard Worker const int kMaxNoMFMVFrames = 12;
25*77c1e3ccSAndroid Build Coastguard Worker const int kMaxPrimRefNoneFrames = 12;
26*77c1e3ccSAndroid Build Coastguard Worker const int kMaxSFrames = 12;
27*77c1e3ccSAndroid Build Coastguard Worker const int kCpuUsed = 1;
28*77c1e3ccSAndroid Build Coastguard Worker 
29*77c1e3ccSAndroid Build Coastguard Worker class ErrorResilienceTestLarge
30*77c1e3ccSAndroid Build Coastguard Worker     : public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
31*77c1e3ccSAndroid Build Coastguard Worker       public ::libaom_test::EncoderTest {
32*77c1e3ccSAndroid Build Coastguard Worker  protected:
ErrorResilienceTestLarge()33*77c1e3ccSAndroid Build Coastguard Worker   ErrorResilienceTestLarge()
34*77c1e3ccSAndroid Build Coastguard Worker       : EncoderTest(GET_PARAM(0)), psnr_(0.0), nframes_(0), mismatch_psnr_(0.0),
35*77c1e3ccSAndroid Build Coastguard Worker         mismatch_nframes_(0), encoding_mode_(GET_PARAM(1)), allow_mismatch_(0),
36*77c1e3ccSAndroid Build Coastguard Worker         enable_altref_(GET_PARAM(2)) {
37*77c1e3ccSAndroid Build Coastguard Worker     Reset();
38*77c1e3ccSAndroid Build Coastguard Worker   }
39*77c1e3ccSAndroid Build Coastguard Worker 
40*77c1e3ccSAndroid Build Coastguard Worker   ~ErrorResilienceTestLarge() override = default;
41*77c1e3ccSAndroid Build Coastguard Worker 
Reset()42*77c1e3ccSAndroid Build Coastguard Worker   void Reset() {
43*77c1e3ccSAndroid Build Coastguard Worker     error_nframes_ = 0;
44*77c1e3ccSAndroid Build Coastguard Worker     invisible_error_nframes_ = 0;
45*77c1e3ccSAndroid Build Coastguard Worker     droppable_nframes_ = 0;
46*77c1e3ccSAndroid Build Coastguard Worker     error_resilient_nframes_ = 0;
47*77c1e3ccSAndroid Build Coastguard Worker     nomfmv_nframes_ = 0;
48*77c1e3ccSAndroid Build Coastguard Worker     prim_ref_none_nframes_ = 0;
49*77c1e3ccSAndroid Build Coastguard Worker     s_nframes_ = 0;
50*77c1e3ccSAndroid Build Coastguard Worker   }
51*77c1e3ccSAndroid Build Coastguard Worker 
SetupEncoder(int bitrate,int lag)52*77c1e3ccSAndroid Build Coastguard Worker   void SetupEncoder(int bitrate, int lag) {
53*77c1e3ccSAndroid Build Coastguard Worker     const aom_rational timebase = { 33333333, 1000000000 };
54*77c1e3ccSAndroid Build Coastguard Worker     cfg_.g_timebase = timebase;
55*77c1e3ccSAndroid Build Coastguard Worker     cfg_.rc_target_bitrate = bitrate;
56*77c1e3ccSAndroid Build Coastguard Worker     cfg_.kf_mode = AOM_KF_DISABLED;
57*77c1e3ccSAndroid Build Coastguard Worker     cfg_.g_lag_in_frames = lag;
58*77c1e3ccSAndroid Build Coastguard Worker     init_flags_ = AOM_CODEC_USE_PSNR;
59*77c1e3ccSAndroid Build Coastguard Worker   }
60*77c1e3ccSAndroid Build Coastguard Worker 
SetUp()61*77c1e3ccSAndroid Build Coastguard Worker   void SetUp() override { InitializeConfig(encoding_mode_); }
62*77c1e3ccSAndroid Build Coastguard Worker 
BeginPassHook(unsigned int)63*77c1e3ccSAndroid Build Coastguard Worker   void BeginPassHook(unsigned int /*pass*/) override {
64*77c1e3ccSAndroid Build Coastguard Worker     psnr_ = 0.0;
65*77c1e3ccSAndroid Build Coastguard Worker     nframes_ = 0;
66*77c1e3ccSAndroid Build Coastguard Worker     decoded_nframes_ = 0;
67*77c1e3ccSAndroid Build Coastguard Worker     mismatch_psnr_ = 0.0;
68*77c1e3ccSAndroid Build Coastguard Worker     mismatch_nframes_ = 0;
69*77c1e3ccSAndroid Build Coastguard Worker   }
70*77c1e3ccSAndroid Build Coastguard Worker 
PSNRPktHook(const aom_codec_cx_pkt_t * pkt)71*77c1e3ccSAndroid Build Coastguard Worker   void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) override {
72*77c1e3ccSAndroid Build Coastguard Worker     psnr_ += pkt->data.psnr.psnr[0];
73*77c1e3ccSAndroid Build Coastguard Worker     nframes_++;
74*77c1e3ccSAndroid Build Coastguard Worker   }
75*77c1e3ccSAndroid Build Coastguard Worker 
PreEncodeFrameHook(libaom_test::VideoSource * video,libaom_test::Encoder * encoder)76*77c1e3ccSAndroid Build Coastguard Worker   void PreEncodeFrameHook(libaom_test::VideoSource *video,
77*77c1e3ccSAndroid Build Coastguard Worker                           libaom_test::Encoder *encoder) override {
78*77c1e3ccSAndroid Build Coastguard Worker     if (video->frame() == 0) {
79*77c1e3ccSAndroid Build Coastguard Worker       encoder->Control(AOME_SET_CPUUSED, kCpuUsed);
80*77c1e3ccSAndroid Build Coastguard Worker       encoder->Control(AOME_SET_ENABLEAUTOALTREF, enable_altref_);
81*77c1e3ccSAndroid Build Coastguard Worker     }
82*77c1e3ccSAndroid Build Coastguard Worker     frame_flags_ &=
83*77c1e3ccSAndroid Build Coastguard Worker         ~(AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF |
84*77c1e3ccSAndroid Build Coastguard Worker           AOM_EFLAG_NO_REF_FRAME_MVS | AOM_EFLAG_ERROR_RESILIENT |
85*77c1e3ccSAndroid Build Coastguard Worker           AOM_EFLAG_SET_S_FRAME | AOM_EFLAG_SET_PRIMARY_REF_NONE);
86*77c1e3ccSAndroid Build Coastguard Worker     if (droppable_nframes_ > 0 &&
87*77c1e3ccSAndroid Build Coastguard Worker         (cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
88*77c1e3ccSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < droppable_nframes_; ++i) {
89*77c1e3ccSAndroid Build Coastguard Worker         if (droppable_frames_[i] == video->frame()) {
90*77c1e3ccSAndroid Build Coastguard Worker           std::cout << "             Encoding droppable frame: "
91*77c1e3ccSAndroid Build Coastguard Worker                     << droppable_frames_[i] << "\n";
92*77c1e3ccSAndroid Build Coastguard Worker           frame_flags_ |= (AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
93*77c1e3ccSAndroid Build Coastguard Worker                            AOM_EFLAG_NO_UPD_ARF);
94*77c1e3ccSAndroid Build Coastguard Worker           break;
95*77c1e3ccSAndroid Build Coastguard Worker         }
96*77c1e3ccSAndroid Build Coastguard Worker       }
97*77c1e3ccSAndroid Build Coastguard Worker     }
98*77c1e3ccSAndroid Build Coastguard Worker 
99*77c1e3ccSAndroid Build Coastguard Worker     if (error_resilient_nframes_ > 0 &&
100*77c1e3ccSAndroid Build Coastguard Worker         (cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
101*77c1e3ccSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < error_resilient_nframes_; ++i) {
102*77c1e3ccSAndroid Build Coastguard Worker         if (error_resilient_frames_[i] == video->frame()) {
103*77c1e3ccSAndroid Build Coastguard Worker           std::cout << "             Encoding error_resilient frame: "
104*77c1e3ccSAndroid Build Coastguard Worker                     << error_resilient_frames_[i] << "\n";
105*77c1e3ccSAndroid Build Coastguard Worker           frame_flags_ |= AOM_EFLAG_ERROR_RESILIENT;
106*77c1e3ccSAndroid Build Coastguard Worker           break;
107*77c1e3ccSAndroid Build Coastguard Worker         }
108*77c1e3ccSAndroid Build Coastguard Worker       }
109*77c1e3ccSAndroid Build Coastguard Worker     }
110*77c1e3ccSAndroid Build Coastguard Worker 
111*77c1e3ccSAndroid Build Coastguard Worker     if (nomfmv_nframes_ > 0 &&
112*77c1e3ccSAndroid Build Coastguard Worker         (cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
113*77c1e3ccSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < nomfmv_nframes_; ++i) {
114*77c1e3ccSAndroid Build Coastguard Worker         if (nomfmv_frames_[i] == video->frame()) {
115*77c1e3ccSAndroid Build Coastguard Worker           std::cout << "             Encoding no mfmv frame: "
116*77c1e3ccSAndroid Build Coastguard Worker                     << nomfmv_frames_[i] << "\n";
117*77c1e3ccSAndroid Build Coastguard Worker           frame_flags_ |= AOM_EFLAG_NO_REF_FRAME_MVS;
118*77c1e3ccSAndroid Build Coastguard Worker           break;
119*77c1e3ccSAndroid Build Coastguard Worker         }
120*77c1e3ccSAndroid Build Coastguard Worker       }
121*77c1e3ccSAndroid Build Coastguard Worker     }
122*77c1e3ccSAndroid Build Coastguard Worker 
123*77c1e3ccSAndroid Build Coastguard Worker     if (prim_ref_none_nframes_ > 0 &&
124*77c1e3ccSAndroid Build Coastguard Worker         (cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
125*77c1e3ccSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < prim_ref_none_nframes_; ++i) {
126*77c1e3ccSAndroid Build Coastguard Worker         if (prim_ref_none_frames_[i] == video->frame()) {
127*77c1e3ccSAndroid Build Coastguard Worker           std::cout << "             Encoding no PRIMARY_REF_NONE frame: "
128*77c1e3ccSAndroid Build Coastguard Worker                     << prim_ref_none_frames_[i] << "\n";
129*77c1e3ccSAndroid Build Coastguard Worker           frame_flags_ |= AOM_EFLAG_SET_PRIMARY_REF_NONE;
130*77c1e3ccSAndroid Build Coastguard Worker           break;
131*77c1e3ccSAndroid Build Coastguard Worker         }
132*77c1e3ccSAndroid Build Coastguard Worker       }
133*77c1e3ccSAndroid Build Coastguard Worker     }
134*77c1e3ccSAndroid Build Coastguard Worker 
135*77c1e3ccSAndroid Build Coastguard Worker     encoder->Control(AV1E_SET_S_FRAME_MODE, 0);
136*77c1e3ccSAndroid Build Coastguard Worker     if (s_nframes_ > 0 &&
137*77c1e3ccSAndroid Build Coastguard Worker         (cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
138*77c1e3ccSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < s_nframes_; ++i) {
139*77c1e3ccSAndroid Build Coastguard Worker         if (s_frames_[i] == video->frame()) {
140*77c1e3ccSAndroid Build Coastguard Worker           std::cout << "             Encoding S frame: " << s_frames_[i]
141*77c1e3ccSAndroid Build Coastguard Worker                     << "\n";
142*77c1e3ccSAndroid Build Coastguard Worker           frame_flags_ |= AOM_EFLAG_SET_S_FRAME;
143*77c1e3ccSAndroid Build Coastguard Worker           break;
144*77c1e3ccSAndroid Build Coastguard Worker         }
145*77c1e3ccSAndroid Build Coastguard Worker       }
146*77c1e3ccSAndroid Build Coastguard Worker     }
147*77c1e3ccSAndroid Build Coastguard Worker   }
148*77c1e3ccSAndroid Build Coastguard Worker 
FramePktHook(const aom_codec_cx_pkt_t * pkt)149*77c1e3ccSAndroid Build Coastguard Worker   void FramePktHook(const aom_codec_cx_pkt_t *pkt) override {
150*77c1e3ccSAndroid Build Coastguard Worker     // Check that the encode frame flags are correctly reflected
151*77c1e3ccSAndroid Build Coastguard Worker     // in the output frame flags.
152*77c1e3ccSAndroid Build Coastguard Worker     const int encode_flags = pkt->data.frame.flags >> 16;
153*77c1e3ccSAndroid Build Coastguard Worker     if ((encode_flags & (AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
154*77c1e3ccSAndroid Build Coastguard Worker                          AOM_EFLAG_NO_UPD_ARF)) ==
155*77c1e3ccSAndroid Build Coastguard Worker         (AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF)) {
156*77c1e3ccSAndroid Build Coastguard Worker       ASSERT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_DROPPABLE,
157*77c1e3ccSAndroid Build Coastguard Worker                 AOM_FRAME_IS_DROPPABLE);
158*77c1e3ccSAndroid Build Coastguard Worker     }
159*77c1e3ccSAndroid Build Coastguard Worker     if (encode_flags & AOM_EFLAG_SET_S_FRAME) {
160*77c1e3ccSAndroid Build Coastguard Worker       ASSERT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_SWITCH,
161*77c1e3ccSAndroid Build Coastguard Worker                 AOM_FRAME_IS_SWITCH);
162*77c1e3ccSAndroid Build Coastguard Worker     }
163*77c1e3ccSAndroid Build Coastguard Worker     if (encode_flags & AOM_EFLAG_ERROR_RESILIENT) {
164*77c1e3ccSAndroid Build Coastguard Worker       ASSERT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_ERROR_RESILIENT,
165*77c1e3ccSAndroid Build Coastguard Worker                 AOM_FRAME_IS_ERROR_RESILIENT);
166*77c1e3ccSAndroid Build Coastguard Worker     }
167*77c1e3ccSAndroid Build Coastguard Worker   }
168*77c1e3ccSAndroid Build Coastguard Worker 
GetAveragePsnr() const169*77c1e3ccSAndroid Build Coastguard Worker   double GetAveragePsnr() const {
170*77c1e3ccSAndroid Build Coastguard Worker     if (nframes_) return psnr_ / nframes_;
171*77c1e3ccSAndroid Build Coastguard Worker     return 0.0;
172*77c1e3ccSAndroid Build Coastguard Worker   }
173*77c1e3ccSAndroid Build Coastguard Worker 
GetAverageMismatchPsnr() const174*77c1e3ccSAndroid Build Coastguard Worker   double GetAverageMismatchPsnr() const {
175*77c1e3ccSAndroid Build Coastguard Worker     if (mismatch_nframes_) return mismatch_psnr_ / mismatch_nframes_;
176*77c1e3ccSAndroid Build Coastguard Worker     return 0.0;
177*77c1e3ccSAndroid Build Coastguard Worker   }
178*77c1e3ccSAndroid Build Coastguard Worker 
DoDecode() const179*77c1e3ccSAndroid Build Coastguard Worker   bool DoDecode() const override {
180*77c1e3ccSAndroid Build Coastguard Worker     if (error_nframes_ > 0 &&
181*77c1e3ccSAndroid Build Coastguard Worker         (cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
182*77c1e3ccSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < error_nframes_; ++i) {
183*77c1e3ccSAndroid Build Coastguard Worker         if (error_frames_[i] == nframes_ - 1) {
184*77c1e3ccSAndroid Build Coastguard Worker           std::cout << "             Skipping decoding frame: "
185*77c1e3ccSAndroid Build Coastguard Worker                     << error_frames_[i] << "\n";
186*77c1e3ccSAndroid Build Coastguard Worker           return false;
187*77c1e3ccSAndroid Build Coastguard Worker         }
188*77c1e3ccSAndroid Build Coastguard Worker       }
189*77c1e3ccSAndroid Build Coastguard Worker     }
190*77c1e3ccSAndroid Build Coastguard Worker     return true;
191*77c1e3ccSAndroid Build Coastguard Worker   }
192*77c1e3ccSAndroid Build Coastguard Worker 
DoDecodeInvisible() const193*77c1e3ccSAndroid Build Coastguard Worker   bool DoDecodeInvisible() const override {
194*77c1e3ccSAndroid Build Coastguard Worker     if (invisible_error_nframes_ > 0 &&
195*77c1e3ccSAndroid Build Coastguard Worker         (cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
196*77c1e3ccSAndroid Build Coastguard Worker       for (unsigned int i = 0; i < invisible_error_nframes_; ++i) {
197*77c1e3ccSAndroid Build Coastguard Worker         if (invisible_error_frames_[i] == nframes_ - 1) {
198*77c1e3ccSAndroid Build Coastguard Worker           std::cout << "             Skipping decoding all invisible frames in "
199*77c1e3ccSAndroid Build Coastguard Worker                        "frame pkt: "
200*77c1e3ccSAndroid Build Coastguard Worker                     << invisible_error_frames_[i] << "\n";
201*77c1e3ccSAndroid Build Coastguard Worker           return false;
202*77c1e3ccSAndroid Build Coastguard Worker         }
203*77c1e3ccSAndroid Build Coastguard Worker       }
204*77c1e3ccSAndroid Build Coastguard Worker     }
205*77c1e3ccSAndroid Build Coastguard Worker     return true;
206*77c1e3ccSAndroid Build Coastguard Worker   }
207*77c1e3ccSAndroid Build Coastguard Worker 
MismatchHook(const aom_image_t * img1,const aom_image_t * img2)208*77c1e3ccSAndroid Build Coastguard Worker   void MismatchHook(const aom_image_t *img1, const aom_image_t *img2) override {
209*77c1e3ccSAndroid Build Coastguard Worker     if (allow_mismatch_) {
210*77c1e3ccSAndroid Build Coastguard Worker       double mismatch_psnr = compute_psnr(img1, img2);
211*77c1e3ccSAndroid Build Coastguard Worker       mismatch_psnr_ += mismatch_psnr;
212*77c1e3ccSAndroid Build Coastguard Worker       ++mismatch_nframes_;
213*77c1e3ccSAndroid Build Coastguard Worker       // std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n";
214*77c1e3ccSAndroid Build Coastguard Worker     } else {
215*77c1e3ccSAndroid Build Coastguard Worker       ::libaom_test::EncoderTest::MismatchHook(img1, img2);
216*77c1e3ccSAndroid Build Coastguard Worker     }
217*77c1e3ccSAndroid Build Coastguard Worker   }
218*77c1e3ccSAndroid Build Coastguard Worker 
DecompressedFrameHook(const aom_image_t & img,aom_codec_pts_t pts)219*77c1e3ccSAndroid Build Coastguard Worker   void DecompressedFrameHook(const aom_image_t &img,
220*77c1e3ccSAndroid Build Coastguard Worker                              aom_codec_pts_t pts) override {
221*77c1e3ccSAndroid Build Coastguard Worker     (void)img;
222*77c1e3ccSAndroid Build Coastguard Worker     (void)pts;
223*77c1e3ccSAndroid Build Coastguard Worker     ++decoded_nframes_;
224*77c1e3ccSAndroid Build Coastguard Worker   }
225*77c1e3ccSAndroid Build Coastguard Worker 
SetErrorFrames(int num,unsigned int * list)226*77c1e3ccSAndroid Build Coastguard Worker   void SetErrorFrames(int num, unsigned int *list) {
227*77c1e3ccSAndroid Build Coastguard Worker     if (num > kMaxErrorFrames)
228*77c1e3ccSAndroid Build Coastguard Worker       num = kMaxErrorFrames;
229*77c1e3ccSAndroid Build Coastguard Worker     else if (num < 0)
230*77c1e3ccSAndroid Build Coastguard Worker       num = 0;
231*77c1e3ccSAndroid Build Coastguard Worker     error_nframes_ = num;
232*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < error_nframes_; ++i)
233*77c1e3ccSAndroid Build Coastguard Worker       error_frames_[i] = list[i];
234*77c1e3ccSAndroid Build Coastguard Worker   }
235*77c1e3ccSAndroid Build Coastguard Worker 
SetInvisibleErrorFrames(int num,unsigned int * list)236*77c1e3ccSAndroid Build Coastguard Worker   void SetInvisibleErrorFrames(int num, unsigned int *list) {
237*77c1e3ccSAndroid Build Coastguard Worker     if (num > kMaxInvisibleErrorFrames)
238*77c1e3ccSAndroid Build Coastguard Worker       num = kMaxInvisibleErrorFrames;
239*77c1e3ccSAndroid Build Coastguard Worker     else if (num < 0)
240*77c1e3ccSAndroid Build Coastguard Worker       num = 0;
241*77c1e3ccSAndroid Build Coastguard Worker     invisible_error_nframes_ = num;
242*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < invisible_error_nframes_; ++i)
243*77c1e3ccSAndroid Build Coastguard Worker       invisible_error_frames_[i] = list[i];
244*77c1e3ccSAndroid Build Coastguard Worker   }
245*77c1e3ccSAndroid Build Coastguard Worker 
SetDroppableFrames(int num,unsigned int * list)246*77c1e3ccSAndroid Build Coastguard Worker   void SetDroppableFrames(int num, unsigned int *list) {
247*77c1e3ccSAndroid Build Coastguard Worker     if (num > kMaxDroppableFrames)
248*77c1e3ccSAndroid Build Coastguard Worker       num = kMaxDroppableFrames;
249*77c1e3ccSAndroid Build Coastguard Worker     else if (num < 0)
250*77c1e3ccSAndroid Build Coastguard Worker       num = 0;
251*77c1e3ccSAndroid Build Coastguard Worker     droppable_nframes_ = num;
252*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < droppable_nframes_; ++i)
253*77c1e3ccSAndroid Build Coastguard Worker       droppable_frames_[i] = list[i];
254*77c1e3ccSAndroid Build Coastguard Worker   }
255*77c1e3ccSAndroid Build Coastguard Worker 
SetErrorResilientFrames(int num,unsigned int * list)256*77c1e3ccSAndroid Build Coastguard Worker   void SetErrorResilientFrames(int num, unsigned int *list) {
257*77c1e3ccSAndroid Build Coastguard Worker     if (num > kMaxErrorResilientFrames)
258*77c1e3ccSAndroid Build Coastguard Worker       num = kMaxErrorResilientFrames;
259*77c1e3ccSAndroid Build Coastguard Worker     else if (num < 0)
260*77c1e3ccSAndroid Build Coastguard Worker       num = 0;
261*77c1e3ccSAndroid Build Coastguard Worker     error_resilient_nframes_ = num;
262*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < error_resilient_nframes_; ++i)
263*77c1e3ccSAndroid Build Coastguard Worker       error_resilient_frames_[i] = list[i];
264*77c1e3ccSAndroid Build Coastguard Worker   }
265*77c1e3ccSAndroid Build Coastguard Worker 
SetNoMFMVFrames(int num,unsigned int * list)266*77c1e3ccSAndroid Build Coastguard Worker   void SetNoMFMVFrames(int num, unsigned int *list) {
267*77c1e3ccSAndroid Build Coastguard Worker     if (num > kMaxNoMFMVFrames)
268*77c1e3ccSAndroid Build Coastguard Worker       num = kMaxNoMFMVFrames;
269*77c1e3ccSAndroid Build Coastguard Worker     else if (num < 0)
270*77c1e3ccSAndroid Build Coastguard Worker       num = 0;
271*77c1e3ccSAndroid Build Coastguard Worker     nomfmv_nframes_ = num;
272*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < nomfmv_nframes_; ++i)
273*77c1e3ccSAndroid Build Coastguard Worker       nomfmv_frames_[i] = list[i];
274*77c1e3ccSAndroid Build Coastguard Worker   }
275*77c1e3ccSAndroid Build Coastguard Worker 
SetPrimaryRefNoneFrames(int num,unsigned int * list)276*77c1e3ccSAndroid Build Coastguard Worker   void SetPrimaryRefNoneFrames(int num, unsigned int *list) {
277*77c1e3ccSAndroid Build Coastguard Worker     if (num > kMaxPrimRefNoneFrames)
278*77c1e3ccSAndroid Build Coastguard Worker       num = kMaxPrimRefNoneFrames;
279*77c1e3ccSAndroid Build Coastguard Worker     else if (num < 0)
280*77c1e3ccSAndroid Build Coastguard Worker       num = 0;
281*77c1e3ccSAndroid Build Coastguard Worker     prim_ref_none_nframes_ = num;
282*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < prim_ref_none_nframes_; ++i)
283*77c1e3ccSAndroid Build Coastguard Worker       prim_ref_none_frames_[i] = list[i];
284*77c1e3ccSAndroid Build Coastguard Worker   }
285*77c1e3ccSAndroid Build Coastguard Worker 
SetSFrames(int num,unsigned int * list)286*77c1e3ccSAndroid Build Coastguard Worker   void SetSFrames(int num, unsigned int *list) {
287*77c1e3ccSAndroid Build Coastguard Worker     if (num > kMaxSFrames)
288*77c1e3ccSAndroid Build Coastguard Worker       num = kMaxSFrames;
289*77c1e3ccSAndroid Build Coastguard Worker     else if (num < 0)
290*77c1e3ccSAndroid Build Coastguard Worker       num = 0;
291*77c1e3ccSAndroid Build Coastguard Worker     s_nframes_ = num;
292*77c1e3ccSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < s_nframes_; ++i) s_frames_[i] = list[i];
293*77c1e3ccSAndroid Build Coastguard Worker   }
294*77c1e3ccSAndroid Build Coastguard Worker 
GetMismatchFrames()295*77c1e3ccSAndroid Build Coastguard Worker   unsigned int GetMismatchFrames() { return mismatch_nframes_; }
GetEncodedFrames()296*77c1e3ccSAndroid Build Coastguard Worker   unsigned int GetEncodedFrames() { return nframes_; }
GetDecodedFrames()297*77c1e3ccSAndroid Build Coastguard Worker   unsigned int GetDecodedFrames() { return decoded_nframes_; }
298*77c1e3ccSAndroid Build Coastguard Worker 
SetAllowMismatch(int allow)299*77c1e3ccSAndroid Build Coastguard Worker   void SetAllowMismatch(int allow) { allow_mismatch_ = allow; }
300*77c1e3ccSAndroid Build Coastguard Worker 
301*77c1e3ccSAndroid Build Coastguard Worker  private:
302*77c1e3ccSAndroid Build Coastguard Worker   double psnr_;
303*77c1e3ccSAndroid Build Coastguard Worker   unsigned int nframes_;
304*77c1e3ccSAndroid Build Coastguard Worker   unsigned int decoded_nframes_;
305*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_nframes_;
306*77c1e3ccSAndroid Build Coastguard Worker   unsigned int invisible_error_nframes_;
307*77c1e3ccSAndroid Build Coastguard Worker   unsigned int droppable_nframes_;
308*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_resilient_nframes_;
309*77c1e3ccSAndroid Build Coastguard Worker   unsigned int nomfmv_nframes_;
310*77c1e3ccSAndroid Build Coastguard Worker   unsigned int prim_ref_none_nframes_;
311*77c1e3ccSAndroid Build Coastguard Worker   unsigned int s_nframes_;
312*77c1e3ccSAndroid Build Coastguard Worker   double mismatch_psnr_;
313*77c1e3ccSAndroid Build Coastguard Worker   unsigned int mismatch_nframes_;
314*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_frames_[kMaxErrorFrames];
315*77c1e3ccSAndroid Build Coastguard Worker   unsigned int invisible_error_frames_[kMaxInvisibleErrorFrames];
316*77c1e3ccSAndroid Build Coastguard Worker   unsigned int droppable_frames_[kMaxDroppableFrames];
317*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_resilient_frames_[kMaxErrorResilientFrames];
318*77c1e3ccSAndroid Build Coastguard Worker   unsigned int nomfmv_frames_[kMaxNoMFMVFrames];
319*77c1e3ccSAndroid Build Coastguard Worker   unsigned int prim_ref_none_frames_[kMaxPrimRefNoneFrames];
320*77c1e3ccSAndroid Build Coastguard Worker   unsigned int s_frames_[kMaxSFrames];
321*77c1e3ccSAndroid Build Coastguard Worker   libaom_test::TestMode encoding_mode_;
322*77c1e3ccSAndroid Build Coastguard Worker   int allow_mismatch_;
323*77c1e3ccSAndroid Build Coastguard Worker   int enable_altref_;
324*77c1e3ccSAndroid Build Coastguard Worker };
325*77c1e3ccSAndroid Build Coastguard Worker 
TEST_P(ErrorResilienceTestLarge,OnVersusOff)326*77c1e3ccSAndroid Build Coastguard Worker TEST_P(ErrorResilienceTestLarge, OnVersusOff) {
327*77c1e3ccSAndroid Build Coastguard Worker   SetupEncoder(2000, 10);
328*77c1e3ccSAndroid Build Coastguard Worker   libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
329*77c1e3ccSAndroid Build Coastguard Worker                                      cfg_.g_timebase.den, cfg_.g_timebase.num,
330*77c1e3ccSAndroid Build Coastguard Worker                                      0, 12);
331*77c1e3ccSAndroid Build Coastguard Worker 
332*77c1e3ccSAndroid Build Coastguard Worker   // Global error resilient mode OFF.
333*77c1e3ccSAndroid Build Coastguard Worker   cfg_.g_error_resilient = 0;
334*77c1e3ccSAndroid Build Coastguard Worker   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
335*77c1e3ccSAndroid Build Coastguard Worker   const double psnr_resilience_off = GetAveragePsnr();
336*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_GT(psnr_resilience_off, 25.0);
337*77c1e3ccSAndroid Build Coastguard Worker 
338*77c1e3ccSAndroid Build Coastguard Worker   Reset();
339*77c1e3ccSAndroid Build Coastguard Worker   // Error resilient mode ON for certain frames
340*77c1e3ccSAndroid Build Coastguard Worker   unsigned int num_error_resilient_frames = 5;
341*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_resilient_frame_list[] = { 3, 5, 6, 9, 11 };
342*77c1e3ccSAndroid Build Coastguard Worker   SetErrorResilientFrames(num_error_resilient_frames,
343*77c1e3ccSAndroid Build Coastguard Worker                           error_resilient_frame_list);
344*77c1e3ccSAndroid Build Coastguard Worker   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
345*77c1e3ccSAndroid Build Coastguard Worker   const double psnr_resilience_on = GetAveragePsnr();
346*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_GT(psnr_resilience_on, 25.0);
347*77c1e3ccSAndroid Build Coastguard Worker 
348*77c1e3ccSAndroid Build Coastguard Worker   // Test that turning on error resilient mode hurts by 10% at most.
349*77c1e3ccSAndroid Build Coastguard Worker   if (psnr_resilience_off > 0.0) {
350*77c1e3ccSAndroid Build Coastguard Worker     const double psnr_ratio = psnr_resilience_on / psnr_resilience_off;
351*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_GE(psnr_ratio, 0.9);
352*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_LE(psnr_ratio, 1.1);
353*77c1e3ccSAndroid Build Coastguard Worker   }
354*77c1e3ccSAndroid Build Coastguard Worker }
355*77c1e3ccSAndroid Build Coastguard Worker 
356*77c1e3ccSAndroid Build Coastguard Worker // Check for successful decoding and no encoder/decoder mismatch
357*77c1e3ccSAndroid Build Coastguard Worker // if we lose (i.e., drop before decoding) a set of droppable
358*77c1e3ccSAndroid Build Coastguard Worker // frames (i.e., frames that don't update any reference buffers).
TEST_P(ErrorResilienceTestLarge,DropFramesWithoutRecovery)359*77c1e3ccSAndroid Build Coastguard Worker TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) {
360*77c1e3ccSAndroid Build Coastguard Worker   if (GET_PARAM(1) == ::libaom_test::kOnePassGood && GET_PARAM(2) == 1) {
361*77c1e3ccSAndroid Build Coastguard Worker     fprintf(stderr, "Skipping test case #1 because of bug aomedia:3002\n");
362*77c1e3ccSAndroid Build Coastguard Worker     return;
363*77c1e3ccSAndroid Build Coastguard Worker   }
364*77c1e3ccSAndroid Build Coastguard Worker   SetupEncoder(500, 10);
365*77c1e3ccSAndroid Build Coastguard Worker   libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
366*77c1e3ccSAndroid Build Coastguard Worker                                      cfg_.g_timebase.den, cfg_.g_timebase.num,
367*77c1e3ccSAndroid Build Coastguard Worker                                      0, 20);
368*77c1e3ccSAndroid Build Coastguard Worker 
369*77c1e3ccSAndroid Build Coastguard Worker   // Set an arbitrary set of error frames same as droppable frames.
370*77c1e3ccSAndroid Build Coastguard Worker   unsigned int num_droppable_frames = 3;
371*77c1e3ccSAndroid Build Coastguard Worker   unsigned int droppable_frame_list[] = { 5, 11, 13 };
372*77c1e3ccSAndroid Build Coastguard Worker   SetDroppableFrames(num_droppable_frames, droppable_frame_list);
373*77c1e3ccSAndroid Build Coastguard Worker   SetErrorFrames(num_droppable_frames, droppable_frame_list);
374*77c1e3ccSAndroid Build Coastguard Worker   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
375*77c1e3ccSAndroid Build Coastguard Worker   // Test that no mismatches have been found
376*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Encoded frames: " << GetEncodedFrames() << "\n";
377*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Decoded frames: " << GetDecodedFrames() << "\n";
378*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Mismatch frames: " << GetMismatchFrames() << "\n";
379*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(GetEncodedFrames() - GetDecodedFrames(), num_droppable_frames);
380*77c1e3ccSAndroid Build Coastguard Worker }
381*77c1e3ccSAndroid Build Coastguard Worker 
382*77c1e3ccSAndroid Build Coastguard Worker // Check for ParseAbility property of an error-resilient frame.
383*77c1e3ccSAndroid Build Coastguard Worker // Encode a frame in error-resilient mode (E-frame), and disallow all
384*77c1e3ccSAndroid Build Coastguard Worker // subsequent frames from using MFMV. If frames are dropped before the
385*77c1e3ccSAndroid Build Coastguard Worker // E frame, all frames starting from the E frame should be parse-able.
TEST_P(ErrorResilienceTestLarge,ParseAbilityTest)386*77c1e3ccSAndroid Build Coastguard Worker TEST_P(ErrorResilienceTestLarge, ParseAbilityTest) {
387*77c1e3ccSAndroid Build Coastguard Worker   SetupEncoder(500, 10);
388*77c1e3ccSAndroid Build Coastguard Worker 
389*77c1e3ccSAndroid Build Coastguard Worker   libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
390*77c1e3ccSAndroid Build Coastguard Worker                                      cfg_.g_timebase.den, cfg_.g_timebase.num,
391*77c1e3ccSAndroid Build Coastguard Worker                                      0, 15);
392*77c1e3ccSAndroid Build Coastguard Worker 
393*77c1e3ccSAndroid Build Coastguard Worker   SetAllowMismatch(1);
394*77c1e3ccSAndroid Build Coastguard Worker 
395*77c1e3ccSAndroid Build Coastguard Worker   // Note that an E-frame cannot be forced on a frame that is a
396*77c1e3ccSAndroid Build Coastguard Worker   // show_existing_frame, or a frame that comes directly after an invisible
397*77c1e3ccSAndroid Build Coastguard Worker   // frame. Currently, this will cause an assertion failure.
398*77c1e3ccSAndroid Build Coastguard Worker   // Set an arbitrary error resilient (E) frame
399*77c1e3ccSAndroid Build Coastguard Worker   unsigned int num_error_resilient_frames = 1;
400*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_resilient_frame_list[] = { 8 };
401*77c1e3ccSAndroid Build Coastguard Worker   SetErrorResilientFrames(num_error_resilient_frames,
402*77c1e3ccSAndroid Build Coastguard Worker                           error_resilient_frame_list);
403*77c1e3ccSAndroid Build Coastguard Worker   // Ensure that any invisible frames before the E frame are dropped
404*77c1e3ccSAndroid Build Coastguard Worker   SetInvisibleErrorFrames(num_error_resilient_frames,
405*77c1e3ccSAndroid Build Coastguard Worker                           error_resilient_frame_list);
406*77c1e3ccSAndroid Build Coastguard Worker   // Set all frames after the error resilient frame to not allow MFMV
407*77c1e3ccSAndroid Build Coastguard Worker   unsigned int num_post_error_resilient_frames = 6;
408*77c1e3ccSAndroid Build Coastguard Worker   unsigned int post_error_resilient_frame_list[] = { 9, 10, 11, 12, 13, 14 };
409*77c1e3ccSAndroid Build Coastguard Worker   SetNoMFMVFrames(num_post_error_resilient_frames,
410*77c1e3ccSAndroid Build Coastguard Worker                   post_error_resilient_frame_list);
411*77c1e3ccSAndroid Build Coastguard Worker 
412*77c1e3ccSAndroid Build Coastguard Worker   // Set a few frames before the E frame that are lost (not decoded)
413*77c1e3ccSAndroid Build Coastguard Worker   unsigned int num_error_frames = 5;
414*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_frame_list[] = { 3, 4, 5, 6, 7 };
415*77c1e3ccSAndroid Build Coastguard Worker   SetErrorFrames(num_error_frames, error_frame_list);
416*77c1e3ccSAndroid Build Coastguard Worker 
417*77c1e3ccSAndroid Build Coastguard Worker   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
418*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Encoded frames: " << GetEncodedFrames() << "\n";
419*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Decoded frames: " << GetDecodedFrames() << "\n";
420*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Mismatch frames: " << GetMismatchFrames() << "\n";
421*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(GetEncodedFrames() - GetDecodedFrames(), num_error_frames);
422*77c1e3ccSAndroid Build Coastguard Worker   // All frames following the E-frame and the E-frame are expected to have
423*77c1e3ccSAndroid Build Coastguard Worker   // mismatches, but still be parse-able.
424*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_LE(GetMismatchFrames(), num_post_error_resilient_frames + 1);
425*77c1e3ccSAndroid Build Coastguard Worker }
426*77c1e3ccSAndroid Build Coastguard Worker 
427*77c1e3ccSAndroid Build Coastguard Worker // Check for ParseAbility property of an S frame.
428*77c1e3ccSAndroid Build Coastguard Worker // Encode an S-frame. If frames are dropped before the S-frame, all frames
429*77c1e3ccSAndroid Build Coastguard Worker // starting from the S frame should be parse-able.
TEST_P(ErrorResilienceTestLarge,SFrameTest)430*77c1e3ccSAndroid Build Coastguard Worker TEST_P(ErrorResilienceTestLarge, SFrameTest) {
431*77c1e3ccSAndroid Build Coastguard Worker   SetupEncoder(500, 10);
432*77c1e3ccSAndroid Build Coastguard Worker 
433*77c1e3ccSAndroid Build Coastguard Worker   libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
434*77c1e3ccSAndroid Build Coastguard Worker                                      cfg_.g_timebase.den, cfg_.g_timebase.num,
435*77c1e3ccSAndroid Build Coastguard Worker                                      0, 15);
436*77c1e3ccSAndroid Build Coastguard Worker 
437*77c1e3ccSAndroid Build Coastguard Worker   SetAllowMismatch(1);
438*77c1e3ccSAndroid Build Coastguard Worker 
439*77c1e3ccSAndroid Build Coastguard Worker   // Note that an S-frame cannot be forced on a frame that is a
440*77c1e3ccSAndroid Build Coastguard Worker   // show_existing_frame. This issue still needs to be addressed.
441*77c1e3ccSAndroid Build Coastguard Worker   // Set an arbitrary S-frame
442*77c1e3ccSAndroid Build Coastguard Worker   unsigned int num_s_frames = 1;
443*77c1e3ccSAndroid Build Coastguard Worker   unsigned int s_frame_list[] = { 6 };
444*77c1e3ccSAndroid Build Coastguard Worker   SetSFrames(num_s_frames, s_frame_list);
445*77c1e3ccSAndroid Build Coastguard Worker   // Ensure that any invisible frames before the S frame are dropped
446*77c1e3ccSAndroid Build Coastguard Worker   SetInvisibleErrorFrames(num_s_frames, s_frame_list);
447*77c1e3ccSAndroid Build Coastguard Worker 
448*77c1e3ccSAndroid Build Coastguard Worker   // Set a few frames before the S frame that are lost (not decoded)
449*77c1e3ccSAndroid Build Coastguard Worker   unsigned int num_error_frames = 4;
450*77c1e3ccSAndroid Build Coastguard Worker   unsigned int error_frame_list[] = { 2, 3, 4, 5 };
451*77c1e3ccSAndroid Build Coastguard Worker   SetErrorFrames(num_error_frames, error_frame_list);
452*77c1e3ccSAndroid Build Coastguard Worker 
453*77c1e3ccSAndroid Build Coastguard Worker   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
454*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Encoded frames: " << GetEncodedFrames() << "\n";
455*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Decoded frames: " << GetDecodedFrames() << "\n";
456*77c1e3ccSAndroid Build Coastguard Worker   std::cout << "             Mismatch frames: " << GetMismatchFrames() << "\n";
457*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(GetEncodedFrames() - GetDecodedFrames(), num_error_frames);
458*77c1e3ccSAndroid Build Coastguard Worker   // All frames following the S-frame and the S-frame are expected to have
459*77c1e3ccSAndroid Build Coastguard Worker   // mismatches, but still be parse-able.
460*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_LE(GetMismatchFrames(), GetEncodedFrames() - s_frame_list[0]);
461*77c1e3ccSAndroid Build Coastguard Worker }
462*77c1e3ccSAndroid Build Coastguard Worker 
463*77c1e3ccSAndroid Build Coastguard Worker AV1_INSTANTIATE_TEST_SUITE(ErrorResilienceTestLarge, NONREALTIME_TEST_MODES,
464*77c1e3ccSAndroid Build Coastguard Worker                            ::testing::Values(0, 1));
465*77c1e3ccSAndroid Build Coastguard Worker }  // namespace
466