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