xref: /aosp_15_r20/external/libaom/aom_dsp/psnrhvs.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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  *  This code was originally written by: Gregory Maxwell, at the Daala
12*77c1e3ccSAndroid Build Coastguard Worker  *  project.
13*77c1e3ccSAndroid Build Coastguard Worker  */
14*77c1e3ccSAndroid Build Coastguard Worker 
15*77c1e3ccSAndroid Build Coastguard Worker #include <assert.h>
16*77c1e3ccSAndroid Build Coastguard Worker #include <math.h>
17*77c1e3ccSAndroid Build Coastguard Worker #include <stdio.h>
18*77c1e3ccSAndroid Build Coastguard Worker #include <stdlib.h>
19*77c1e3ccSAndroid Build Coastguard Worker 
20*77c1e3ccSAndroid Build Coastguard Worker #include "config/aom_config.h"
21*77c1e3ccSAndroid Build Coastguard Worker #include "config/aom_dsp_rtcd.h"
22*77c1e3ccSAndroid Build Coastguard Worker 
23*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/psnr.h"
24*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/ssim.h"
25*77c1e3ccSAndroid Build Coastguard Worker 
od_bin_fdct8x8(tran_low_t * y,int ystride,const int16_t * x,int xstride)26*77c1e3ccSAndroid Build Coastguard Worker static void od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
27*77c1e3ccSAndroid Build Coastguard Worker                            int xstride) {
28*77c1e3ccSAndroid Build Coastguard Worker   int i, j;
29*77c1e3ccSAndroid Build Coastguard Worker   (void)xstride;
30*77c1e3ccSAndroid Build Coastguard Worker   aom_fdct8x8(x, y, ystride);
31*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < 8; i++)
32*77c1e3ccSAndroid Build Coastguard Worker     for (j = 0; j < 8; j++)
33*77c1e3ccSAndroid Build Coastguard Worker       *(y + ystride * i + j) = (*(y + ystride * i + j) + 4) >> 3;
34*77c1e3ccSAndroid Build Coastguard Worker }
35*77c1e3ccSAndroid Build Coastguard Worker 
36*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_HIGHBITDEPTH
hbd_od_bin_fdct8x8(tran_low_t * y,int ystride,const int16_t * x,int xstride)37*77c1e3ccSAndroid Build Coastguard Worker static void hbd_od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
38*77c1e3ccSAndroid Build Coastguard Worker                                int xstride) {
39*77c1e3ccSAndroid Build Coastguard Worker   int i, j;
40*77c1e3ccSAndroid Build Coastguard Worker   (void)xstride;
41*77c1e3ccSAndroid Build Coastguard Worker   aom_highbd_fdct8x8(x, y, ystride);
42*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < 8; i++)
43*77c1e3ccSAndroid Build Coastguard Worker     for (j = 0; j < 8; j++)
44*77c1e3ccSAndroid Build Coastguard Worker       *(y + ystride * i + j) = (*(y + ystride * i + j) + 4) >> 3;
45*77c1e3ccSAndroid Build Coastguard Worker }
46*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_AV1_HIGHBITDEPTH
47*77c1e3ccSAndroid Build Coastguard Worker 
48*77c1e3ccSAndroid Build Coastguard Worker /* Normalized inverse quantization matrix for 8x8 DCT at the point of
49*77c1e3ccSAndroid Build Coastguard Worker  * transparency. This is not the JPEG based matrix from the paper,
50*77c1e3ccSAndroid Build Coastguard Worker  this one gives a slightly higher MOS agreement.*/
51*77c1e3ccSAndroid Build Coastguard Worker static const double csf_y[8][8] = {
52*77c1e3ccSAndroid Build Coastguard Worker   { 1.6193873005, 2.2901594831, 2.08509755623, 1.48366094411, 1.00227514334,
53*77c1e3ccSAndroid Build Coastguard Worker     0.678296995242, 0.466224900598, 0.3265091542 },
54*77c1e3ccSAndroid Build Coastguard Worker   { 2.2901594831, 1.94321815382, 2.04793073064, 1.68731108984, 1.2305666963,
55*77c1e3ccSAndroid Build Coastguard Worker     0.868920337363, 0.61280991668, 0.436405793551 },
56*77c1e3ccSAndroid Build Coastguard Worker   { 2.08509755623, 2.04793073064, 1.34329019223, 1.09205635862, 0.875748795257,
57*77c1e3ccSAndroid Build Coastguard Worker     0.670882927016, 0.501731932449, 0.372504254596 },
58*77c1e3ccSAndroid Build Coastguard Worker   { 1.48366094411, 1.68731108984, 1.09205635862, 0.772819797575, 0.605636379554,
59*77c1e3ccSAndroid Build Coastguard Worker     0.48309405692, 0.380429446972, 0.295774038565 },
60*77c1e3ccSAndroid Build Coastguard Worker   { 1.00227514334, 1.2305666963, 0.875748795257, 0.605636379554, 0.448996256676,
61*77c1e3ccSAndroid Build Coastguard Worker     0.352889268808, 0.283006984131, 0.226951348204 },
62*77c1e3ccSAndroid Build Coastguard Worker   { 0.678296995242, 0.868920337363, 0.670882927016, 0.48309405692,
63*77c1e3ccSAndroid Build Coastguard Worker     0.352889268808, 0.27032073436, 0.215017739696, 0.17408067321 },
64*77c1e3ccSAndroid Build Coastguard Worker   { 0.466224900598, 0.61280991668, 0.501731932449, 0.380429446972,
65*77c1e3ccSAndroid Build Coastguard Worker     0.283006984131, 0.215017739696, 0.168869545842, 0.136153931001 },
66*77c1e3ccSAndroid Build Coastguard Worker   { 0.3265091542, 0.436405793551, 0.372504254596, 0.295774038565,
67*77c1e3ccSAndroid Build Coastguard Worker     0.226951348204, 0.17408067321, 0.136153931001, 0.109083846276 }
68*77c1e3ccSAndroid Build Coastguard Worker };
69*77c1e3ccSAndroid Build Coastguard Worker static const double csf_cb420[8][8] = {
70*77c1e3ccSAndroid Build Coastguard Worker   { 1.91113096927, 2.46074210438, 1.18284184739, 1.14982565193, 1.05017074788,
71*77c1e3ccSAndroid Build Coastguard Worker     0.898018824055, 0.74725392039, 0.615105596242 },
72*77c1e3ccSAndroid Build Coastguard Worker   { 2.46074210438, 1.58529308355, 1.21363250036, 1.38190029285, 1.33100189972,
73*77c1e3ccSAndroid Build Coastguard Worker     1.17428548929, 0.996404342439, 0.830890433625 },
74*77c1e3ccSAndroid Build Coastguard Worker   { 1.18284184739, 1.21363250036, 0.978712413627, 1.02624506078, 1.03145147362,
75*77c1e3ccSAndroid Build Coastguard Worker     0.960060382087, 0.849823426169, 0.731221236837 },
76*77c1e3ccSAndroid Build Coastguard Worker   { 1.14982565193, 1.38190029285, 1.02624506078, 0.861317501629, 0.801821139099,
77*77c1e3ccSAndroid Build Coastguard Worker     0.751437590932, 0.685398513368, 0.608694761374 },
78*77c1e3ccSAndroid Build Coastguard Worker   { 1.05017074788, 1.33100189972, 1.03145147362, 0.801821139099, 0.676555426187,
79*77c1e3ccSAndroid Build Coastguard Worker     0.605503172737, 0.55002013668, 0.495804539034 },
80*77c1e3ccSAndroid Build Coastguard Worker   { 0.898018824055, 1.17428548929, 0.960060382087, 0.751437590932,
81*77c1e3ccSAndroid Build Coastguard Worker     0.605503172737, 0.514674450957, 0.454353482512, 0.407050308965 },
82*77c1e3ccSAndroid Build Coastguard Worker   { 0.74725392039, 0.996404342439, 0.849823426169, 0.685398513368,
83*77c1e3ccSAndroid Build Coastguard Worker     0.55002013668, 0.454353482512, 0.389234902883, 0.342353999733 },
84*77c1e3ccSAndroid Build Coastguard Worker   { 0.615105596242, 0.830890433625, 0.731221236837, 0.608694761374,
85*77c1e3ccSAndroid Build Coastguard Worker     0.495804539034, 0.407050308965, 0.342353999733, 0.295530605237 }
86*77c1e3ccSAndroid Build Coastguard Worker };
87*77c1e3ccSAndroid Build Coastguard Worker static const double csf_cr420[8][8] = {
88*77c1e3ccSAndroid Build Coastguard Worker   { 2.03871978502, 2.62502345193, 1.26180942886, 1.11019789803, 1.01397751469,
89*77c1e3ccSAndroid Build Coastguard Worker     0.867069376285, 0.721500455585, 0.593906509971 },
90*77c1e3ccSAndroid Build Coastguard Worker   { 2.62502345193, 1.69112867013, 1.17180569821, 1.3342742857, 1.28513006198,
91*77c1e3ccSAndroid Build Coastguard Worker     1.13381474809, 0.962064122248, 0.802254508198 },
92*77c1e3ccSAndroid Build Coastguard Worker   { 1.26180942886, 1.17180569821, 0.944981930573, 0.990876405848,
93*77c1e3ccSAndroid Build Coastguard Worker     0.995903384143, 0.926972725286, 0.820534991409, 0.706020324706 },
94*77c1e3ccSAndroid Build Coastguard Worker   { 1.11019789803, 1.3342742857, 0.990876405848, 0.831632933426, 0.77418706195,
95*77c1e3ccSAndroid Build Coastguard Worker     0.725539939514, 0.661776842059, 0.587716619023 },
96*77c1e3ccSAndroid Build Coastguard Worker   { 1.01397751469, 1.28513006198, 0.995903384143, 0.77418706195, 0.653238524286,
97*77c1e3ccSAndroid Build Coastguard Worker     0.584635025748, 0.531064164893, 0.478717061273 },
98*77c1e3ccSAndroid Build Coastguard Worker   { 0.867069376285, 1.13381474809, 0.926972725286, 0.725539939514,
99*77c1e3ccSAndroid Build Coastguard Worker     0.584635025748, 0.496936637883, 0.438694579826, 0.393021669543 },
100*77c1e3ccSAndroid Build Coastguard Worker   { 0.721500455585, 0.962064122248, 0.820534991409, 0.661776842059,
101*77c1e3ccSAndroid Build Coastguard Worker     0.531064164893, 0.438694579826, 0.375820256136, 0.330555063063 },
102*77c1e3ccSAndroid Build Coastguard Worker   { 0.593906509971, 0.802254508198, 0.706020324706, 0.587716619023,
103*77c1e3ccSAndroid Build Coastguard Worker     0.478717061273, 0.393021669543, 0.330555063063, 0.285345396658 }
104*77c1e3ccSAndroid Build Coastguard Worker };
105*77c1e3ccSAndroid Build Coastguard Worker 
convert_score_db(double _score,double _weight,int16_t pix_max)106*77c1e3ccSAndroid Build Coastguard Worker static double convert_score_db(double _score, double _weight, int16_t pix_max) {
107*77c1e3ccSAndroid Build Coastguard Worker   assert(_score * _weight >= 0.0);
108*77c1e3ccSAndroid Build Coastguard Worker 
109*77c1e3ccSAndroid Build Coastguard Worker   if (_weight * _score < pix_max * pix_max * 1e-10) return MAX_PSNR;
110*77c1e3ccSAndroid Build Coastguard Worker   return 10 * (log10(pix_max * pix_max) - log10(_weight * _score));
111*77c1e3ccSAndroid Build Coastguard Worker }
112*77c1e3ccSAndroid Build Coastguard Worker 
calc_psnrhvs(const unsigned char * src,int _systride,const unsigned char * dst,int _dystride,double _par,int _w,int _h,int _step,const double _csf[8][8],uint32_t _shift,int buf_is_hbd,int16_t pix_max,int luma)113*77c1e3ccSAndroid Build Coastguard Worker static double calc_psnrhvs(const unsigned char *src, int _systride,
114*77c1e3ccSAndroid Build Coastguard Worker                            const unsigned char *dst, int _dystride, double _par,
115*77c1e3ccSAndroid Build Coastguard Worker                            int _w, int _h, int _step, const double _csf[8][8],
116*77c1e3ccSAndroid Build Coastguard Worker                            uint32_t _shift, int buf_is_hbd, int16_t pix_max,
117*77c1e3ccSAndroid Build Coastguard Worker                            int luma) {
118*77c1e3ccSAndroid Build Coastguard Worker   double ret;
119*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *_src8 = src;
120*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *_dst8 = dst;
121*77c1e3ccSAndroid Build Coastguard Worker   const uint16_t *_src16 = CONVERT_TO_SHORTPTR(src);
122*77c1e3ccSAndroid Build Coastguard Worker   const uint16_t *_dst16 = CONVERT_TO_SHORTPTR(dst);
123*77c1e3ccSAndroid Build Coastguard Worker   DECLARE_ALIGNED(16, int16_t, dct_s[8 * 8]);
124*77c1e3ccSAndroid Build Coastguard Worker   DECLARE_ALIGNED(16, int16_t, dct_d[8 * 8]);
125*77c1e3ccSAndroid Build Coastguard Worker   DECLARE_ALIGNED(16, tran_low_t, dct_s_coef[8 * 8]);
126*77c1e3ccSAndroid Build Coastguard Worker   DECLARE_ALIGNED(16, tran_low_t, dct_d_coef[8 * 8]);
127*77c1e3ccSAndroid Build Coastguard Worker   double mask[8][8];
128*77c1e3ccSAndroid Build Coastguard Worker   int pixels;
129*77c1e3ccSAndroid Build Coastguard Worker   int x;
130*77c1e3ccSAndroid Build Coastguard Worker   int y;
131*77c1e3ccSAndroid Build Coastguard Worker   float sum1;
132*77c1e3ccSAndroid Build Coastguard Worker   float sum2;
133*77c1e3ccSAndroid Build Coastguard Worker   float delt;
134*77c1e3ccSAndroid Build Coastguard Worker   (void)_par;
135*77c1e3ccSAndroid Build Coastguard Worker   ret = pixels = 0;
136*77c1e3ccSAndroid Build Coastguard Worker   sum1 = sum2 = delt = 0.0f;
137*77c1e3ccSAndroid Build Coastguard Worker   for (y = 0; y < _h; y++) {
138*77c1e3ccSAndroid Build Coastguard Worker     for (x = 0; x < _w; x++) {
139*77c1e3ccSAndroid Build Coastguard Worker       if (!buf_is_hbd) {
140*77c1e3ccSAndroid Build Coastguard Worker         sum1 += _src8[y * _systride + x];
141*77c1e3ccSAndroid Build Coastguard Worker         sum2 += _dst8[y * _dystride + x];
142*77c1e3ccSAndroid Build Coastguard Worker       } else {
143*77c1e3ccSAndroid Build Coastguard Worker         sum1 += _src16[y * _systride + x] >> _shift;
144*77c1e3ccSAndroid Build Coastguard Worker         sum2 += _dst16[y * _dystride + x] >> _shift;
145*77c1e3ccSAndroid Build Coastguard Worker       }
146*77c1e3ccSAndroid Build Coastguard Worker     }
147*77c1e3ccSAndroid Build Coastguard Worker   }
148*77c1e3ccSAndroid Build Coastguard Worker   if (luma) delt = (sum1 - sum2) / (_w * _h);
149*77c1e3ccSAndroid Build Coastguard Worker   /*In the PSNR-HVS-M paper[1] the authors describe the construction of
150*77c1e3ccSAndroid Build Coastguard Worker    their masking table as "we have used the quantization table for the
151*77c1e3ccSAndroid Build Coastguard Worker    color component Y of JPEG [6] that has been also obtained on the
152*77c1e3ccSAndroid Build Coastguard Worker    basis of CSF. Note that the values in quantization table JPEG have
153*77c1e3ccSAndroid Build Coastguard Worker    been normalized and then squared." Their CSF matrix (from PSNR-HVS)
154*77c1e3ccSAndroid Build Coastguard Worker    was also constructed from the JPEG matrices. I can not find any obvious
155*77c1e3ccSAndroid Build Coastguard Worker    scheme of normalizing to produce their table, but if I multiply their
156*77c1e3ccSAndroid Build Coastguard Worker    CSF by 0.3885746225901003 and square the result I get their masking table.
157*77c1e3ccSAndroid Build Coastguard Worker    I have no idea where this constant comes from, but deviating from it
158*77c1e3ccSAndroid Build Coastguard Worker    too greatly hurts MOS agreement.
159*77c1e3ccSAndroid Build Coastguard Worker 
160*77c1e3ccSAndroid Build Coastguard Worker    [1] Nikolay Ponomarenko, Flavia Silvestri, Karen Egiazarian, Marco Carli,
161*77c1e3ccSAndroid Build Coastguard Worker    Jaakko Astola, Vladimir Lukin, "On between-coefficient contrast masking
162*77c1e3ccSAndroid Build Coastguard Worker    of DCT basis functions", CD-ROM Proceedings of the Third
163*77c1e3ccSAndroid Build Coastguard Worker    International Workshop on Video Processing and Quality Metrics for Consumer
164*77c1e3ccSAndroid Build Coastguard Worker    Electronics VPQM-07, Scottsdale, Arizona, USA, 25-26 January, 2007, 4 p.
165*77c1e3ccSAndroid Build Coastguard Worker 
166*77c1e3ccSAndroid Build Coastguard Worker    Suggested in aomedia issue#2363:
167*77c1e3ccSAndroid Build Coastguard Worker    0.3885746225901003 is a reciprocal of the maximum coefficient (2.573509)
168*77c1e3ccSAndroid Build Coastguard Worker    of the old JPEG based matrix from the paper. Since you are not using that,
169*77c1e3ccSAndroid Build Coastguard Worker    divide by actual maximum coefficient. */
170*77c1e3ccSAndroid Build Coastguard Worker   for (x = 0; x < 8; x++)
171*77c1e3ccSAndroid Build Coastguard Worker     for (y = 0; y < 8; y++)
172*77c1e3ccSAndroid Build Coastguard Worker       mask[x][y] = (_csf[x][y] / _csf[1][0]) * (_csf[x][y] / _csf[1][0]);
173*77c1e3ccSAndroid Build Coastguard Worker   for (y = 0; y < _h - 7; y += _step) {
174*77c1e3ccSAndroid Build Coastguard Worker     for (x = 0; x < _w - 7; x += _step) {
175*77c1e3ccSAndroid Build Coastguard Worker       int i;
176*77c1e3ccSAndroid Build Coastguard Worker       int j;
177*77c1e3ccSAndroid Build Coastguard Worker       int n = 0;
178*77c1e3ccSAndroid Build Coastguard Worker       double s_gx = 0;
179*77c1e3ccSAndroid Build Coastguard Worker       double s_gy = 0;
180*77c1e3ccSAndroid Build Coastguard Worker       double g = 0;
181*77c1e3ccSAndroid Build Coastguard Worker       double s_gmean = 0;
182*77c1e3ccSAndroid Build Coastguard Worker       double s_gvar = 0;
183*77c1e3ccSAndroid Build Coastguard Worker       double s_mask = 0;
184*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < 8; i++) {
185*77c1e3ccSAndroid Build Coastguard Worker         for (j = 0; j < 8; j++) {
186*77c1e3ccSAndroid Build Coastguard Worker           if (!buf_is_hbd) {
187*77c1e3ccSAndroid Build Coastguard Worker             dct_s[i * 8 + j] = _src8[(y + i) * _systride + (j + x)];
188*77c1e3ccSAndroid Build Coastguard Worker             dct_d[i * 8 + j] = _dst8[(y + i) * _dystride + (j + x)];
189*77c1e3ccSAndroid Build Coastguard Worker           } else {
190*77c1e3ccSAndroid Build Coastguard Worker             dct_s[i * 8 + j] = _src16[(y + i) * _systride + (j + x)] >> _shift;
191*77c1e3ccSAndroid Build Coastguard Worker             dct_d[i * 8 + j] = _dst16[(y + i) * _dystride + (j + x)] >> _shift;
192*77c1e3ccSAndroid Build Coastguard Worker           }
193*77c1e3ccSAndroid Build Coastguard Worker           dct_d[i * 8 + j] += (int)(delt + 0.5f);
194*77c1e3ccSAndroid Build Coastguard Worker         }
195*77c1e3ccSAndroid Build Coastguard Worker       }
196*77c1e3ccSAndroid Build Coastguard Worker       for (i = 1; i < 7; i++) {
197*77c1e3ccSAndroid Build Coastguard Worker         for (j = 1; j < 7; j++) {
198*77c1e3ccSAndroid Build Coastguard Worker           s_gx = (dct_s[(i - 1) * 8 + j - 1] * 3 -
199*77c1e3ccSAndroid Build Coastguard Worker                   dct_s[(i - 1) * 8 + j + 1] * 3 + dct_s[i * 8 + j - 1] * 10 -
200*77c1e3ccSAndroid Build Coastguard Worker                   dct_s[i * 8 + j + 1] * 10 + dct_s[(i + 1) * 8 + j - 1] * 3 -
201*77c1e3ccSAndroid Build Coastguard Worker                   dct_s[(i + 1) * 8 + j + 1] * 3) /
202*77c1e3ccSAndroid Build Coastguard Worker                  (pix_max * 16.f);
203*77c1e3ccSAndroid Build Coastguard Worker           s_gy = (dct_s[(i - 1) * 8 + j - 1] * 3 -
204*77c1e3ccSAndroid Build Coastguard Worker                   dct_s[(i + 1) * 8 + j - 1] * 3 + dct_s[(i - 1) * 8 + j] * 10 -
205*77c1e3ccSAndroid Build Coastguard Worker                   dct_s[(i + 1) * 8 + j] * 10 + dct_s[(i - 1) * 8 + j + 1] * 3 -
206*77c1e3ccSAndroid Build Coastguard Worker                   dct_s[(i + 1) * 8 + j + 1] * 3) /
207*77c1e3ccSAndroid Build Coastguard Worker                  (pix_max * 16.f);
208*77c1e3ccSAndroid Build Coastguard Worker           g = sqrt(s_gx * s_gx + s_gy * s_gy);
209*77c1e3ccSAndroid Build Coastguard Worker           if (g > 0.1f) n++;
210*77c1e3ccSAndroid Build Coastguard Worker           s_gmean += g;
211*77c1e3ccSAndroid Build Coastguard Worker         }
212*77c1e3ccSAndroid Build Coastguard Worker       }
213*77c1e3ccSAndroid Build Coastguard Worker       s_gvar = 1.f / (36 - n + 1) * s_gmean / 36.f;
214*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_HIGHBITDEPTH
215*77c1e3ccSAndroid Build Coastguard Worker       if (!buf_is_hbd) {
216*77c1e3ccSAndroid Build Coastguard Worker         od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
217*77c1e3ccSAndroid Build Coastguard Worker         od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
218*77c1e3ccSAndroid Build Coastguard Worker       } else {
219*77c1e3ccSAndroid Build Coastguard Worker         hbd_od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
220*77c1e3ccSAndroid Build Coastguard Worker         hbd_od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
221*77c1e3ccSAndroid Build Coastguard Worker       }
222*77c1e3ccSAndroid Build Coastguard Worker #else
223*77c1e3ccSAndroid Build Coastguard Worker       od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
224*77c1e3ccSAndroid Build Coastguard Worker       od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
225*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_AV1_HIGHBITDEPTH
226*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < 8; i++)
227*77c1e3ccSAndroid Build Coastguard Worker         for (j = (i == 0); j < 8; j++)
228*77c1e3ccSAndroid Build Coastguard Worker           s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j];
229*77c1e3ccSAndroid Build Coastguard Worker       s_mask = sqrt(s_mask * s_gvar) / 8.f;
230*77c1e3ccSAndroid Build Coastguard Worker       for (i = 0; i < 8; i++) {
231*77c1e3ccSAndroid Build Coastguard Worker         for (j = 0; j < 8; j++) {
232*77c1e3ccSAndroid Build Coastguard Worker           double err;
233*77c1e3ccSAndroid Build Coastguard Worker           err = fabs((double)(dct_s_coef[i * 8 + j] - dct_d_coef[i * 8 + j]));
234*77c1e3ccSAndroid Build Coastguard Worker           if (i != 0 || j != 0)
235*77c1e3ccSAndroid Build Coastguard Worker             err = err < s_mask / mask[i][j] ? 0 : err - s_mask / mask[i][j];
236*77c1e3ccSAndroid Build Coastguard Worker           ret += (err * _csf[i][j]) * (err * _csf[i][j]);
237*77c1e3ccSAndroid Build Coastguard Worker           pixels++;
238*77c1e3ccSAndroid Build Coastguard Worker         }
239*77c1e3ccSAndroid Build Coastguard Worker       }
240*77c1e3ccSAndroid Build Coastguard Worker     }
241*77c1e3ccSAndroid Build Coastguard Worker   }
242*77c1e3ccSAndroid Build Coastguard Worker   if (pixels <= 0) return 0;
243*77c1e3ccSAndroid Build Coastguard Worker   ret /= pixels;
244*77c1e3ccSAndroid Build Coastguard Worker   ret += 0.04 * delt * delt;
245*77c1e3ccSAndroid Build Coastguard Worker   return ret;
246*77c1e3ccSAndroid Build Coastguard Worker }
247*77c1e3ccSAndroid Build Coastguard Worker 
aom_psnrhvs(const YV12_BUFFER_CONFIG * src,const YV12_BUFFER_CONFIG * dst,double * y_psnrhvs,double * u_psnrhvs,double * v_psnrhvs,uint32_t bd,uint32_t in_bd)248*77c1e3ccSAndroid Build Coastguard Worker double aom_psnrhvs(const YV12_BUFFER_CONFIG *src, const YV12_BUFFER_CONFIG *dst,
249*77c1e3ccSAndroid Build Coastguard Worker                    double *y_psnrhvs, double *u_psnrhvs, double *v_psnrhvs,
250*77c1e3ccSAndroid Build Coastguard Worker                    uint32_t bd, uint32_t in_bd) {
251*77c1e3ccSAndroid Build Coastguard Worker   double psnrhvs;
252*77c1e3ccSAndroid Build Coastguard Worker   const double par = 1.0;
253*77c1e3ccSAndroid Build Coastguard Worker   const int step = 7;
254*77c1e3ccSAndroid Build Coastguard Worker   uint32_t bd_shift = 0;
255*77c1e3ccSAndroid Build Coastguard Worker   assert(bd == 8 || bd == 10 || bd == 12);
256*77c1e3ccSAndroid Build Coastguard Worker   assert(bd >= in_bd);
257*77c1e3ccSAndroid Build Coastguard Worker   assert(src->flags == dst->flags);
258*77c1e3ccSAndroid Build Coastguard Worker   const int buf_is_hbd = src->flags & YV12_FLAG_HIGHBITDEPTH;
259*77c1e3ccSAndroid Build Coastguard Worker 
260*77c1e3ccSAndroid Build Coastguard Worker   int16_t pix_max = 255;
261*77c1e3ccSAndroid Build Coastguard Worker   if (in_bd == 10)
262*77c1e3ccSAndroid Build Coastguard Worker     pix_max = 1023;
263*77c1e3ccSAndroid Build Coastguard Worker   else if (in_bd == 12)
264*77c1e3ccSAndroid Build Coastguard Worker     pix_max = 4095;
265*77c1e3ccSAndroid Build Coastguard Worker 
266*77c1e3ccSAndroid Build Coastguard Worker   bd_shift = bd - in_bd;
267*77c1e3ccSAndroid Build Coastguard Worker 
268*77c1e3ccSAndroid Build Coastguard Worker   *y_psnrhvs =
269*77c1e3ccSAndroid Build Coastguard Worker       calc_psnrhvs(src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride,
270*77c1e3ccSAndroid Build Coastguard Worker                    par, src->y_crop_width, src->y_crop_height, step, csf_y,
271*77c1e3ccSAndroid Build Coastguard Worker                    bd_shift, buf_is_hbd, pix_max, 1);
272*77c1e3ccSAndroid Build Coastguard Worker   *u_psnrhvs =
273*77c1e3ccSAndroid Build Coastguard Worker       calc_psnrhvs(src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride,
274*77c1e3ccSAndroid Build Coastguard Worker                    par, src->uv_crop_width, src->uv_crop_height, step,
275*77c1e3ccSAndroid Build Coastguard Worker                    csf_cb420, bd_shift, buf_is_hbd, pix_max, 0);
276*77c1e3ccSAndroid Build Coastguard Worker   *v_psnrhvs =
277*77c1e3ccSAndroid Build Coastguard Worker       calc_psnrhvs(src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride,
278*77c1e3ccSAndroid Build Coastguard Worker                    par, src->uv_crop_width, src->uv_crop_height, step,
279*77c1e3ccSAndroid Build Coastguard Worker                    csf_cr420, bd_shift, buf_is_hbd, pix_max, 0);
280*77c1e3ccSAndroid Build Coastguard Worker   psnrhvs = (*y_psnrhvs) * .8 + .1 * ((*u_psnrhvs) + (*v_psnrhvs));
281*77c1e3ccSAndroid Build Coastguard Worker   return convert_score_db(psnrhvs, 1.0, pix_max);
282*77c1e3ccSAndroid Build Coastguard Worker }
283