Statistics
| Branch: | Revision:

psnr-tools / EvalVid / psnr.c @ 2ac6f1f0

History | View | Annotate | Download (5.4 KB)

1

    
2
#include <math.h>
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <time.h>
7

    
8
#ifdef _WIN32
9
  #include "stdint_w32.h"
10
  #define alloca _alloca
11
#else
12
  #include <stdint.h>
13
#endif
14

    
15
/****************************************************************************
16
 * structural similarity metric [from x264]
17
 ****************************************************************************/
18

    
19
#define x264_alloca(x) (void*)(((intptr_t)alloca((x)+15)+15)&~15)
20
#define XCHG(type,a,b) { type t = a; a = b; b = t; }
21
#define X264_MIN(a,b) ( (a)<(b) ? (a) : (b) )
22

    
23
static void ssim_4x4x2_core( const uint8_t *pix1, int stride1,
24
                             const uint8_t *pix2, int stride2,
25
                             int sums[2][4])
26
{
27
    int x, y, z;
28
    for(z=0; z<2; z++)
29
    {
30
        uint32_t s1=0, s2=0, ss=0, s12=0;
31
        for(y=0; y<4; y++)
32
            for(x=0; x<4; x++)
33
            {
34
                int a = pix1[x+y*stride1];
35
                int b = pix2[x+y*stride2];
36
                s1  += a;
37
                s2  += b;
38
                ss  += a*a;
39
                ss  += b*b;
40
                s12 += a*b;
41
            }
42
        sums[z][0] = s1;
43
        sums[z][1] = s2;
44
        sums[z][2] = ss;
45
        sums[z][3] = s12;
46
        pix1 += 4;
47
        pix2 += 4;
48
    }
49
}
50

    
51
static float ssim_end1( int s1, int s2, int ss, int s12 )
52
{
53
    static const int ssim_c1 = (int)(.01*.01*255*255*64 + .5);
54
    static const int ssim_c2 = (int)(.03*.03*255*255*64*63 + .5);
55
    int vars = ss*64 - s1*s1 - s2*s2;
56
    int covar = s12*64 - s1*s2;
57
    return (float)(2*s1*s2 + ssim_c1) * (float)(2*covar + ssim_c2)\
58
           / ((float)(s1*s1 + s2*s2 + ssim_c1) * (float)(vars + ssim_c2));
59
}
60

    
61
static float ssim_end4( int sum0[5][4], int sum1[5][4], int width )
62
{
63
    int i;
64
    float ssim = 0.0;
65
    for( i = 0; i < width; i++ )
66
        ssim += ssim_end1( sum0[i][0] + sum0[i+1][0] + sum1[i][0] + sum1[i+1][0],
67
                           sum0[i][1] + sum0[i+1][1] + sum1[i][1] + sum1[i+1][1],
68
                           sum0[i][2] + sum0[i+1][2] + sum1[i][2] + sum1[i+1][2],
69
                           sum0[i][3] + sum0[i+1][3] + sum1[i][3] + sum1[i+1][3] );
70
    return ssim;
71
}
72

    
73
float x264_pixel_ssim_wxh(
74
                           uint8_t *pix1, int stride1,
75
                           uint8_t *pix2, int stride2,
76
                           int width, int height )
