00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <inttypes.h>
00025 #include <assert.h>
00026
00027 #include "libavutil/intfloat.h"
00028
00029 #define FFMIN(a, b) ((a) > (b) ? (b) : (a))
00030 #define F 100
00031 #define SIZE 2048
00032
00033 uint64_t exp16_table[21] = {
00034 65537,
00035 65538,
00036 65540,
00037 65544,
00038 65552,
00039 65568,
00040 65600,
00041 65664,
00042 65793,
00043 66050,
00044 66568,
00045 67616,
00046 69763,
00047 74262,
00048 84150,
00049 108051,
00050 178145,
00051 484249,
00052 3578144,
00053 195360063,
00054 582360139072LL,
00055 };
00056
00057 #if 0
00058
00059 static unsigned int exp16(unsigned int a){
00060 int i;
00061 int out= 1<<16;
00062
00063 for(i=19;i>=0;i--){
00064 if(a&(1<<i))
00065 out= (out*exp16_table[i] + (1<<15))>>16;
00066 }
00067
00068 return out;
00069 }
00070 #endif
00071
00072
00073 static int64_t log16(uint64_t a)
00074 {
00075 int i;
00076 int out = 0;
00077
00078 if (a < 1 << 16)
00079 return -log16((1LL << 32) / a);
00080 a <<= 16;
00081
00082 for (i = 20; i >= 0; i--) {
00083 int64_t b = exp16_table[i];
00084 if (a < (b << 16))
00085 continue;
00086 out |= 1 << i;
00087 a = ((a / b) << 16) + (((a % b) << 16) + b / 2) / b;
00088 }
00089 return out;
00090 }
00091
00092 static uint64_t int_sqrt(uint64_t a)
00093 {
00094 uint64_t ret = 0;
00095 uint64_t ret_sq = 0;
00096 int s;
00097
00098 for (s = 31; s >= 0; s--) {
00099 uint64_t b = ret_sq + (1ULL << (s * 2)) + (ret << s) * 2;
00100 if (b <= a) {
00101 ret_sq = b;
00102 ret += 1ULL << s;
00103 }
00104 }
00105 return ret;
00106 }
00107
00108 static int16_t get_s16l(uint8_t *p)
00109 {
00110 union {
00111 uint16_t u;
00112 int16_t s;
00113 } v;
00114 v.u = p[0] | p[1] << 8;
00115 return v.s;
00116 }
00117
00118 static float get_f32l(uint8_t *p)
00119 {
00120 union av_intfloat32 v;
00121 v.i = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
00122 return v.f;
00123 }
00124
00125 static int run_psnr(FILE *f[2], int len, int shift, int skip_bytes)
00126 {
00127 int i, j;
00128 uint64_t sse = 0;
00129 uint64_t dev;
00130 uint8_t buf[2][SIZE];
00131 uint64_t psnr;
00132 int64_t max = (1LL << (8 * len)) - 1;
00133 int size0 = 0;
00134 int size1 = 0;
00135 int maxdist = 0;
00136 int noseek;
00137
00138 noseek = fseek(f[0], 0, SEEK_SET) ||
00139 fseek(f[1], 0, SEEK_SET);
00140
00141 if (!noseek) {
00142 for (i = 0; i < 2; i++) {
00143 uint8_t *p = buf[i];
00144 if (fread(p, 1, 12, f[i]) != 12)
00145 return 1;
00146 if (!memcmp(p, "RIFF", 4) &&
00147 !memcmp(p + 8, "WAVE", 4)) {
00148 if (fread(p, 1, 8, f[i]) != 8)
00149 return 1;
00150 while (memcmp(p, "data", 4)) {
00151 int s = p[4] | p[5] << 8 | p[6] << 16 | p[7] << 24;
00152 fseek(f[i], s, SEEK_CUR);
00153 if (fread(p, 1, 8, f[i]) != 8)
00154 return 1;
00155 }
00156 } else {
00157 fseek(f[i], -12, SEEK_CUR);
00158 }
00159 }
00160
00161 fseek(f[shift < 0], abs(shift), SEEK_CUR);
00162
00163 fseek(f[0], skip_bytes, SEEK_CUR);
00164 fseek(f[1], skip_bytes, SEEK_CUR);
00165 }
00166
00167 for (;;) {
00168 int s0 = fread(buf[0], 1, SIZE, f[0]);
00169 int s1 = fread(buf[1], 1, SIZE, f[1]);
00170
00171 for (j = 0; j < FFMIN(s0, s1); j += len) {
00172 int64_t a = buf[0][j];
00173 int64_t b = buf[1][j];
00174 int dist;
00175 if (len == 2) {
00176 a = get_s16l(buf[0] + j);
00177 b = get_s16l(buf[1] + j);
00178 } else if (len == 4) {
00179 a = get_f32l(buf[0] + j) * (1 << 24);
00180 b = get_f32l(buf[1] + j) * (1 << 24);
00181 } else {
00182 a = buf[0][j];
00183 b = buf[1][j];
00184 }
00185 sse += (a - b) * (a - b);
00186 dist = abs(a - b);
00187 if (dist > maxdist)
00188 maxdist = dist;
00189 }
00190 size0 += s0;
00191 size1 += s1;
00192 if (s0 + s1 <= 0)
00193 break;
00194 }
00195
00196 i = FFMIN(size0, size1) / len;
00197 if (!i)
00198 i = 1;
00199 dev = int_sqrt(((sse / i) * F * F) + (((sse % i) * F * F) + i / 2) / i);
00200 if (sse)
00201 psnr = ((2 * log16(max << 16) + log16(i) - log16(sse)) *
00202 284619LL * F + (1LL << 31)) / (1LL << 32);
00203 else
00204 psnr = 1000 * F - 1;
00205
00206 printf("stddev:%5d.%02d PSNR:%3d.%02d MAXDIFF:%5d bytes:%9d/%9d\n",
00207 (int)(dev / F), (int)(dev % F),
00208 (int)(psnr / F), (int)(psnr % F),
00209 maxdist, size0, size1);
00210 return psnr;
00211 }
00212
00213 int main(int argc, char *argv[])
00214 {
00215 FILE *f[2];
00216 int len = 1;
00217 int shift_first= argc < 5 ? 0 : atoi(argv[4]);
00218 int skip_bytes = argc < 6 ? 0 : atoi(argv[5]);
00219 int shift_last = shift_first + (argc < 7 ? 0 : atoi(argv[6]));
00220 int shift;
00221 int max_psnr = -1;
00222 int max_psnr_shift = 0;
00223
00224 if (argc > 3) {
00225 if (!strcmp(argv[3], "u8")) {
00226 len = 1;
00227 } else if (!strcmp(argv[3], "s16")) {
00228 len = 2;
00229 } else if (!strcmp(argv[3], "f32")) {
00230 len = 4;
00231 } else {
00232 char *end;
00233 len = strtol(argv[3], &end, 0);
00234 if (*end || len < 1 || len > 2) {
00235 fprintf(stderr, "Unsupported sample format: %s\n", argv[3]);
00236 return 1;
00237 }
00238 }
00239 }
00240
00241 if (argc < 3) {
00242 printf("tiny_psnr <file1> <file2> [<elem size> [<shift> [<skip bytes> [<shift search range>]]]]\n");
00243 printf("WAV headers are skipped automatically.\n");
00244 return 1;
00245 }
00246
00247 f[0] = fopen(argv[1], "rb");
00248 f[1] = fopen(argv[2], "rb");
00249 if (!f[0] || !f[1]) {
00250 fprintf(stderr, "Could not open input files.\n");
00251 return 1;
00252 }
00253
00254 for (shift = shift_first; shift <= shift_last; shift++) {
00255 int psnr = run_psnr(f, len, shift, skip_bytes);
00256 if (psnr > max_psnr || (shift < 0 && psnr == max_psnr)) {
00257 max_psnr = psnr;
00258 max_psnr_shift = shift;
00259 }
00260 }
00261 if (shift_last > shift_first)
00262 printf("Best PSNR is %3d.%02d for shift %i\n", (int)(max_psnr / F), (int)(max_psnr % F), max_psnr_shift);
00263 return 0;
00264 }