tiny_psnr.c 4.94 KB
Newer Older
1 2 3
/*
 * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
 *
4 5 6
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
7 8
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12 13 14 15 16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 20 21
 */

#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <inttypes.h>
25
#include <assert.h>
26

27
#define FFMIN(a, b) ((a) > (b) ? (b) : (a))
28 29 30
#define F 100
#define SIZE 2048

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
uint64_t exp16_table[21] = {
           65537,
           65538,
           65540,
           65544,
           65552,
           65568,
           65600,
           65664,
           65793,
           66050,
           66568,
           67616,
           69763,
           74262,
           84150,
          108051,
          178145,
          484249,
         3578144,
       195360063,
    582360139072LL,
53
};
54 55

#if 0
56 57 58 59 60 61 62 63 64
// 16.16 fixpoint exp()
static unsigned int exp16(unsigned int a){
    int i;
    int out= 1<<16;

    for(i=19;i>=0;i--){
        if(a&(1<<i))
            out= (out*exp16_table[i] + (1<<15))>>16;
    }
65

66 67
    return out;
}
68 69
#endif

70
// 16.16 fixpoint log()
71 72
static int64_t log16(uint64_t a)
{
73
    int i;
74 75 76 77 78 79 80 81 82 83 84 85
    int out = 0;

    if (a < 1 << 16)
        return -log16((1LL << 32) / a);
    a <<= 16;

    for (i = 20; i >= 0; i--) {
        int64_t b = exp16_table[i];
        if (a < (b << 16))
            continue;
        out |= 1 << i;
        a    = ((a / b) << 16) + (((a % b) << 16) + b / 2) / b;
86 87 88 89
    }
    return out;
}

90 91
static uint64_t int_sqrt(uint64_t a)
{
92 93
    uint64_t ret    = 0;
    uint64_t ret_sq = 0;
94 95
    int s;

96 97 98 99 100
    for (s = 31; s >= 0; s--) {
        uint64_t b = ret_sq + (1ULL << (s * 2)) + (ret << s) * 2;
        if (b <= a) {
            ret_sq = b;
            ret   += 1ULL << s;
101 102 103 104 105
        }
    }
    return ret;
}

106 107
int main(int argc, char *argv[])
{
108
    int i, j;
109
    uint64_t sse = 0;
110 111 112
    uint64_t dev;
    FILE *f[2];
    uint8_t buf[2][SIZE];
113
    uint64_t psnr;
114 115 116 117 118 119 120 121 122
    int len        = argc < 4 ? 1 : atoi(argv[3]);
    int64_t max    = (1 << (8 * len)) - 1;
    int shift      = argc < 5 ? 0 : atoi(argv[4]);
    int skip_bytes = argc < 6 ? 0 : atoi(argv[5]);
    int size0      = 0;
    int size1      = 0;
    int maxdist    = 0;

    if (argc < 3) {
123
        printf("tiny_psnr <file1> <file2> [<elem size> [<shift> [<skip bytes>]]]\n");
124
        printf("WAV headers are skipped automatically.\n");
125
        return 1;
126
    }
127

128 129 130
    f[0] = fopen(argv[1], "rb");
    f[1] = fopen(argv[2], "rb");
    if (!f[0] || !f[1]) {
131
        fprintf(stderr, "Could not open input files.\n");
132
        return 1;
133
    }
134 135 136

    for (i = 0; i < 2; i++) {
        uint8_t *p = buf[i];
137 138
        if (fread(p, 1, 12, f[i]) != 12)
            return 1;
139 140
        if (!memcmp(p, "RIFF", 4) &&
            !memcmp(p + 8, "WAVE", 4)) {
141 142
            if (fread(p, 1, 8, f[i]) != 8)
                return 1;
143
            while (memcmp(p, "data", 4)) {
144
                int s = p[4] | p[5] << 8 | p[6] << 16 | p[7] << 24;
145
                fseek(f[i], s, SEEK_CUR);
146 147
                if (fread(p, 1, 8, f[i]) != 8)
                    return 1;
148 149 150 151 152 153
            }
        } else {
            fseek(f[i], -12, SEEK_CUR);
        }
    }

154
    fseek(f[shift < 0], abs(shift), SEEK_CUR);
155

156 157
    fseek(f[0], skip_bytes, SEEK_CUR);
    fseek(f[1], skip_bytes, SEEK_CUR);
158

159 160 161
    for (;;) {
        int s0 = fread(buf[0], 1, SIZE, f[0]);
        int s1 = fread(buf[1], 1, SIZE, f[1]);
162

163 164 165
        for (j = 0; j < FFMIN(s0, s1); j++) {
            int64_t a = buf[0][j];
            int64_t b = buf[1][j];
166
            int dist;
167 168 169
            if (len == 2) {
                a = (int16_t)(a | (buf[0][++j] << 8));
                b = (int16_t)(b | (buf[1][  j] << 8));
170
            }
171 172 173 174
            sse += (a - b) * (a - b);
            dist = abs(a - b);
            if (dist > maxdist)
                maxdist = dist;
175
        }
176 177
        size0 += s0;
        size1 += s1;
178
        if (s0 + s1 <= 0)
179
            break;
180
    }
181

182 183 184 185 186 187 188
    i = FFMIN(size0, size1) / len;
    if (!i)
        i = 1;
    dev = int_sqrt(((sse / i) * F * F) + (((sse % i) * F * F) + i / 2) / i);
    if (sse)
        psnr = ((2 * log16(max << 16) + log16(i) - log16(sse)) *
                284619LL * F + (1LL << 31)) / (1LL << 32);
189
    else
190
        psnr = 1000 * F - 1; // floating point free infinity :)
191

192
    printf("stddev:%5d.%02d PSNR:%3d.%02d MAXDIFF:%5d bytes:%9d/%9d\n",
193 194 195
           (int)(dev / F), (int)(dev % F),
           (int)(psnr / F), (int)(psnr % F),
           maxdist, size0, size1);
196 197
    return 0;
}