77
{
78
    int x, y, z;
79
    float ssim = 0.0;
80
    int (*sum0)[4] = x264_alloca(4 * (width/4+3) * sizeof(int));
81
    int (*sum1)[4] = x264_alloca(4 * (width/4+3) * sizeof(int));
82
    width >>= 2;
83
    height >>= 2;
84
    z = 0;
85
    for( y = 1; y < height; y++ )
86
    {
87
        for( ; z <= y; z++ )
88
        {
89
            XCHG( void*, sum0, sum1 );
90
            for( x = 0; x < width; x+=2 )
91
                ssim_4x4x2_core( &pix1[4*(x+z*stride1)], stride1, &pix2[4*(x+z*stride2)], stride2, &sum0[x] );
92
        }
93
        for( x = 0; x < width-1; x += 4 )
94
            ssim += ssim_end4( sum0+x, sum1+x, X264_MIN(4,width-x-1) );
95
    }
96
    return ssim / ((width-1) * (height-1));
97
}
98

    
99
int main(int n, char *cl[])
100
{
101
  FILE *f1, *f2;
102
  int ssim = 0, i, x, y, yuv, inc = 1, size = 0, N = 0, Y, F;
103
  double yrmse, diff, mean = 0, stdv = 0, *ypsnr = 0;
104
  unsigned char *b1, *b2;
105
  clock_t t = clock();
106

    
107
  if (n != 6 && n != 7) {
108
    puts("psnr x y <YUV format> <src.yuv> <dst.yuv> [multiplex] [ssim]");
109
    puts("  x\t\tframe width");
110
    puts("  y\t\tframe height");
111
    puts("  YUV format\t420, 422, etc.");
112
    puts("  src.yuv\tsource video");
113
    puts("  dst.yuv\tdistorted video");
114
    puts("  [multiplex]\toptional");
115
    puts("  [ssim]\toptional: calculate structural similarity instead of PSNR");
116
    return EXIT_FAILURE;
117
  }
118

    
119
  if ((f1 = fopen(cl[4], "rb")) == 0) goto A;
120
  if ((f2 = fopen(cl[5], "rb")) == 0) goto B;
121
  if (!(x = strtoul(cl[1], 0, 10)) ||
122
      !(y = strtoul(cl[2], 0, 10))) goto C; 
123
  if ((yuv = strtoul(cl[3], 0, 10)) > 444) goto D;
124
  if (cl[6] && !strcmp(cl[6], "multiplex")) inc = 2;
125
  if (cl[6] && !strcmp(cl[6], "ssim")) ssim = 1;
126

    
127
  Y = x * y;
128
  switch (yuv) {
129
    case 400: F = Y; break;
130
    case 422: F = Y * 2; break;
131
    case 444: F = Y * 3; break;
132
    default :
133
    case 420: F = Y * 3 / 2; break;
134
  }
135

    
136
  if (!(b1 = malloc(F))) goto E;
137
  if (!(b2 = malloc(F))) goto E;
138

    
139
  for (;;) {
140
    if (1 != fread(b1, F, 1, f1) || 1 != fread(b2, F, 1, f2)) break;
141

    
142
    if (++N > size) {
143
      size += 0xffff;
144
      if (!(ypsnr = realloc(ypsnr, size * sizeof *ypsnr))) goto E;
145
    }
146

    
147
    if (ssim) {
148
      mean += ypsnr[N - 1] = x264_pixel_ssim_wxh(b1, x, b2, x, x, y);
149
    } else {
150
      for (yrmse = 0, i = inc - 1; i < (inc == 1 ? Y : F); i += inc) {
151
        diff = b1[i] - b2[i];
152
        yrmse += diff * diff;
153
      }
154
      mean += ypsnr[N - 1] = yrmse ? 20 * (log10(255 / sqrt(yrmse / Y))) : 255;
155
    }
156

    
157
    printf("%.3f\n", ypsnr[N - 1]);
158
  }
159

    
160
  if (N) {
161
    mean /= N;
162

    
163
    for (stdv = 0, i = 0; i < N; i++) {
164
      diff = ypsnr[i] - mean;
165
      stdv += diff * diff;
166
    }
167
    stdv = sqrt(stdv / (N - 1));
168

    
169
    free(ypsnr);
170
  }
171

    
172
  fclose(f1);
173
  fclose(f2);
174

    
175
  fprintf(stderr, "%s:\t%d frames (CPU: %lu s) mean: %.6f stdv: %.6f\n",
176
    ssim ? "ssim" : "psnr", N, (unsigned long) ((clock() - t) / CLOCKS_PER_SEC), mean, stdv);
177

    
178
  return 0;
179

    
180
A: fprintf(stderr, " Error opening source video file.\n"); goto X;
181
B: fprintf(stderr, " Error opening decoded video file.\n"); goto X;
182
C: fprintf(stderr, " Invalid width or height.\n"); goto X;
183
D: fprintf(stderr, " Invalid YUV format.\n"); goto X;
184
E: fprintf(stderr, " Not enough memory.\n");
185

    
186
X: return EXIT_FAILURE;
187
}