• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <climits>
13 #include <vector>
14 
15 #include "gtest/gtest.h"
16 
17 #include "config/aom_config.h"
18 #include "test/codec_factory.h"
19 #include "test/encode_test_driver.h"
20 #include "test/i420_video_source.h"
21 #include "test/video_source.h"
22 #include "test/util.h"
23 
24 namespace {
25 
26 const unsigned int kCqLevel = 18;
27 const double kMaxPsnr = 100.0;
28 
29 // kPsnrThreshold represents the psnr threshold used to validate the quality of
30 // the first frame. The indices correspond to one/two-pass, allintra and
31 // realtime encoding modes.
32 const double kPsnrThreshold[3] = { 29.0, 41.5, 41.5 };
33 
34 // kPsnrFluctuation represents the maximum allowed psnr fluctuation w.r.t first
35 // frame. The indices correspond to one/two-pass, allintra and realtime
36 // encoding modes.
37 const double kPsnrFluctuation[3] = { 2.5, 0.3, 17.0 };
38 
39 class MonochromeTest
40     : public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode, int,
41                                                  int>,
42       public ::libaom_test::EncoderTest {
43  protected:
MonochromeTest()44   MonochromeTest()
45       : EncoderTest(GET_PARAM(0)), lossless_(GET_PARAM(2)),
46         frame0_psnr_y_(0.0) {}
47 
48   ~MonochromeTest() override = default;
49 
SetUp()50   void SetUp() override { InitializeConfig(GET_PARAM(1)); }
51 
PreEncodeFrameHook(::libaom_test::VideoSource * video,::libaom_test::Encoder * encoder)52   void PreEncodeFrameHook(::libaom_test::VideoSource *video,
53                           ::libaom_test::Encoder *encoder) override {
54     if (video->frame() == 0) {
55       encoder->Control(AOME_SET_CPUUSED, GET_PARAM(3));
56       if (mode_ == ::libaom_test::kAllIntra) {
57         encoder->Control(AOME_SET_CQ_LEVEL, kCqLevel);
58       } else if (mode_ == ::libaom_test::kRealTime) {
59         encoder->Control(AOME_SET_MAX_INTRA_BITRATE_PCT, 10000);
60       }
61       if (lossless_) {
62         encoder->Control(AV1E_SET_LOSSLESS, 1);
63       }
64     }
65   }
66 
DecompressedFrameHook(const aom_image_t & img,aom_codec_pts_t pts)67   void DecompressedFrameHook(const aom_image_t &img,
68                              aom_codec_pts_t pts) override {
69     (void)pts;
70 
71     // Get value of top-left corner pixel of U plane
72     int chroma_value = img.planes[AOM_PLANE_U][0];
73 
74     bool is_chroma_constant =
75         ComparePlaneToValue(img, AOM_PLANE_U, chroma_value) &&
76         ComparePlaneToValue(img, AOM_PLANE_V, chroma_value);
77 
78     // Chroma planes should be constant
79     EXPECT_TRUE(is_chroma_constant);
80 
81     // Monochrome flag on image should be set
82     EXPECT_EQ(img.monochrome, 1);
83 
84     chroma_value_list_.push_back(chroma_value);
85   }
86 
87   // Returns true if all pixels on the plane are equal to value, and returns
88   // false otherwise.
ComparePlaneToValue(const aom_image_t & img,const int plane,const int value)89   bool ComparePlaneToValue(const aom_image_t &img, const int plane,
90                            const int value) {
91     const int w = aom_img_plane_width(&img, plane);
92     const int h = aom_img_plane_height(&img, plane);
93     const uint8_t *const buf = img.planes[plane];
94     const int stride = img.stride[plane];
95 
96     for (int r = 0; r < h; ++r) {
97       for (int c = 0; c < w; ++c) {
98         if (buf[r * stride + c] != value) return false;
99       }
100     }
101     return true;
102   }
103 
PSNRPktHook(const aom_codec_cx_pkt_t * pkt)104   void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) override {
105     // Check average PSNR value is >= 100 db in case of lossless encoding.
106     if (lossless_) {
107       EXPECT_GE(pkt->data.psnr.psnr[0], kMaxPsnr);
108       return;
109     }
110     const int psnr_index = (mode_ == ::libaom_test::kRealTime)   ? 2
111                            : (mode_ == ::libaom_test::kAllIntra) ? 1
112                                                                  : 0;
113     // Check that the initial Y PSNR value is 'high enough', and check that
114     // subsequent Y PSNR values are 'close' to this initial value.
115     if (frame0_psnr_y_ == 0.0) {
116       frame0_psnr_y_ = pkt->data.psnr.psnr[1];
117       EXPECT_GT(frame0_psnr_y_, kPsnrThreshold[psnr_index]);
118     }
119     EXPECT_NEAR(pkt->data.psnr.psnr[1], frame0_psnr_y_,
120                 kPsnrFluctuation[psnr_index]);
121   }
122 
123   int lossless_;
124   std::vector<int> chroma_value_list_;
125   double frame0_psnr_y_;
126 };
127 
128 #if !CONFIG_REALTIME_ONLY
TEST_P(MonochromeTest,TestMonochromeEncoding)129 TEST_P(MonochromeTest, TestMonochromeEncoding) {
130   ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
131                                        30, 1, 0, 5);
132 
133   init_flags_ = AOM_CODEC_USE_PSNR;
134 
135   cfg_.rc_buf_initial_sz = 500;
136   cfg_.rc_buf_optimal_sz = 600;
137   cfg_.rc_buf_sz = 1000;
138   cfg_.rc_min_quantizer = 2;
139   cfg_.rc_max_quantizer = 56;
140   cfg_.rc_undershoot_pct = 50;
141   cfg_.rc_overshoot_pct = 50;
142   cfg_.rc_end_usage = AOM_CBR;
143   cfg_.g_lag_in_frames = 1;
144   cfg_.kf_min_dist = cfg_.kf_max_dist = 3000;
145   // Enable dropped frames.
146   cfg_.rc_dropframe_thresh = 1;
147   // Run at low bitrate.
148   cfg_.rc_target_bitrate = 40;
149   // Set monochrome encoding flag
150   cfg_.monochrome = 1;
151 
152   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
153 
154   // Check that the chroma planes are equal across all frames
155   std::vector<int>::const_iterator iter = chroma_value_list_.begin();
156   int initial_chroma_value = *iter;
157   for (; iter != chroma_value_list_.end(); ++iter) {
158     // Check that all decoded frames have the same constant chroma planes.
159     EXPECT_EQ(*iter, initial_chroma_value);
160   }
161 }
162 
163 class MonochromeAllIntraTest : public MonochromeTest {};
164 
TEST_P(MonochromeAllIntraTest,TestMonochromeEncoding)165 TEST_P(MonochromeAllIntraTest, TestMonochromeEncoding) {
166   ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
167                                        30, 1, 0, 5);
168   init_flags_ = AOM_CODEC_USE_PSNR;
169   // Set monochrome encoding flag
170   cfg_.monochrome = 1;
171   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
172 
173   // Check that the chroma planes are equal across all frames
174   std::vector<int>::const_iterator iter = chroma_value_list_.begin();
175   int initial_chroma_value = *iter;
176   for (; iter != chroma_value_list_.end(); ++iter) {
177     // Check that all decoded frames have the same constant chroma planes.
178     EXPECT_EQ(*iter, initial_chroma_value);
179   }
180 }
181 
182 #endif  // !CONFIG_REALTIME_ONLY
183 
184 class MonochromeRealtimeTest : public MonochromeTest {};
185 
TEST_P(MonochromeRealtimeTest,TestMonochromeEncoding)186 TEST_P(MonochromeRealtimeTest, TestMonochromeEncoding) {
187   ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
188                                        30, 1, 0, 30);
189   init_flags_ = AOM_CODEC_USE_PSNR;
190   // Set monochrome encoding flag
191   cfg_.monochrome = 1;
192   // Run at low bitrate.
193   cfg_.rc_target_bitrate = 40;
194   cfg_.rc_buf_sz = 6000;
195   cfg_.rc_buf_initial_sz = 4000;
196   cfg_.rc_buf_optimal_sz = 5000;
197   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
198 
199 #if CONFIG_AV1_DECODER
200   // Check that the chroma planes are equal across all frames
201   std::vector<int>::const_iterator iter = chroma_value_list_.begin();
202   int initial_chroma_value = *iter;
203   for (; iter != chroma_value_list_.end(); ++iter) {
204     // Check that all decoded frames have the same constant chroma planes.
205     EXPECT_EQ(*iter, initial_chroma_value);
206   }
207 #endif
208 }
209 
210 #if !CONFIG_REALTIME_ONLY
211 AV1_INSTANTIATE_TEST_SUITE(MonochromeTest,
212                            ::testing::Values(::libaom_test::kOnePassGood,
213                                              ::libaom_test::kTwoPassGood),
214                            ::testing::Values(0),   // lossless
215                            ::testing::Values(0));  // cpu_used
216 
217 AV1_INSTANTIATE_TEST_SUITE(MonochromeAllIntraTest,
218                            ::testing::Values(::libaom_test::kAllIntra),
219                            ::testing::Values(0, 1),   // lossless
220                            ::testing::Values(6, 9));  // cpu_used
221 #endif                                                // !CONFIG_REALTIME_ONLY
222 
223 AV1_INSTANTIATE_TEST_SUITE(MonochromeRealtimeTest,
224                            ::testing::Values(::libaom_test::kRealTime),
225                            ::testing::Values(0),          // lossless
226                            ::testing::Values(6, 8, 10));  // cpu_used
227 
228 }  // namespace
229