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 #define FFMIN(a, b) ((a) > (b) ? (b) : (a))
00028 #define F 100
00029 #define SIZE 2048
00030
00031 uint64_t exp16_table[21] = {
00032 65537,
00033 65538,
00034 65540,
00035 65544,
00036 65552,
00037 65568,
00038 65600,
00039 65664,
00040 65793,
00041 66050,
00042 66568,
00043 67616,
00044 69763,
00045 74262,
00046 84150,
00047 108051,
00048 178145,
00049 484249,
00050 3578144,
00051 195360063,
00052 582360139072LL,
00053 };
00054
00055 #if 0
00056
00057 static unsigned int exp16(unsigned int a){
00058 int i;
00059 int out= 1<<16;
00060
00061 for(i=19;i>=0;i--){
00062 if(a&(1<<i))
00063 out= (out*exp16_table[i] + (1<<15))>>16;
00064 }
00065
00066 return out;
00067 }
00068 #endif
00069
00070
00071 static int64_t log16(uint64_t a)
00072 {
00073 int i;
00074 int out = 0;
00075
00076 if (a < 1 << 16)
00077 return -log16((1LL << 32) / a);
00078 a <<= 16;
00079
00080 for (i = 20; i >= 0; i--) {
00081 int64_t b = exp16_table[i];
00082 if (a < (b << 16))
00083 continue;
00084 out |= 1 << i;
00085 a = ((a / b) << 16) + (((a % b) << 16) + b / 2) / b;
00086 }
00087 return out;
00088 }
00089
00090 static uint64_t int_sqrt(uint64_t a)
00091 {
00092 uint64_t ret = 0;
00093 uint64_t ret_sq = 0;
00094 int s;
00095
00096 for (s = 31; s >= 0; s--) {
00097 uint64_t b = ret_sq + (1ULL << (s * 2)) + (ret << s) * 2;
00098 if (b <= a) {
00099 ret_sq = b;
00100 ret += 1ULL << s;
00101 }
00102 }
00103 return ret;
00104 }
00105
00106 static int run_psnr(FILE *f[2], int len, int shift, int skip_bytes)
00107 {
00108 int i, j;
00109 uint64_t sse = 0;
00110 uint64_t dev;
00111 uint8_t buf[2][SIZE];
00112 uint64_t psnr;
00113 int64_t max = (1 << (8 * len)) - 1;
00114 int size0 = 0;
00115 int size1 = 0;
00116 int maxdist = 0;
00117 int noseek;
00118
00119 noseek = fseek(f[0], 0, SEEK_SET) ||
00120 fseek(f[1], 0, SEEK_SET);
00121
00122 if (!noseek) {
00123 for (i = 0; i < 2; i++) {
00124 uint8_t *p = buf[i];
00125 if (fread(p, 1, 12, f[i]) != 12)
00126 return 1;
00127 if (!memcmp(p, "RIFF", 4) &&
00128 !memcmp(p + 8, "WAVE", 4)) {
00129 if (fread(p, 1, 8, f[i]) != 8)
00130 return 1;
00131 while (memcmp(p, "data", 4)) {
00132 int s = p[4] | p[5] << 8 | p[6] << 16 | p[7] << 24;
00133 fseek(f[i], s, SEEK_CUR);
00134 if (fread(p, 1, 8, f[i]) != 8)
00135 return 1;
00136 }
00137 } else {
00138 fseek(f[i], -12, SEEK_CUR);
00139 }
00140 }
00141
00142 fseek(f[shift < 0], abs(shift), SEEK_CUR);
00143
00144 fseek(f[0], skip_bytes, SEEK_CUR);
00145 fseek(f[1], skip_bytes, SEEK_CUR);
00146 }
00147
00148 for (;;) {
00149 int s0 = fread(buf[0], 1, SIZE, f[0]);
00150 int s1 = fread(buf[1], 1, SIZE, f[1]);
00151
00152 for (j = 0; j < FFMIN(s0, s1); j++) {
00153 int64_t a = buf[0][j];
00154 int64_t b = buf[1][j];
00155 int dist;
00156 if (len == 2) {
00157 a = (int16_t)(a | (buf[0][++j] << 8));
00158 b = (int16_t)(b | (buf[1][ j] << 8));
00159 }
00160 sse += (a - b) * (a - b);
00161 dist = abs(a - b);
00162 if (dist > maxdist)
00163 maxdist = dist;
00164 }
00165 size0 += s0;
00166 size1 += s1;
00167 if (s0 + s1 <= 0)
00168 break;
00169 }
00170
00171 i = FFMIN(size0, size1) / len;
00172 if (!i)
00173 i = 1;
00174 dev = int_sqrt(((sse / i) * F * F) + (((sse % i) * F * F) + i / 2) / i);
00175 if (sse)
00176 psnr = ((2 * log16(max << 16) + log16(i) - log16(sse)) *
00177 284619LL * F + (1LL << 31)) / (1LL << 32);
00178 else
00179 psnr = 1000 * F - 1;
00180
00181 printf("stddev:%5d.%02d PSNR:%3d.%02d MAXDIFF:%5d bytes:%9d/%9d\n",
00182 (int)(dev / F), (int)(dev % F),
00183 (int)(psnr / F), (int)(psnr % F),
00184 maxdist, size0, size1);
00185 return psnr;
00186 }
00187
00188 int main(int argc, char *argv[])
00189 {
00190 FILE *f[2];
00191 int len = argc < 4 ? 1 : atoi(argv[3]);
00192 int shift_first= argc < 5 ? 0 : atoi(argv[4]);
00193 int skip_bytes = argc < 6 ? 0 : atoi(argv[5]);
00194 int shift_last = shift_first + (argc < 7 ? 0 : atoi(argv[6]));
00195 int shift;
00196 int max_psnr = -1;
00197 int max_psnr_shift = 0;
00198
00199 if (argc < 3) {
00200 printf("tiny_psnr <file1> <file2> [<elem size> [<shift> [<skip bytes> [<shift search range>]]]]\n");
00201 printf("WAV headers are skipped automatically.\n");
00202 return 1;
00203 }
00204
00205 f[0] = fopen(argv[1], "rb");
00206 f[1] = fopen(argv[2], "rb");
00207 if (!f[0] || !f[1]) {
00208 fprintf(stderr, "Could not open input files.\n");
00209 return 1;
00210 }
00211
00212 for (shift = shift_first; shift <= shift_last; shift++) {
00213 int psnr = run_psnr(f, len, shift, skip_bytes);
00214 if (psnr > max_psnr || (shift < 0 && psnr == max_psnr)) {
00215 max_psnr = psnr;
00216 max_psnr_shift = shift;
00217 }
00218 }
00219 if (shift_last > shift_first)
00220 printf("Best PSNR is %3d.%02d for shift %i\n", (int)(max_psnr / F), (int)(max_psnr % F), max_psnr_shift);
00221 return 0;
00222 }