xref: /aosp_15_r20/external/libvpx/tools/tiny_ssim.c (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker  *  Copyright (c) 2016 The WebM project authors. All Rights Reserved.
3*fb1b10abSAndroid Build Coastguard Worker  *
4*fb1b10abSAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker  */
10*fb1b10abSAndroid Build Coastguard Worker 
11*fb1b10abSAndroid Build Coastguard Worker #include <assert.h>
12*fb1b10abSAndroid Build Coastguard Worker #include <errno.h>
13*fb1b10abSAndroid Build Coastguard Worker #include <math.h>
14*fb1b10abSAndroid Build Coastguard Worker #include <stdio.h>
15*fb1b10abSAndroid Build Coastguard Worker #include <stdlib.h>
16*fb1b10abSAndroid Build Coastguard Worker #include <string.h>
17*fb1b10abSAndroid Build Coastguard Worker #include "vpx/vpx_codec.h"
18*fb1b10abSAndroid Build Coastguard Worker #include "vpx/vpx_integer.h"
19*fb1b10abSAndroid Build Coastguard Worker #include "./y4minput.h"
20*fb1b10abSAndroid Build Coastguard Worker #include "vpx_dsp/ssim.h"
21*fb1b10abSAndroid Build Coastguard Worker #include "vpx_ports/mem.h"
22*fb1b10abSAndroid Build Coastguard Worker 
23*fb1b10abSAndroid Build Coastguard Worker static const int64_t cc1 = 26634;        // (64^2*(.01*255)^2
24*fb1b10abSAndroid Build Coastguard Worker static const int64_t cc2 = 239708;       // (64^2*(.03*255)^2
25*fb1b10abSAndroid Build Coastguard Worker static const int64_t cc1_10 = 428658;    // (64^2*(.01*1023)^2
26*fb1b10abSAndroid Build Coastguard Worker static const int64_t cc2_10 = 3857925;   // (64^2*(.03*1023)^2
27*fb1b10abSAndroid Build Coastguard Worker static const int64_t cc1_12 = 6868593;   // (64^2*(.01*4095)^2
28*fb1b10abSAndroid Build Coastguard Worker static const int64_t cc2_12 = 61817334;  // (64^2*(.03*4095)^2
29*fb1b10abSAndroid Build Coastguard Worker 
30*fb1b10abSAndroid Build Coastguard Worker #if CONFIG_VP9_HIGHBITDEPTH
calc_plane_error16(uint16_t * orig,int orig_stride,uint16_t * recon,int recon_stride,unsigned int cols,unsigned int rows)31*fb1b10abSAndroid Build Coastguard Worker static uint64_t calc_plane_error16(uint16_t *orig, int orig_stride,
32*fb1b10abSAndroid Build Coastguard Worker                                    uint16_t *recon, int recon_stride,
33*fb1b10abSAndroid Build Coastguard Worker                                    unsigned int cols, unsigned int rows) {
34*fb1b10abSAndroid Build Coastguard Worker   unsigned int row, col;
35*fb1b10abSAndroid Build Coastguard Worker   uint64_t total_sse = 0;
36*fb1b10abSAndroid Build Coastguard Worker   int diff;
37*fb1b10abSAndroid Build Coastguard Worker   if (orig == NULL || recon == NULL) {
38*fb1b10abSAndroid Build Coastguard Worker     assert(0);
39*fb1b10abSAndroid Build Coastguard Worker     return 0;
40*fb1b10abSAndroid Build Coastguard Worker   }
41*fb1b10abSAndroid Build Coastguard Worker 
42*fb1b10abSAndroid Build Coastguard Worker   for (row = 0; row < rows; row++) {
43*fb1b10abSAndroid Build Coastguard Worker     for (col = 0; col < cols; col++) {
44*fb1b10abSAndroid Build Coastguard Worker       diff = orig[col] - recon[col];
45*fb1b10abSAndroid Build Coastguard Worker       total_sse += diff * diff;
46*fb1b10abSAndroid Build Coastguard Worker     }
47*fb1b10abSAndroid Build Coastguard Worker 
48*fb1b10abSAndroid Build Coastguard Worker     orig += orig_stride;
49*fb1b10abSAndroid Build Coastguard Worker     recon += recon_stride;
50*fb1b10abSAndroid Build Coastguard Worker   }
51*fb1b10abSAndroid Build Coastguard Worker   return total_sse;
52*fb1b10abSAndroid Build Coastguard Worker }
53*fb1b10abSAndroid Build Coastguard Worker #endif  // CONFIG_VP9_HIGHBITDEPTH
54*fb1b10abSAndroid Build Coastguard Worker 
calc_plane_error(uint8_t * orig,int orig_stride,uint8_t * recon,int recon_stride,unsigned int cols,unsigned int rows)55*fb1b10abSAndroid Build Coastguard Worker static uint64_t calc_plane_error(uint8_t *orig, int orig_stride, uint8_t *recon,
56*fb1b10abSAndroid Build Coastguard Worker                                  int recon_stride, unsigned int cols,
57*fb1b10abSAndroid Build Coastguard Worker                                  unsigned int rows) {
58*fb1b10abSAndroid Build Coastguard Worker   unsigned int row, col;
59*fb1b10abSAndroid Build Coastguard Worker   uint64_t total_sse = 0;
60*fb1b10abSAndroid Build Coastguard Worker   int diff;
61*fb1b10abSAndroid Build Coastguard Worker   if (orig == NULL || recon == NULL) {
62*fb1b10abSAndroid Build Coastguard Worker     assert(0);
63*fb1b10abSAndroid Build Coastguard Worker     return 0;
64*fb1b10abSAndroid Build Coastguard Worker   }
65*fb1b10abSAndroid Build Coastguard Worker 
66*fb1b10abSAndroid Build Coastguard Worker   for (row = 0; row < rows; row++) {
67*fb1b10abSAndroid Build Coastguard Worker     for (col = 0; col < cols; col++) {
68*fb1b10abSAndroid Build Coastguard Worker       diff = orig[col] - recon[col];
69*fb1b10abSAndroid Build Coastguard Worker       total_sse += diff * diff;
70*fb1b10abSAndroid Build Coastguard Worker     }
71*fb1b10abSAndroid Build Coastguard Worker 
72*fb1b10abSAndroid Build Coastguard Worker     orig += orig_stride;
73*fb1b10abSAndroid Build Coastguard Worker     recon += recon_stride;
74*fb1b10abSAndroid Build Coastguard Worker   }
75*fb1b10abSAndroid Build Coastguard Worker   return total_sse;
76*fb1b10abSAndroid Build Coastguard Worker }
77*fb1b10abSAndroid Build Coastguard Worker 
78*fb1b10abSAndroid Build Coastguard Worker #define MAX_PSNR 100
mse2psnr(double samples,double peak,double mse)79*fb1b10abSAndroid Build Coastguard Worker static double mse2psnr(double samples, double peak, double mse) {
80*fb1b10abSAndroid Build Coastguard Worker   double psnr;
81*fb1b10abSAndroid Build Coastguard Worker 
82*fb1b10abSAndroid Build Coastguard Worker   if (mse > 0.0)
83*fb1b10abSAndroid Build Coastguard Worker     psnr = 10.0 * log10(peak * peak * samples / mse);
84*fb1b10abSAndroid Build Coastguard Worker   else
85*fb1b10abSAndroid Build Coastguard Worker     psnr = MAX_PSNR;  // Limit to prevent / 0
86*fb1b10abSAndroid Build Coastguard Worker 
87*fb1b10abSAndroid Build Coastguard Worker   if (psnr > MAX_PSNR) psnr = MAX_PSNR;
88*fb1b10abSAndroid Build Coastguard Worker 
89*fb1b10abSAndroid Build Coastguard Worker   return psnr;
90*fb1b10abSAndroid Build Coastguard Worker }
91*fb1b10abSAndroid Build Coastguard Worker 
92*fb1b10abSAndroid Build Coastguard Worker typedef enum { RAW_YUV, Y4M } input_file_type;
93*fb1b10abSAndroid Build Coastguard Worker 
94*fb1b10abSAndroid Build Coastguard Worker typedef struct input_file {
95*fb1b10abSAndroid Build Coastguard Worker   FILE *file;
96*fb1b10abSAndroid Build Coastguard Worker   input_file_type type;
97*fb1b10abSAndroid Build Coastguard Worker   unsigned char *buf;
98*fb1b10abSAndroid Build Coastguard Worker   y4m_input y4m;
99*fb1b10abSAndroid Build Coastguard Worker   vpx_image_t img;
100*fb1b10abSAndroid Build Coastguard Worker   int w;
101*fb1b10abSAndroid Build Coastguard Worker   int h;
102*fb1b10abSAndroid Build Coastguard Worker   int bit_depth;
103*fb1b10abSAndroid Build Coastguard Worker   int frame_size;
104*fb1b10abSAndroid Build Coastguard Worker } input_file_t;
105*fb1b10abSAndroid Build Coastguard Worker 
106*fb1b10abSAndroid Build Coastguard Worker // Open a file and determine if its y4m or raw.  If y4m get the header.
open_input_file(const char * file_name,input_file_t * input,int w,int h,int bit_depth)107*fb1b10abSAndroid Build Coastguard Worker static int open_input_file(const char *file_name, input_file_t *input, int w,
108*fb1b10abSAndroid Build Coastguard Worker                            int h, int bit_depth) {
109*fb1b10abSAndroid Build Coastguard Worker   char y4m_buf[4];
110*fb1b10abSAndroid Build Coastguard Worker   input->w = w;
111*fb1b10abSAndroid Build Coastguard Worker   input->h = h;
112*fb1b10abSAndroid Build Coastguard Worker   input->bit_depth = bit_depth;
113*fb1b10abSAndroid Build Coastguard Worker   input->type = RAW_YUV;
114*fb1b10abSAndroid Build Coastguard Worker   input->buf = NULL;
115*fb1b10abSAndroid Build Coastguard Worker   input->file = strcmp(file_name, "-") ? fopen(file_name, "rb") : stdin;
116*fb1b10abSAndroid Build Coastguard Worker   if (input->file == NULL) return -1;
117*fb1b10abSAndroid Build Coastguard Worker   if (fread(y4m_buf, 1, 4, input->file) != 4) return -1;
118*fb1b10abSAndroid Build Coastguard Worker   if (memcmp(y4m_buf, "YUV4", 4) == 0) input->type = Y4M;
119*fb1b10abSAndroid Build Coastguard Worker   switch (input->type) {
120*fb1b10abSAndroid Build Coastguard Worker     case Y4M:
121*fb1b10abSAndroid Build Coastguard Worker       y4m_input_open(&input->y4m, input->file, y4m_buf, 4, 0);
122*fb1b10abSAndroid Build Coastguard Worker       input->w = input->y4m.pic_w;
123*fb1b10abSAndroid Build Coastguard Worker       input->h = input->y4m.pic_h;
124*fb1b10abSAndroid Build Coastguard Worker       input->bit_depth = input->y4m.bit_depth;
125*fb1b10abSAndroid Build Coastguard Worker       // Y4M alloc's its own buf. Init this to avoid problems if we never
126*fb1b10abSAndroid Build Coastguard Worker       // read frames.
127*fb1b10abSAndroid Build Coastguard Worker       memset(&input->img, 0, sizeof(input->img));
128*fb1b10abSAndroid Build Coastguard Worker       break;
129*fb1b10abSAndroid Build Coastguard Worker     case RAW_YUV:
130*fb1b10abSAndroid Build Coastguard Worker       fseek(input->file, 0, SEEK_SET);
131*fb1b10abSAndroid Build Coastguard Worker       input->w = w;
132*fb1b10abSAndroid Build Coastguard Worker       input->h = h;
133*fb1b10abSAndroid Build Coastguard Worker       // handle odd frame sizes
134*fb1b10abSAndroid Build Coastguard Worker       input->frame_size = w * h + ((w + 1) / 2) * ((h + 1) / 2) * 2;
135*fb1b10abSAndroid Build Coastguard Worker       if (bit_depth > 8) {
136*fb1b10abSAndroid Build Coastguard Worker         input->frame_size *= 2;
137*fb1b10abSAndroid Build Coastguard Worker       }
138*fb1b10abSAndroid Build Coastguard Worker       input->buf = malloc(input->frame_size);
139*fb1b10abSAndroid Build Coastguard Worker       break;
140*fb1b10abSAndroid Build Coastguard Worker   }
141*fb1b10abSAndroid Build Coastguard Worker   return 0;
142*fb1b10abSAndroid Build Coastguard Worker }
143*fb1b10abSAndroid Build Coastguard Worker 
close_input_file(input_file_t * in)144*fb1b10abSAndroid Build Coastguard Worker static void close_input_file(input_file_t *in) {
145*fb1b10abSAndroid Build Coastguard Worker   if (in->file) fclose(in->file);
146*fb1b10abSAndroid Build Coastguard Worker   if (in->type == Y4M) {
147*fb1b10abSAndroid Build Coastguard Worker     vpx_img_free(&in->img);
148*fb1b10abSAndroid Build Coastguard Worker   } else {
149*fb1b10abSAndroid Build Coastguard Worker     free(in->buf);
150*fb1b10abSAndroid Build Coastguard Worker   }
151*fb1b10abSAndroid Build Coastguard Worker }
152*fb1b10abSAndroid Build Coastguard Worker 
153*fb1b10abSAndroid Build Coastguard Worker // Returns 1 on success, 0 on failure due to a read error or eof (or format
154*fb1b10abSAndroid Build Coastguard Worker // error in the case of y4m).
read_input_file(input_file_t * in,unsigned char ** y,unsigned char ** u,unsigned char ** v,int bd)155*fb1b10abSAndroid Build Coastguard Worker static int read_input_file(input_file_t *in, unsigned char **y,
156*fb1b10abSAndroid Build Coastguard Worker                            unsigned char **u, unsigned char **v, int bd) {
157*fb1b10abSAndroid Build Coastguard Worker   size_t r1 = 0;
158*fb1b10abSAndroid Build Coastguard Worker   switch (in->type) {
159*fb1b10abSAndroid Build Coastguard Worker     case Y4M:
160*fb1b10abSAndroid Build Coastguard Worker       r1 = y4m_input_fetch_frame(&in->y4m, in->file, &in->img);
161*fb1b10abSAndroid Build Coastguard Worker       if (r1 == (size_t)-1) return 0;
162*fb1b10abSAndroid Build Coastguard Worker       *y = in->img.planes[0];
163*fb1b10abSAndroid Build Coastguard Worker       *u = in->img.planes[1];
164*fb1b10abSAndroid Build Coastguard Worker       *v = in->img.planes[2];
165*fb1b10abSAndroid Build Coastguard Worker       break;
166*fb1b10abSAndroid Build Coastguard Worker     case RAW_YUV:
167*fb1b10abSAndroid Build Coastguard Worker       if (bd < 9) {
168*fb1b10abSAndroid Build Coastguard Worker         r1 = fread(in->buf, in->frame_size, 1, in->file);
169*fb1b10abSAndroid Build Coastguard Worker         *y = in->buf;
170*fb1b10abSAndroid Build Coastguard Worker         *u = in->buf + in->w * in->h;
171*fb1b10abSAndroid Build Coastguard Worker         *v = *u + ((1 + in->w) / 2) * ((1 + in->h) / 2);
172*fb1b10abSAndroid Build Coastguard Worker       } else {
173*fb1b10abSAndroid Build Coastguard Worker         r1 = fread(in->buf, in->frame_size, 1, in->file);
174*fb1b10abSAndroid Build Coastguard Worker         *y = in->buf;
175*fb1b10abSAndroid Build Coastguard Worker         *u = in->buf + (in->w * in->h) * 2;
176*fb1b10abSAndroid Build Coastguard Worker         *v = *u + 2 * ((1 + in->w) / 2) * ((1 + in->h) / 2);
177*fb1b10abSAndroid Build Coastguard Worker       }
178*fb1b10abSAndroid Build Coastguard Worker       break;
179*fb1b10abSAndroid Build Coastguard Worker   }
180*fb1b10abSAndroid Build Coastguard Worker 
181*fb1b10abSAndroid Build Coastguard Worker   return r1 != 0;
182*fb1b10abSAndroid Build Coastguard Worker }
183*fb1b10abSAndroid Build Coastguard Worker 
ssim_parms_8x8(const uint8_t * s,int sp,const uint8_t * r,int rp,uint32_t * sum_s,uint32_t * sum_r,uint32_t * sum_sq_s,uint32_t * sum_sq_r,uint32_t * sum_sxr)184*fb1b10abSAndroid Build Coastguard Worker static void ssim_parms_8x8(const uint8_t *s, int sp, const uint8_t *r, int rp,
185*fb1b10abSAndroid Build Coastguard Worker                            uint32_t *sum_s, uint32_t *sum_r, uint32_t *sum_sq_s,
186*fb1b10abSAndroid Build Coastguard Worker                            uint32_t *sum_sq_r, uint32_t *sum_sxr) {
187*fb1b10abSAndroid Build Coastguard Worker   int i, j;
188*fb1b10abSAndroid Build Coastguard Worker   if (s == NULL || r == NULL || sum_s == NULL || sum_r == NULL ||
189*fb1b10abSAndroid Build Coastguard Worker       sum_sq_s == NULL || sum_sq_r == NULL || sum_sxr == NULL) {
190*fb1b10abSAndroid Build Coastguard Worker     assert(0);
191*fb1b10abSAndroid Build Coastguard Worker     return;
192*fb1b10abSAndroid Build Coastguard Worker   }
193*fb1b10abSAndroid Build Coastguard Worker   for (i = 0; i < 8; i++, s += sp, r += rp) {
194*fb1b10abSAndroid Build Coastguard Worker     for (j = 0; j < 8; j++) {
195*fb1b10abSAndroid Build Coastguard Worker       *sum_s += s[j];
196*fb1b10abSAndroid Build Coastguard Worker       *sum_r += r[j];
197*fb1b10abSAndroid Build Coastguard Worker       *sum_sq_s += s[j] * s[j];
198*fb1b10abSAndroid Build Coastguard Worker       *sum_sq_r += r[j] * r[j];
199*fb1b10abSAndroid Build Coastguard Worker       *sum_sxr += s[j] * r[j];
200*fb1b10abSAndroid Build Coastguard Worker     }
201*fb1b10abSAndroid Build Coastguard Worker   }
202*fb1b10abSAndroid Build Coastguard Worker }
203*fb1b10abSAndroid Build Coastguard Worker 
204*fb1b10abSAndroid Build Coastguard Worker #if CONFIG_VP9_HIGHBITDEPTH
highbd_ssim_parms_8x8(const uint16_t * s,int sp,const uint16_t * r,int rp,uint32_t * sum_s,uint32_t * sum_r,uint32_t * sum_sq_s,uint32_t * sum_sq_r,uint32_t * sum_sxr)205*fb1b10abSAndroid Build Coastguard Worker static void highbd_ssim_parms_8x8(const uint16_t *s, int sp, const uint16_t *r,
206*fb1b10abSAndroid Build Coastguard Worker                                   int rp, uint32_t *sum_s, uint32_t *sum_r,
207*fb1b10abSAndroid Build Coastguard Worker                                   uint32_t *sum_sq_s, uint32_t *sum_sq_r,
208*fb1b10abSAndroid Build Coastguard Worker                                   uint32_t *sum_sxr) {
209*fb1b10abSAndroid Build Coastguard Worker   int i, j;
210*fb1b10abSAndroid Build Coastguard Worker   if (s == NULL || r == NULL || sum_s == NULL || sum_r == NULL ||
211*fb1b10abSAndroid Build Coastguard Worker       sum_sq_s == NULL || sum_sq_r == NULL || sum_sxr == NULL) {
212*fb1b10abSAndroid Build Coastguard Worker     assert(0);
213*fb1b10abSAndroid Build Coastguard Worker     return;
214*fb1b10abSAndroid Build Coastguard Worker   }
215*fb1b10abSAndroid Build Coastguard Worker   for (i = 0; i < 8; i++, s += sp, r += rp) {
216*fb1b10abSAndroid Build Coastguard Worker     for (j = 0; j < 8; j++) {
217*fb1b10abSAndroid Build Coastguard Worker       *sum_s += s[j];
218*fb1b10abSAndroid Build Coastguard Worker       *sum_r += r[j];
219*fb1b10abSAndroid Build Coastguard Worker       *sum_sq_s += s[j] * s[j];
220*fb1b10abSAndroid Build Coastguard Worker       *sum_sq_r += r[j] * r[j];
221*fb1b10abSAndroid Build Coastguard Worker       *sum_sxr += s[j] * r[j];
222*fb1b10abSAndroid Build Coastguard Worker     }
223*fb1b10abSAndroid Build Coastguard Worker   }
224*fb1b10abSAndroid Build Coastguard Worker }
225*fb1b10abSAndroid Build Coastguard Worker #endif  // CONFIG_VP9_HIGHBITDEPTH
226*fb1b10abSAndroid Build Coastguard Worker 
similarity(uint32_t sum_s,uint32_t sum_r,uint32_t sum_sq_s,uint32_t sum_sq_r,uint32_t sum_sxr,int count,uint32_t bd)227*fb1b10abSAndroid Build Coastguard Worker static double similarity(uint32_t sum_s, uint32_t sum_r, uint32_t sum_sq_s,
228*fb1b10abSAndroid Build Coastguard Worker                          uint32_t sum_sq_r, uint32_t sum_sxr, int count,
229*fb1b10abSAndroid Build Coastguard Worker                          uint32_t bd) {
230*fb1b10abSAndroid Build Coastguard Worker   double ssim_n, ssim_d;
231*fb1b10abSAndroid Build Coastguard Worker   int64_t c1 = 0, c2 = 0;
232*fb1b10abSAndroid Build Coastguard Worker   if (bd == 8) {
233*fb1b10abSAndroid Build Coastguard Worker     // scale the constants by number of pixels
234*fb1b10abSAndroid Build Coastguard Worker     c1 = (cc1 * count * count) >> 12;
235*fb1b10abSAndroid Build Coastguard Worker     c2 = (cc2 * count * count) >> 12;
236*fb1b10abSAndroid Build Coastguard Worker   } else if (bd == 10) {
237*fb1b10abSAndroid Build Coastguard Worker     c1 = (cc1_10 * count * count) >> 12;
238*fb1b10abSAndroid Build Coastguard Worker     c2 = (cc2_10 * count * count) >> 12;
239*fb1b10abSAndroid Build Coastguard Worker   } else if (bd == 12) {
240*fb1b10abSAndroid Build Coastguard Worker     c1 = (cc1_12 * count * count) >> 12;
241*fb1b10abSAndroid Build Coastguard Worker     c2 = (cc2_12 * count * count) >> 12;
242*fb1b10abSAndroid Build Coastguard Worker   } else {
243*fb1b10abSAndroid Build Coastguard Worker     assert(0);
244*fb1b10abSAndroid Build Coastguard Worker   }
245*fb1b10abSAndroid Build Coastguard Worker 
246*fb1b10abSAndroid Build Coastguard Worker   ssim_n = (2.0 * sum_s * sum_r + c1) *
247*fb1b10abSAndroid Build Coastguard Worker            (2.0 * count * sum_sxr - 2.0 * sum_s * sum_r + c2);
248*fb1b10abSAndroid Build Coastguard Worker 
249*fb1b10abSAndroid Build Coastguard Worker   ssim_d = ((double)sum_s * sum_s + (double)sum_r * sum_r + c1) *
250*fb1b10abSAndroid Build Coastguard Worker            ((double)count * sum_sq_s - (double)sum_s * sum_s +
251*fb1b10abSAndroid Build Coastguard Worker             (double)count * sum_sq_r - (double)sum_r * sum_r + c2);
252*fb1b10abSAndroid Build Coastguard Worker 
253*fb1b10abSAndroid Build Coastguard Worker   return ssim_n / ssim_d;
254*fb1b10abSAndroid Build Coastguard Worker }
255*fb1b10abSAndroid Build Coastguard Worker 
ssim_8x8(const uint8_t * s,int sp,const uint8_t * r,int rp)256*fb1b10abSAndroid Build Coastguard Worker static double ssim_8x8(const uint8_t *s, int sp, const uint8_t *r, int rp) {
257*fb1b10abSAndroid Build Coastguard Worker   uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
258*fb1b10abSAndroid Build Coastguard Worker   ssim_parms_8x8(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr);
259*fb1b10abSAndroid Build Coastguard Worker   return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64, 8);
260*fb1b10abSAndroid Build Coastguard Worker }
261*fb1b10abSAndroid Build Coastguard Worker 
262*fb1b10abSAndroid Build Coastguard Worker #if CONFIG_VP9_HIGHBITDEPTH
highbd_ssim_8x8(const uint16_t * s,int sp,const uint16_t * r,int rp,uint32_t bd)263*fb1b10abSAndroid Build Coastguard Worker static double highbd_ssim_8x8(const uint16_t *s, int sp, const uint16_t *r,
264*fb1b10abSAndroid Build Coastguard Worker                               int rp, uint32_t bd) {
265*fb1b10abSAndroid Build Coastguard Worker   uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
266*fb1b10abSAndroid Build Coastguard Worker   highbd_ssim_parms_8x8(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r,
267*fb1b10abSAndroid Build Coastguard Worker                         &sum_sxr);
268*fb1b10abSAndroid Build Coastguard Worker   return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64, bd);
269*fb1b10abSAndroid Build Coastguard Worker }
270*fb1b10abSAndroid Build Coastguard Worker #endif  // CONFIG_VP9_HIGHBITDEPTH
271*fb1b10abSAndroid Build Coastguard Worker 
272*fb1b10abSAndroid Build Coastguard Worker // We are using a 8x8 moving window with starting location of each 8x8 window
273*fb1b10abSAndroid Build Coastguard Worker // on the 4x4 pixel grid. Such arrangement allows the windows to overlap
274*fb1b10abSAndroid Build Coastguard Worker // block boundaries to penalize blocking artifacts.
ssim2(const uint8_t * img1,const uint8_t * img2,int stride_img1,int stride_img2,int width,int height)275*fb1b10abSAndroid Build Coastguard Worker static double ssim2(const uint8_t *img1, const uint8_t *img2, int stride_img1,
276*fb1b10abSAndroid Build Coastguard Worker                     int stride_img2, int width, int height) {
277*fb1b10abSAndroid Build Coastguard Worker   int i, j;
278*fb1b10abSAndroid Build Coastguard Worker   int samples = 0;
279*fb1b10abSAndroid Build Coastguard Worker   double ssim_total = 0;
280*fb1b10abSAndroid Build Coastguard Worker 
281*fb1b10abSAndroid Build Coastguard Worker   // sample point start with each 4x4 location
282*fb1b10abSAndroid Build Coastguard Worker   for (i = 0; i <= height - 8;
283*fb1b10abSAndroid Build Coastguard Worker        i += 4, img1 += stride_img1 * 4, img2 += stride_img2 * 4) {
284*fb1b10abSAndroid Build Coastguard Worker     for (j = 0; j <= width - 8; j += 4) {
285*fb1b10abSAndroid Build Coastguard Worker       double v = ssim_8x8(img1 + j, stride_img1, img2 + j, stride_img2);
286*fb1b10abSAndroid Build Coastguard Worker       ssim_total += v;
287*fb1b10abSAndroid Build Coastguard Worker       samples++;
288*fb1b10abSAndroid Build Coastguard Worker     }
289*fb1b10abSAndroid Build Coastguard Worker   }
290*fb1b10abSAndroid Build Coastguard Worker   ssim_total /= samples;
291*fb1b10abSAndroid Build Coastguard Worker   return ssim_total;
292*fb1b10abSAndroid Build Coastguard Worker }
293*fb1b10abSAndroid Build Coastguard Worker 
294*fb1b10abSAndroid Build Coastguard Worker #if CONFIG_VP9_HIGHBITDEPTH
highbd_ssim2(const uint8_t * img1,const uint8_t * img2,int stride_img1,int stride_img2,int width,int height,uint32_t bd)295*fb1b10abSAndroid Build Coastguard Worker static double highbd_ssim2(const uint8_t *img1, const uint8_t *img2,
296*fb1b10abSAndroid Build Coastguard Worker                            int stride_img1, int stride_img2, int width,
297*fb1b10abSAndroid Build Coastguard Worker                            int height, uint32_t bd) {
298*fb1b10abSAndroid Build Coastguard Worker   int i, j;
299*fb1b10abSAndroid Build Coastguard Worker   int samples = 0;
300*fb1b10abSAndroid Build Coastguard Worker   double ssim_total = 0;
301*fb1b10abSAndroid Build Coastguard Worker 
302*fb1b10abSAndroid Build Coastguard Worker   // sample point start with each 4x4 location
303*fb1b10abSAndroid Build Coastguard Worker   for (i = 0; i <= height - 8;
304*fb1b10abSAndroid Build Coastguard Worker        i += 4, img1 += stride_img1 * 4, img2 += stride_img2 * 4) {
305*fb1b10abSAndroid Build Coastguard Worker     for (j = 0; j <= width - 8; j += 4) {
306*fb1b10abSAndroid Build Coastguard Worker       double v =
307*fb1b10abSAndroid Build Coastguard Worker           highbd_ssim_8x8(CONVERT_TO_SHORTPTR(img1 + j), stride_img1,
308*fb1b10abSAndroid Build Coastguard Worker                           CONVERT_TO_SHORTPTR(img2 + j), stride_img2, bd);
309*fb1b10abSAndroid Build Coastguard Worker       ssim_total += v;
310*fb1b10abSAndroid Build Coastguard Worker       samples++;
311*fb1b10abSAndroid Build Coastguard Worker     }
312*fb1b10abSAndroid Build Coastguard Worker   }
313*fb1b10abSAndroid Build Coastguard Worker   ssim_total /= samples;
314*fb1b10abSAndroid Build Coastguard Worker   return ssim_total;
315*fb1b10abSAndroid Build Coastguard Worker }
316*fb1b10abSAndroid Build Coastguard Worker #endif  // CONFIG_VP9_HIGHBITDEPTH
317*fb1b10abSAndroid Build Coastguard Worker 
main(int argc,char * argv[])318*fb1b10abSAndroid Build Coastguard Worker int main(int argc, char *argv[]) {
319*fb1b10abSAndroid Build Coastguard Worker   FILE *framestats = NULL;
320*fb1b10abSAndroid Build Coastguard Worker   int bit_depth = 8;
321*fb1b10abSAndroid Build Coastguard Worker   int w = 0, h = 0, tl_skip = 0, tl_skips_remaining = 0;
322*fb1b10abSAndroid Build Coastguard Worker   double ssimavg = 0, ssimyavg = 0, ssimuavg = 0, ssimvavg = 0;
323*fb1b10abSAndroid Build Coastguard Worker   double psnrglb = 0, psnryglb = 0, psnruglb = 0, psnrvglb = 0;
324*fb1b10abSAndroid Build Coastguard Worker   double psnravg = 0, psnryavg = 0, psnruavg = 0, psnrvavg = 0;
325*fb1b10abSAndroid Build Coastguard Worker   double *ssimy = NULL, *ssimu = NULL, *ssimv = NULL;
326*fb1b10abSAndroid Build Coastguard Worker   uint64_t *psnry = NULL, *psnru = NULL, *psnrv = NULL;
327*fb1b10abSAndroid Build Coastguard Worker   size_t i, n_frames = 0, allocated_frames = 0;
328*fb1b10abSAndroid Build Coastguard Worker   int return_value = 0;
329*fb1b10abSAndroid Build Coastguard Worker   input_file_t in[2];
330*fb1b10abSAndroid Build Coastguard Worker   double peak = 255.0;
331*fb1b10abSAndroid Build Coastguard Worker 
332*fb1b10abSAndroid Build Coastguard Worker   memset(in, 0, sizeof(in));
333*fb1b10abSAndroid Build Coastguard Worker 
334*fb1b10abSAndroid Build Coastguard Worker   if (argc < 3) {
335*fb1b10abSAndroid Build Coastguard Worker     fprintf(stderr,
336*fb1b10abSAndroid Build Coastguard Worker             "Usage: %s file1.{yuv|y4m} file2.{yuv|y4m}"
337*fb1b10abSAndroid Build Coastguard Worker             " [WxH tl_skip={0,1,3} frame_stats_file bits]\n",
338*fb1b10abSAndroid Build Coastguard Worker             argv[0]);
339*fb1b10abSAndroid Build Coastguard Worker     return 1;
340*fb1b10abSAndroid Build Coastguard Worker   }
341*fb1b10abSAndroid Build Coastguard Worker 
342*fb1b10abSAndroid Build Coastguard Worker   if (argc > 3) {
343*fb1b10abSAndroid Build Coastguard Worker     sscanf(argv[3], "%dx%d", &w, &h);
344*fb1b10abSAndroid Build Coastguard Worker   }
345*fb1b10abSAndroid Build Coastguard Worker 
346*fb1b10abSAndroid Build Coastguard Worker   if (argc > 6) {
347*fb1b10abSAndroid Build Coastguard Worker     sscanf(argv[6], "%d", &bit_depth);
348*fb1b10abSAndroid Build Coastguard Worker   }
349*fb1b10abSAndroid Build Coastguard Worker 
350*fb1b10abSAndroid Build Coastguard Worker   if (open_input_file(argv[1], &in[0], w, h, bit_depth) < 0) {
351*fb1b10abSAndroid Build Coastguard Worker     fprintf(stderr, "File %s can't be opened or parsed!\n", argv[1]);
352*fb1b10abSAndroid Build Coastguard Worker     goto clean_up;
353*fb1b10abSAndroid Build Coastguard Worker   }
354*fb1b10abSAndroid Build Coastguard Worker 
355*fb1b10abSAndroid Build Coastguard Worker   if (w == 0 && h == 0) {
356*fb1b10abSAndroid Build Coastguard Worker     // If a y4m is the first file and w, h is not set grab from first file.
357*fb1b10abSAndroid Build Coastguard Worker     w = in[0].w;
358*fb1b10abSAndroid Build Coastguard Worker     h = in[0].h;
359*fb1b10abSAndroid Build Coastguard Worker     bit_depth = in[0].bit_depth;
360*fb1b10abSAndroid Build Coastguard Worker   }
361*fb1b10abSAndroid Build Coastguard Worker   if (bit_depth == 10) peak = 1023.0;
362*fb1b10abSAndroid Build Coastguard Worker 
363*fb1b10abSAndroid Build Coastguard Worker   if (bit_depth == 12) peak = 4095.0;
364*fb1b10abSAndroid Build Coastguard Worker 
365*fb1b10abSAndroid Build Coastguard Worker   if (open_input_file(argv[2], &in[1], w, h, bit_depth) < 0) {
366*fb1b10abSAndroid Build Coastguard Worker     fprintf(stderr, "File %s can't be opened or parsed!\n", argv[2]);
367*fb1b10abSAndroid Build Coastguard Worker     goto clean_up;
368*fb1b10abSAndroid Build Coastguard Worker   }
369*fb1b10abSAndroid Build Coastguard Worker 
370*fb1b10abSAndroid Build Coastguard Worker   if (in[0].w != in[1].w || in[0].h != in[1].h || in[0].w != w ||
371*fb1b10abSAndroid Build Coastguard Worker       in[0].h != h || w == 0 || h == 0) {
372*fb1b10abSAndroid Build Coastguard Worker     fprintf(stderr,
373*fb1b10abSAndroid Build Coastguard Worker             "Failing: Image dimensions don't match or are unspecified!\n");
374*fb1b10abSAndroid Build Coastguard Worker     return_value = 1;
375*fb1b10abSAndroid Build Coastguard Worker     goto clean_up;
376*fb1b10abSAndroid Build Coastguard Worker   }
377*fb1b10abSAndroid Build Coastguard Worker 
378*fb1b10abSAndroid Build Coastguard Worker   if (in[0].bit_depth != in[1].bit_depth) {
379*fb1b10abSAndroid Build Coastguard Worker     fprintf(stderr,
380*fb1b10abSAndroid Build Coastguard Worker             "Failing: Image bit depths don't match or are unspecified!\n");
381*fb1b10abSAndroid Build Coastguard Worker     return_value = 1;
382*fb1b10abSAndroid Build Coastguard Worker     goto clean_up;
383*fb1b10abSAndroid Build Coastguard Worker   }
384*fb1b10abSAndroid Build Coastguard Worker 
385*fb1b10abSAndroid Build Coastguard Worker   bit_depth = in[0].bit_depth;
386*fb1b10abSAndroid Build Coastguard Worker 
387*fb1b10abSAndroid Build Coastguard Worker   // Number of frames to skip from file1.yuv for every frame used. Normal
388*fb1b10abSAndroid Build Coastguard Worker   // values 0, 1 and 3 correspond to TL2, TL1 and TL0 respectively for a 3TL
389*fb1b10abSAndroid Build Coastguard Worker   // encoding in mode 10. 7 would be reasonable for comparing TL0 of a 4-layer
390*fb1b10abSAndroid Build Coastguard Worker   // encoding.
391*fb1b10abSAndroid Build Coastguard Worker   if (argc > 4) {
392*fb1b10abSAndroid Build Coastguard Worker     sscanf(argv[4], "%d", &tl_skip);
393*fb1b10abSAndroid Build Coastguard Worker     if (argc > 5) {
394*fb1b10abSAndroid Build Coastguard Worker       framestats = fopen(argv[5], "w");
395*fb1b10abSAndroid Build Coastguard Worker       if (!framestats) {
396*fb1b10abSAndroid Build Coastguard Worker         fprintf(stderr, "Could not open \"%s\" for writing: %s\n", argv[5],
397*fb1b10abSAndroid Build Coastguard Worker                 strerror(errno));
398*fb1b10abSAndroid Build Coastguard Worker         return_value = 1;
399*fb1b10abSAndroid Build Coastguard Worker         goto clean_up;
400*fb1b10abSAndroid Build Coastguard Worker       }
401*fb1b10abSAndroid Build Coastguard Worker     }
402*fb1b10abSAndroid Build Coastguard Worker   }
403*fb1b10abSAndroid Build Coastguard Worker 
404*fb1b10abSAndroid Build Coastguard Worker   while (1) {
405*fb1b10abSAndroid Build Coastguard Worker     int r1, r2;
406*fb1b10abSAndroid Build Coastguard Worker     unsigned char *y[2], *u[2], *v[2];
407*fb1b10abSAndroid Build Coastguard Worker 
408*fb1b10abSAndroid Build Coastguard Worker     r1 = read_input_file(&in[0], &y[0], &u[0], &v[0], bit_depth);
409*fb1b10abSAndroid Build Coastguard Worker     if (r1 == 0) {
410*fb1b10abSAndroid Build Coastguard Worker       if (ferror(in[0].file)) {
411*fb1b10abSAndroid Build Coastguard Worker         fprintf(stderr, "Failed to read data from '%s'\n", argv[1]);
412*fb1b10abSAndroid Build Coastguard Worker         return_value = 1;
413*fb1b10abSAndroid Build Coastguard Worker         goto clean_up;
414*fb1b10abSAndroid Build Coastguard Worker       }
415*fb1b10abSAndroid Build Coastguard Worker       break;
416*fb1b10abSAndroid Build Coastguard Worker     }
417*fb1b10abSAndroid Build Coastguard Worker 
418*fb1b10abSAndroid Build Coastguard Worker     // Reading parts of file1.yuv that were not used in temporal layer.
419*fb1b10abSAndroid Build Coastguard Worker     if (tl_skips_remaining > 0) {
420*fb1b10abSAndroid Build Coastguard Worker       --tl_skips_remaining;
421*fb1b10abSAndroid Build Coastguard Worker       continue;
422*fb1b10abSAndroid Build Coastguard Worker     }
423*fb1b10abSAndroid Build Coastguard Worker     // Use frame, but skip |tl_skip| after it.
424*fb1b10abSAndroid Build Coastguard Worker     tl_skips_remaining = tl_skip;
425*fb1b10abSAndroid Build Coastguard Worker 
426*fb1b10abSAndroid Build Coastguard Worker     r2 = read_input_file(&in[1], &y[1], &u[1], &v[1], bit_depth);
427*fb1b10abSAndroid Build Coastguard Worker     if (r2 == 0) {
428*fb1b10abSAndroid Build Coastguard Worker       if (ferror(in[1].file)) {
429*fb1b10abSAndroid Build Coastguard Worker         fprintf(stderr, "Failed to read data from '%s'\n", argv[2]);
430*fb1b10abSAndroid Build Coastguard Worker         return_value = 1;
431*fb1b10abSAndroid Build Coastguard Worker         goto clean_up;
432*fb1b10abSAndroid Build Coastguard Worker       }
433*fb1b10abSAndroid Build Coastguard Worker       break;
434*fb1b10abSAndroid Build Coastguard Worker     }
435*fb1b10abSAndroid Build Coastguard Worker 
436*fb1b10abSAndroid Build Coastguard Worker #if CONFIG_VP9_HIGHBITDEPTH
437*fb1b10abSAndroid Build Coastguard Worker #define psnr_and_ssim(ssim, psnr, buf0, buf1, w, h)                           \
438*fb1b10abSAndroid Build Coastguard Worker   do {                                                                        \
439*fb1b10abSAndroid Build Coastguard Worker     if (bit_depth < 9) {                                                      \
440*fb1b10abSAndroid Build Coastguard Worker       ssim = ssim2(buf0, buf1, w, w, w, h);                                   \
441*fb1b10abSAndroid Build Coastguard Worker       psnr = calc_plane_error(buf0, w, buf1, w, w, h);                        \
442*fb1b10abSAndroid Build Coastguard Worker     } else {                                                                  \
443*fb1b10abSAndroid Build Coastguard Worker       ssim = highbd_ssim2(CONVERT_TO_BYTEPTR(buf0), CONVERT_TO_BYTEPTR(buf1), \
444*fb1b10abSAndroid Build Coastguard Worker                           w, w, w, h, bit_depth);                             \
445*fb1b10abSAndroid Build Coastguard Worker       psnr = calc_plane_error16(CAST_TO_SHORTPTR(buf0), w,                    \
446*fb1b10abSAndroid Build Coastguard Worker                                 CAST_TO_SHORTPTR(buf1), w, w, h);             \
447*fb1b10abSAndroid Build Coastguard Worker     }                                                                         \
448*fb1b10abSAndroid Build Coastguard Worker   } while (0)
449*fb1b10abSAndroid Build Coastguard Worker #else
450*fb1b10abSAndroid Build Coastguard Worker #define psnr_and_ssim(ssim, psnr, buf0, buf1, w, h)  \
451*fb1b10abSAndroid Build Coastguard Worker   do {                                               \
452*fb1b10abSAndroid Build Coastguard Worker     ssim = ssim2(buf0, buf1, w, w, w, h);            \
453*fb1b10abSAndroid Build Coastguard Worker     psnr = calc_plane_error(buf0, w, buf1, w, w, h); \
454*fb1b10abSAndroid Build Coastguard Worker   } while (0)
455*fb1b10abSAndroid Build Coastguard Worker #endif  // CONFIG_VP9_HIGHBITDEPTH
456*fb1b10abSAndroid Build Coastguard Worker 
457*fb1b10abSAndroid Build Coastguard Worker     if (n_frames == allocated_frames) {
458*fb1b10abSAndroid Build Coastguard Worker       allocated_frames = allocated_frames == 0 ? 1024 : allocated_frames * 2;
459*fb1b10abSAndroid Build Coastguard Worker       ssimy = realloc(ssimy, allocated_frames * sizeof(*ssimy));
460*fb1b10abSAndroid Build Coastguard Worker       ssimu = realloc(ssimu, allocated_frames * sizeof(*ssimu));
461*fb1b10abSAndroid Build Coastguard Worker       ssimv = realloc(ssimv, allocated_frames * sizeof(*ssimv));
462*fb1b10abSAndroid Build Coastguard Worker       psnry = realloc(psnry, allocated_frames * sizeof(*psnry));
463*fb1b10abSAndroid Build Coastguard Worker       psnru = realloc(psnru, allocated_frames * sizeof(*psnru));
464*fb1b10abSAndroid Build Coastguard Worker       psnrv = realloc(psnrv, allocated_frames * sizeof(*psnrv));
465*fb1b10abSAndroid Build Coastguard Worker       if (!(ssimy && ssimu && ssimv && psnry && psnru && psnrv)) {
466*fb1b10abSAndroid Build Coastguard Worker         fprintf(stderr, "Error allocating SSIM/PSNR data.\n");
467*fb1b10abSAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
468*fb1b10abSAndroid Build Coastguard Worker       }
469*fb1b10abSAndroid Build Coastguard Worker     }
470*fb1b10abSAndroid Build Coastguard Worker     psnr_and_ssim(ssimy[n_frames], psnry[n_frames], y[0], y[1], w, h);
471*fb1b10abSAndroid Build Coastguard Worker     psnr_and_ssim(ssimu[n_frames], psnru[n_frames], u[0], u[1], (w + 1) / 2,
472*fb1b10abSAndroid Build Coastguard Worker                   (h + 1) / 2);
473*fb1b10abSAndroid Build Coastguard Worker     psnr_and_ssim(ssimv[n_frames], psnrv[n_frames], v[0], v[1], (w + 1) / 2,
474*fb1b10abSAndroid Build Coastguard Worker                   (h + 1) / 2);
475*fb1b10abSAndroid Build Coastguard Worker 
476*fb1b10abSAndroid Build Coastguard Worker     n_frames++;
477*fb1b10abSAndroid Build Coastguard Worker   }
478*fb1b10abSAndroid Build Coastguard Worker 
479*fb1b10abSAndroid Build Coastguard Worker   if (framestats) {
480*fb1b10abSAndroid Build Coastguard Worker     fprintf(framestats,
481*fb1b10abSAndroid Build Coastguard Worker             "ssim,ssim-y,ssim-u,ssim-v,psnr,psnr-y,psnr-u,psnr-v\n");
482*fb1b10abSAndroid Build Coastguard Worker   }
483*fb1b10abSAndroid Build Coastguard Worker 
484*fb1b10abSAndroid Build Coastguard Worker   for (i = 0; i < n_frames; ++i) {
485*fb1b10abSAndroid Build Coastguard Worker     double frame_ssim;
486*fb1b10abSAndroid Build Coastguard Worker     double frame_psnr, frame_psnry, frame_psnru, frame_psnrv;
487*fb1b10abSAndroid Build Coastguard Worker 
488*fb1b10abSAndroid Build Coastguard Worker     frame_ssim = 0.8 * ssimy[i] + 0.1 * (ssimu[i] + ssimv[i]);
489*fb1b10abSAndroid Build Coastguard Worker     ssimavg += frame_ssim;
490*fb1b10abSAndroid Build Coastguard Worker     ssimyavg += ssimy[i];
491*fb1b10abSAndroid Build Coastguard Worker     ssimuavg += ssimu[i];
492*fb1b10abSAndroid Build Coastguard Worker     ssimvavg += ssimv[i];
493*fb1b10abSAndroid Build Coastguard Worker 
494*fb1b10abSAndroid Build Coastguard Worker     frame_psnr =
495*fb1b10abSAndroid Build Coastguard Worker         mse2psnr(w * h * 6 / 4, peak, (double)psnry[i] + psnru[i] + psnrv[i]);
496*fb1b10abSAndroid Build Coastguard Worker     frame_psnry = mse2psnr(w * h * 4 / 4, peak, (double)psnry[i]);
497*fb1b10abSAndroid Build Coastguard Worker     frame_psnru = mse2psnr(w * h * 1 / 4, peak, (double)psnru[i]);
498*fb1b10abSAndroid Build Coastguard Worker     frame_psnrv = mse2psnr(w * h * 1 / 4, peak, (double)psnrv[i]);
499*fb1b10abSAndroid Build Coastguard Worker 
500*fb1b10abSAndroid Build Coastguard Worker     psnravg += frame_psnr;
501*fb1b10abSAndroid Build Coastguard Worker     psnryavg += frame_psnry;
502*fb1b10abSAndroid Build Coastguard Worker     psnruavg += frame_psnru;
503*fb1b10abSAndroid Build Coastguard Worker     psnrvavg += frame_psnrv;
504*fb1b10abSAndroid Build Coastguard Worker 
505*fb1b10abSAndroid Build Coastguard Worker     psnryglb += psnry[i];
506*fb1b10abSAndroid Build Coastguard Worker     psnruglb += psnru[i];
507*fb1b10abSAndroid Build Coastguard Worker     psnrvglb += psnrv[i];
508*fb1b10abSAndroid Build Coastguard Worker 
509*fb1b10abSAndroid Build Coastguard Worker     if (framestats) {
510*fb1b10abSAndroid Build Coastguard Worker       fprintf(framestats, "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf\n", frame_ssim,
511*fb1b10abSAndroid Build Coastguard Worker               ssimy[i], ssimu[i], ssimv[i], frame_psnr, frame_psnry,
512*fb1b10abSAndroid Build Coastguard Worker               frame_psnru, frame_psnrv);
513*fb1b10abSAndroid Build Coastguard Worker     }
514*fb1b10abSAndroid Build Coastguard Worker   }
515*fb1b10abSAndroid Build Coastguard Worker 
516*fb1b10abSAndroid Build Coastguard Worker   ssimavg /= n_frames;
517*fb1b10abSAndroid Build Coastguard Worker   ssimyavg /= n_frames;
518*fb1b10abSAndroid Build Coastguard Worker   ssimuavg /= n_frames;
519*fb1b10abSAndroid Build Coastguard Worker   ssimvavg /= n_frames;
520*fb1b10abSAndroid Build Coastguard Worker 
521*fb1b10abSAndroid Build Coastguard Worker   printf("VpxSSIM: %lf\n", 100 * pow(ssimavg, 8.0));
522*fb1b10abSAndroid Build Coastguard Worker   printf("SSIM: %lf\n", ssimavg);
523*fb1b10abSAndroid Build Coastguard Worker   printf("SSIM-Y: %lf\n", ssimyavg);
524*fb1b10abSAndroid Build Coastguard Worker   printf("SSIM-U: %lf\n", ssimuavg);
525*fb1b10abSAndroid Build Coastguard Worker   printf("SSIM-V: %lf\n", ssimvavg);
526*fb1b10abSAndroid Build Coastguard Worker   puts("");
527*fb1b10abSAndroid Build Coastguard Worker 
528*fb1b10abSAndroid Build Coastguard Worker   psnravg /= n_frames;
529*fb1b10abSAndroid Build Coastguard Worker   psnryavg /= n_frames;
530*fb1b10abSAndroid Build Coastguard Worker   psnruavg /= n_frames;
531*fb1b10abSAndroid Build Coastguard Worker   psnrvavg /= n_frames;
532*fb1b10abSAndroid Build Coastguard Worker 
533*fb1b10abSAndroid Build Coastguard Worker   printf("AvgPSNR: %lf\n", psnravg);
534*fb1b10abSAndroid Build Coastguard Worker   printf("AvgPSNR-Y: %lf\n", psnryavg);
535*fb1b10abSAndroid Build Coastguard Worker   printf("AvgPSNR-U: %lf\n", psnruavg);
536*fb1b10abSAndroid Build Coastguard Worker   printf("AvgPSNR-V: %lf\n", psnrvavg);
537*fb1b10abSAndroid Build Coastguard Worker   puts("");
538*fb1b10abSAndroid Build Coastguard Worker 
539*fb1b10abSAndroid Build Coastguard Worker   psnrglb = psnryglb + psnruglb + psnrvglb;
540*fb1b10abSAndroid Build Coastguard Worker   psnrglb = mse2psnr((double)n_frames * w * h * 6 / 4, peak, psnrglb);
541*fb1b10abSAndroid Build Coastguard Worker   psnryglb = mse2psnr((double)n_frames * w * h * 4 / 4, peak, psnryglb);
542*fb1b10abSAndroid Build Coastguard Worker   psnruglb = mse2psnr((double)n_frames * w * h * 1 / 4, peak, psnruglb);
543*fb1b10abSAndroid Build Coastguard Worker   psnrvglb = mse2psnr((double)n_frames * w * h * 1 / 4, peak, psnrvglb);
544*fb1b10abSAndroid Build Coastguard Worker 
545*fb1b10abSAndroid Build Coastguard Worker   printf("GlbPSNR: %lf\n", psnrglb);
546*fb1b10abSAndroid Build Coastguard Worker   printf("GlbPSNR-Y: %lf\n", psnryglb);
547*fb1b10abSAndroid Build Coastguard Worker   printf("GlbPSNR-U: %lf\n", psnruglb);
548*fb1b10abSAndroid Build Coastguard Worker   printf("GlbPSNR-V: %lf\n", psnrvglb);
549*fb1b10abSAndroid Build Coastguard Worker   puts("");
550*fb1b10abSAndroid Build Coastguard Worker 
551*fb1b10abSAndroid Build Coastguard Worker   printf("Nframes: %d\n", (int)n_frames);
552*fb1b10abSAndroid Build Coastguard Worker 
553*fb1b10abSAndroid Build Coastguard Worker clean_up:
554*fb1b10abSAndroid Build Coastguard Worker 
555*fb1b10abSAndroid Build Coastguard Worker   close_input_file(&in[0]);
556*fb1b10abSAndroid Build Coastguard Worker   close_input_file(&in[1]);
557*fb1b10abSAndroid Build Coastguard Worker 
558*fb1b10abSAndroid Build Coastguard Worker   if (framestats) fclose(framestats);
559*fb1b10abSAndroid Build Coastguard Worker 
560*fb1b10abSAndroid Build Coastguard Worker   free(ssimy);
561*fb1b10abSAndroid Build Coastguard Worker   free(ssimu);
562*fb1b10abSAndroid Build Coastguard Worker   free(ssimv);
563*fb1b10abSAndroid Build Coastguard Worker 
564*fb1b10abSAndroid Build Coastguard Worker   free(psnry);
565*fb1b10abSAndroid Build Coastguard Worker   free(psnru);
566*fb1b10abSAndroid Build Coastguard Worker   free(psnrv);
567*fb1b10abSAndroid Build Coastguard Worker 
568*fb1b10abSAndroid Build Coastguard Worker   return return_value;
569*fb1b10abSAndroid Build Coastguard Worker }
570