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 <math.h>
13 #include <stdlib.h>
14 #include <new>
15 #include <tuple>
16 
17 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
18 #include "test/acm_random.h"
19 #include "test/util.h"
20 
21 #include "config/aom_config.h"
22 
23 #include "aom_dsp/psnr.h"
24 #include "aom_dsp/ssim.h"
25 #include "aom_ports/mem.h"
26 #include "aom_ports/msvc.h"
27 #include "aom_scale/yv12config.h"
28 
29 using libaom_test::ACMRandom;
30 
31 namespace {
32 
33 typedef double (*LBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
34                                 const YV12_BUFFER_CONFIG *dest);
35 typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
36                                 const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
37                                 uint32_t bd);
38 
compute_hbd_psnr(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest,uint32_t in_bd,uint32_t bd)39 double compute_hbd_psnr(const YV12_BUFFER_CONFIG *source,
40                         const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
41                         uint32_t bd) {
42   PSNR_STATS psnr;
43   aom_calc_highbd_psnr(source, dest, &psnr, bd, in_bd);
44   return psnr.psnr[0];
45 }
46 
compute_psnr(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest)47 double compute_psnr(const YV12_BUFFER_CONFIG *source,
48                     const YV12_BUFFER_CONFIG *dest) {
49   PSNR_STATS psnr;
50   aom_calc_psnr(source, dest, &psnr);
51   return psnr.psnr[0];
52 }
53 
compute_hbd_psnrhvs(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest,uint32_t in_bd,uint32_t bd)54 double compute_hbd_psnrhvs(const YV12_BUFFER_CONFIG *source,
55                            const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
56                            uint32_t bd) {
57   double tempy, tempu, tempv;
58   return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, bd, in_bd);
59 }
60 
compute_psnrhvs(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest)61 double compute_psnrhvs(const YV12_BUFFER_CONFIG *source,
62                        const YV12_BUFFER_CONFIG *dest) {
63   double tempy, tempu, tempv;
64   return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, 8, 8);
65 }
66 
compute_hbd_fastssim(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest,uint32_t in_bd,uint32_t bd)67 double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source,
68                             const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
69                             uint32_t bd) {
70   double tempy, tempu, tempv;
71   return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, bd, in_bd);
72 }
73 
compute_fastssim(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest)74 double compute_fastssim(const YV12_BUFFER_CONFIG *source,
75                         const YV12_BUFFER_CONFIG *dest) {
76   double tempy, tempu, tempv;
77   return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, 8, 8);
78 }
79 
compute_hbd_aomssim(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest,uint32_t in_bd,uint32_t bd)80 double compute_hbd_aomssim(const YV12_BUFFER_CONFIG *source,
81                            const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
82                            uint32_t bd) {
83   double ssim[2], weight[2];
84   aom_highbd_calc_ssim(source, dest, weight, bd, in_bd, ssim);
85   return 100 * pow(ssim[0] / weight[0], 8.0);
86 }
87 
compute_aomssim(const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dest)88 double compute_aomssim(const YV12_BUFFER_CONFIG *source,
89                        const YV12_BUFFER_CONFIG *dest) {
90   double ssim, weight;
91   aom_lowbd_calc_ssim(source, dest, &weight, &ssim);
92   return 100 * pow(ssim / weight, 8.0);
93 }
94 
95 class HBDMetricsTestBase {
96  public:
~HBDMetricsTestBase()97   virtual ~HBDMetricsTestBase() {}
98 
99  protected:
RunAccuracyCheck()100   void RunAccuracyCheck() {
101     const int width = 1920;
102     const int height = 1080;
103     size_t i = 0;
104     const uint8_t kPixFiller = 128;
105     YV12_BUFFER_CONFIG lbd_src, lbd_dst;
106     YV12_BUFFER_CONFIG hbd_src, hbd_dst;
107     ACMRandom rnd(ACMRandom::DeterministicSeed());
108     double lbd_db, hbd_db;
109 
110     memset(&lbd_src, 0, sizeof(lbd_src));
111     memset(&lbd_dst, 0, sizeof(lbd_dst));
112     memset(&hbd_src, 0, sizeof(hbd_src));
113     memset(&hbd_dst, 0, sizeof(hbd_dst));
114 
115     aom_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16);
116     aom_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16);
117     aom_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16);
118     aom_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16);
119 
120     memset(lbd_src.buffer_alloc, kPixFiller, lbd_src.buffer_alloc_sz);
121     while (i < lbd_src.buffer_alloc_sz) {
122       uint16_t spel, dpel;
123       spel = lbd_src.buffer_alloc[i];
124       // Create some distortion for dst buffer.
125       dpel = rnd.Rand8();
126       lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
127       ((uint16_t *)(hbd_src.buffer_alloc))[i] = spel << (bit_depth_ - 8);
128       ((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
129       i++;
130     }
131 
132     lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
133     hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
134     EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
135 
136     i = 0;
137     while (i < lbd_src.buffer_alloc_sz) {
138       uint16_t dpel;
139       // Create some small distortion for dst buffer.
140       dpel = 120 + (rnd.Rand8() >> 4);
141       lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
142       ((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
143       i++;
144     }
145 
146     lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
147     hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
148     EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
149 
150     i = 0;
151     while (i < lbd_src.buffer_alloc_sz) {
152       uint16_t dpel;
153       // Create some small distortion for dst buffer.
154       dpel = 126 + (rnd.Rand8() >> 6);
155       lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
156       ((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
157       i++;
158     }
159 
160     lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
161     hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
162     EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
163 
164     aom_free_frame_buffer(&lbd_src);
165     aom_free_frame_buffer(&lbd_dst);
166     aom_free_frame_buffer(&hbd_src);
167     aom_free_frame_buffer(&hbd_dst);
168   }
169 
170   int input_bit_depth_;
171   int bit_depth_;
172   double threshold_;
173   LBDMetricFunc lbd_metric_;
174   HBDMetricFunc hbd_metric_;
175 };
176 
177 typedef std::tuple<LBDMetricFunc, HBDMetricFunc, int, int, double>
178     MetricTestTParam;
179 class HBDMetricsTest : public HBDMetricsTestBase,
180                        public ::testing::TestWithParam<MetricTestTParam> {
181  public:
SetUp()182   virtual void SetUp() {
183     lbd_metric_ = GET_PARAM(0);
184     hbd_metric_ = GET_PARAM(1);
185     input_bit_depth_ = GET_PARAM(2);
186     bit_depth_ = GET_PARAM(3);
187     threshold_ = GET_PARAM(4);
188   }
TearDown()189   virtual void TearDown() {}
190 };
191 
TEST_P(HBDMetricsTest,RunAccuracyCheck)192 TEST_P(HBDMetricsTest, RunAccuracyCheck) { RunAccuracyCheck(); }
193 
194 // Allow small variation due to floating point operations.
195 static const double kSsim_thresh = 0.001;
196 // Allow some additional errors accumulated in floating point operations.
197 static const double kFSsim_thresh = 0.03;
198 // Allow some extra variation due to rounding error accumulated in dct.
199 static const double kPhvs_thresh = 0.3;
200 
201 INSTANTIATE_TEST_SUITE_P(
202     AOMSSIM, HBDMetricsTest,
203     ::testing::Values(MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
204                                        8, 10, kSsim_thresh),
205                       MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
206                                        10, 10, kPhvs_thresh),
207                       MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
208                                        8, 12, kSsim_thresh),
209                       MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
210                                        12, 12, kPhvs_thresh)));
211 INSTANTIATE_TEST_SUITE_P(
212     FASTSSIM, HBDMetricsTest,
213     ::testing::Values(MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
214                                        8, 10, kFSsim_thresh),
215                       MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
216                                        10, 10, kFSsim_thresh),
217                       MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
218                                        8, 12, kFSsim_thresh),
219                       MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
220                                        12, 12, kFSsim_thresh)));
221 INSTANTIATE_TEST_SUITE_P(
222     PSNRHVS, HBDMetricsTest,
223     ::testing::Values(MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
224                                        8, 10, kPhvs_thresh),
225                       MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
226                                        10, 10, kPhvs_thresh),
227                       MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
228                                        8, 12, kPhvs_thresh),
229                       MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
230                                        12, 12, kPhvs_thresh)));
231 INSTANTIATE_TEST_SUITE_P(
232     PSNR, HBDMetricsTest,
233     ::testing::Values(
234         MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 10, kPhvs_thresh),
235         MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 10, 10,
236                          kPhvs_thresh),
237         MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 12, kPhvs_thresh),
238         MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 12, 12,
239                          kPhvs_thresh)));
240 }  // namespace
241