xref: /aosp_15_r20/external/libvpx/test/frame_size_tests.cc (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1 /*
2  *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include <memory>
11 
12 #include "gtest/gtest.h"
13 #include "test/codec_factory.h"
14 #include "test/register_state_check.h"
15 #include "test/video_source.h"
16 #include "vpx_config.h"
17 
18 namespace {
19 
20 class EncoderWithExpectedError : public ::libvpx_test::Encoder {
21  public:
EncoderWithExpectedError(vpx_codec_enc_cfg_t cfg,vpx_enc_deadline_t deadline,const unsigned long init_flags,::libvpx_test::TwopassStatsStore * stats)22   EncoderWithExpectedError(vpx_codec_enc_cfg_t cfg, vpx_enc_deadline_t deadline,
23                            const unsigned long init_flags,  // NOLINT
24                            ::libvpx_test::TwopassStatsStore *stats)
25       : ::libvpx_test::Encoder(cfg, deadline, init_flags, stats) {}
26   // This overrides with expected error code.
EncodeFrame(::libvpx_test::VideoSource * video,const unsigned long frame_flags,const vpx_codec_err_t expected_err)27   void EncodeFrame(::libvpx_test::VideoSource *video,
28                    const unsigned long frame_flags,  // NOLINT
29                    const vpx_codec_err_t expected_err) {
30     if (video->img()) {
31       EncodeFrameInternal(*video, frame_flags, expected_err);
32     } else {
33       Flush();
34     }
35 
36     // Handle twopass stats
37     ::libvpx_test::CxDataIterator iter = GetCxData();
38 
39     while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
40       if (pkt->kind != VPX_CODEC_STATS_PKT) continue;
41 
42       stats_->Append(*pkt);
43     }
44   }
45 
46  protected:
EncodeFrameInternal(const::libvpx_test::VideoSource & video,const unsigned long frame_flags,const vpx_codec_err_t expected_err)47   void EncodeFrameInternal(const ::libvpx_test::VideoSource &video,
48                            const unsigned long frame_flags,  // NOLINT
49                            const vpx_codec_err_t expected_err) {
50     vpx_codec_err_t res;
51     const vpx_image_t *img = video.img();
52 
53     // Handle frame resizing
54     if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) {
55       cfg_.g_w = img->d_w;
56       cfg_.g_h = img->d_h;
57       res = vpx_codec_enc_config_set(&encoder_, &cfg_);
58       ASSERT_EQ(res, VPX_CODEC_OK) << EncoderError();
59     }
60 
61     // Encode the frame
62     API_REGISTER_STATE_CHECK(res = vpx_codec_encode(&encoder_, img, video.pts(),
63                                                     video.duration(),
64                                                     frame_flags, deadline_));
65     ASSERT_EQ(expected_err, res) << EncoderError();
66   }
67 
CodecInterface() const68   vpx_codec_iface_t *CodecInterface() const override {
69 #if CONFIG_VP9_ENCODER
70     return &vpx_codec_vp9_cx_algo;
71 #else
72     return nullptr;
73 #endif
74   }
75 };
76 
77 class VP9FrameSizeTestsLarge : public ::libvpx_test::EncoderTest,
78                                public ::testing::Test {
79  protected:
VP9FrameSizeTestsLarge()80   VP9FrameSizeTestsLarge()
81       : EncoderTest(&::libvpx_test::kVP9), expected_res_(VPX_CODEC_OK) {}
82   ~VP9FrameSizeTestsLarge() override = default;
83 
SetUp()84   void SetUp() override {
85     InitializeConfig();
86     SetMode(::libvpx_test::kRealTime);
87   }
88 
HandleDecodeResult(const vpx_codec_err_t res_dec,const libvpx_test::VideoSource &,libvpx_test::Decoder * decoder)89   bool HandleDecodeResult(const vpx_codec_err_t res_dec,
90                           const libvpx_test::VideoSource & /*video*/,
91                           libvpx_test::Decoder *decoder) override {
92     EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError();
93     return !::testing::Test::HasFailure();
94   }
95 
PreEncodeFrameHook(::libvpx_test::VideoSource * video,::libvpx_test::Encoder * encoder)96   void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
97                           ::libvpx_test::Encoder *encoder) override {
98     if (video->frame() == 0) {
99       encoder->Control(VP8E_SET_CPUUSED, 7);
100       encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
101       encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
102       encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
103       encoder->Control(VP8E_SET_ARNR_TYPE, 3);
104     }
105   }
106 
107   using ::libvpx_test::EncoderTest::RunLoop;
RunLoop(::libvpx_test::VideoSource * video,const vpx_codec_err_t expected_err)108   virtual void RunLoop(::libvpx_test::VideoSource *video,
109                        const vpx_codec_err_t expected_err) {
110     stats_.Reset();
111 
112     ASSERT_TRUE(passes_ == 1 || passes_ == 2);
113     for (unsigned int pass = 0; pass < passes_; pass++) {
114       vpx_codec_pts_t last_pts = 0;
115 
116       if (passes_ == 1) {
117         cfg_.g_pass = VPX_RC_ONE_PASS;
118       } else if (pass == 0) {
119         cfg_.g_pass = VPX_RC_FIRST_PASS;
120       } else {
121         cfg_.g_pass = VPX_RC_LAST_PASS;
122       }
123 
124       BeginPassHook(pass);
125       std::unique_ptr<EncoderWithExpectedError> encoder(
126           new EncoderWithExpectedError(cfg_, deadline_, init_flags_, &stats_));
127       ASSERT_NE(encoder.get(), nullptr);
128 
129       ASSERT_NO_FATAL_FAILURE(video->Begin());
130       encoder->InitEncoder(video);
131       ASSERT_FALSE(::testing::Test::HasFatalFailure());
132       for (bool again = true; again; video->Next()) {
133         again = (video->img() != nullptr);
134 
135         PreEncodeFrameHook(video, encoder.get());
136         encoder->EncodeFrame(video, frame_flags_, expected_err);
137 
138         PostEncodeFrameHook(encoder.get());
139 
140         ::libvpx_test::CxDataIterator iter = encoder->GetCxData();
141 
142         while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
143           pkt = MutateEncoderOutputHook(pkt);
144           again = true;
145           switch (pkt->kind) {
146             case VPX_CODEC_CX_FRAME_PKT:
147               ASSERT_GE(pkt->data.frame.pts, last_pts);
148               last_pts = pkt->data.frame.pts;
149               FramePktHook(pkt);
150               break;
151 
152             case VPX_CODEC_PSNR_PKT: PSNRPktHook(pkt); break;
153             case VPX_CODEC_STATS_PKT: StatsPktHook(pkt); break;
154             default: break;
155           }
156         }
157 
158         if (!Continue()) break;
159       }
160 
161       EndPassHook();
162 
163       if (!Continue()) break;
164     }
165   }
166 
167   vpx_codec_err_t expected_res_;
168 };
169 
TEST_F(VP9FrameSizeTestsLarge,TestInvalidSizes)170 TEST_F(VP9FrameSizeTestsLarge, TestInvalidSizes) {
171 #ifdef CHROMIUM
172   GTEST_SKIP() << "16K framebuffers are not supported by Chromium's allocator.";
173 #else
174   ::libvpx_test::RandomVideoSource video;
175 
176 #if CONFIG_SIZE_LIMIT
177   video.SetSize(DECODE_WIDTH_LIMIT + 16, DECODE_HEIGHT_LIMIT + 16);
178   video.set_limit(2);
179   expected_res_ = VPX_CODEC_MEM_ERROR;
180   ASSERT_NO_FATAL_FAILURE(RunLoop(&video, expected_res_));
181 #endif
182 
183 #endif
184 }
185 
TEST_F(VP9FrameSizeTestsLarge,ValidSizes)186 TEST_F(VP9FrameSizeTestsLarge, ValidSizes) {
187 #ifdef CHROMIUM
188   GTEST_SKIP()
189       << "Under Chromium's configuration the allocator is unable to provide"
190          "the space required for a single frame at the maximum resolution.";
191 #else
192   ::libvpx_test::RandomVideoSource video;
193 
194 #if CONFIG_SIZE_LIMIT
195   video.SetSize(DECODE_WIDTH_LIMIT, DECODE_HEIGHT_LIMIT);
196   video.set_limit(2);
197   expected_res_ = VPX_CODEC_OK;
198   ASSERT_NO_FATAL_FAILURE(::libvpx_test::EncoderTest::RunLoop(&video));
199 #else
200 // This test produces a pretty large single frame allocation,  (roughly
201 // 25 megabits). The encoder allocates a good number of these frames
202 // one for each lag in frames (for 2 pass), and then one for each possible
203 // reference buffer (8) - we can end up with up to 30 buffers of roughly this
204 // size or almost 1 gig of memory.
205 // In total the allocations will exceed 2GiB which may cause a failure with
206 // mingw + wine, use a smaller size in that case.
207 #if defined(_WIN32) && !defined(_WIN64)
208   video.SetSize(4096, 3072);
209 #else
210   video.SetSize(4096, 4096);
211 #endif
212   video.set_limit(2);
213   expected_res_ = VPX_CODEC_OK;
214   ASSERT_NO_FATAL_FAILURE(::libvpx_test::EncoderTest::RunLoop(&video));
215 #endif
216 
217 #endif  // defined(CHROMIUM)
218 }
219 
TEST_F(VP9FrameSizeTestsLarge,OneByOneVideo)220 TEST_F(VP9FrameSizeTestsLarge, OneByOneVideo) {
221   ::libvpx_test::RandomVideoSource video;
222 
223   video.SetSize(1, 1);
224   video.set_limit(2);
225   expected_res_ = VPX_CODEC_OK;
226   ASSERT_NO_FATAL_FAILURE(::libvpx_test::EncoderTest::RunLoop(&video));
227 }
228 }  // namespace
229