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