2001-12-23 20:21:19 +00:00
|
|
|
/*
|
|
|
|
* ieeetest.c --- test IDCT code against the IEEE Std 1180-1990 spec
|
|
|
|
*
|
|
|
|
* Note that this does only one pass of the test.
|
|
|
|
* Six invocations of ieeetest are needed to complete the entire spec.
|
|
|
|
* The shell script "doieee" performs the complete test.
|
|
|
|
*
|
|
|
|
* Written by Tom Lane (tgl@cs.cmu.edu).
|
|
|
|
* Released to public domain 11/22/93.
|
|
|
|
*/
|
|
|
|
|
2003-11-07 12:47:02 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2001-12-23 20:21:19 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <gst/gst.h>
|
2001-12-25 22:30:51 +00:00
|
|
|
#include <gst/idct/idct.h>
|
2001-12-23 20:21:19 +00:00
|
|
|
#include "dct.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* prototypes */
|
|
|
|
|
|
|
|
void usage (char *msg);
|
|
|
|
long ieeerand (long L, long H);
|
2004-03-14 22:34:34 +00:00
|
|
|
void dct_init (void);
|
|
|
|
void ref_fdct (DCTELEM block[8][8]);
|
|
|
|
void ref_idct (DCTELEM block[8][8]);
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
/* error stat accumulators -- assume initialized to 0 */
|
|
|
|
|
|
|
|
long sumerrs[DCTSIZE2];
|
|
|
|
long sumsqerrs[DCTSIZE2];
|
|
|
|
int maxerr[DCTSIZE2];
|
|
|
|
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
char *
|
|
|
|
meets (double val, double limit)
|
2001-12-23 20:21:19 +00:00
|
|
|
{
|
2004-03-14 22:34:34 +00:00
|
|
|
return ((fabs (val) <= limit) ? "meets" : "FAILS");
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-14 22:34:34 +00:00
|
|
|
main (int argc, char **argv)
|
2001-12-23 20:21:19 +00:00
|
|
|
{
|
|
|
|
long minpix, maxpix, sign;
|
|
|
|
long curiter, niters;
|
|
|
|
int i, j;
|
|
|
|
double max, total;
|
|
|
|
int method;
|
2004-03-15 19:32:28 +00:00
|
|
|
DCTELEM block[DCTSIZE2]; /* random source data */
|
|
|
|
DCTELEM refcoefs[DCTSIZE2]; /* coefs from reference FDCT */
|
|
|
|
DCTELEM refout[DCTSIZE2]; /* output from reference IDCT */
|
|
|
|
DCTELEM testout[DCTSIZE2]; /* output from test IDCT */
|
2004-03-14 22:34:34 +00:00
|
|
|
GstIDCT *idct;
|
|
|
|
guint64 tscstart, tscmin = ~0, tscmax = 0;
|
|
|
|
guint64 tscstop;
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
/* Argument parsing --- not very bulletproof at all */
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
if (argc != 6)
|
|
|
|
usage (NULL);
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
method = atoi (argv[1]);
|
|
|
|
minpix = atoi (argv[2]);
|
|
|
|
maxpix = atoi (argv[3]);
|
|
|
|
sign = atoi (argv[4]);
|
|
|
|
niters = atol (argv[5]);
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
gst_library_load ("gstidct");
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
idct = gst_idct_new (method);
|
2001-12-23 20:21:19 +00:00
|
|
|
if (idct == 0) {
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("method not available\n\n\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
dct_init ();
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
/* Loop once per generated random-data block */
|
|
|
|
|
|
|
|
for (curiter = 0; curiter < niters; curiter++) {
|
|
|
|
|
|
|
|
/* generate a pseudo-random block of data */
|
|
|
|
for (i = 0; i < DCTSIZE2; i++)
|
2004-03-14 22:34:34 +00:00
|
|
|
block[i] = (DCTELEM) (ieeerand (-minpix, maxpix) * sign);
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
/* perform reference FDCT */
|
2004-03-14 22:34:34 +00:00
|
|
|
memcpy (refcoefs, block, sizeof (DCTELEM) * DCTSIZE2);
|
|
|
|
ref_fdct ((DCTELEM **) & refcoefs);
|
2001-12-23 20:21:19 +00:00
|
|
|
/* clip */
|
|
|
|
for (i = 0; i < DCTSIZE2; i++) {
|
2004-03-14 22:34:34 +00:00
|
|
|
if (refcoefs[i] < -2048)
|
2004-03-15 19:32:28 +00:00
|
|
|
refcoefs[i] = -2048;
|
2004-03-14 22:34:34 +00:00
|
|
|
else if (refcoefs[i] > 2047)
|
2004-03-15 19:32:28 +00:00
|
|
|
refcoefs[i] = 2047;
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* perform reference IDCT */
|
2004-03-14 22:34:34 +00:00
|
|
|
memcpy (refout, refcoefs, sizeof (DCTELEM) * DCTSIZE2);
|
|
|
|
ref_idct (refout);
|
2001-12-23 20:21:19 +00:00
|
|
|
/* clip */
|
|
|
|
for (i = 0; i < DCTSIZE2; i++) {
|
2004-03-14 22:34:34 +00:00
|
|
|
if (refout[i] < -256)
|
2004-03-15 19:32:28 +00:00
|
|
|
refout[i] = -256;
|
2004-03-14 22:34:34 +00:00
|
|
|
else if (refout[i] > 255)
|
2004-03-15 19:32:28 +00:00
|
|
|
refout[i] = 255;
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* perform test IDCT */
|
2004-03-14 22:34:34 +00:00
|
|
|
if (GST_IDCT_TRANSPOSE (idct)) {
|
2001-12-23 20:21:19 +00:00
|
|
|
for (j = 0; j < DCTSIZE; j++) {
|
2004-03-15 19:32:28 +00:00
|
|
|
for (i = 0; i < DCTSIZE; i++) {
|
|
|
|
testout[i * DCTSIZE + j] = refcoefs[j * DCTSIZE + i];
|
|
|
|
}
|
2004-03-14 22:34:34 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy (testout, refcoefs, sizeof (DCTELEM) * DCTSIZE2);
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_trace_read_tsc (&tscstart);
|
|
|
|
gst_idct_convert (idct, testout);
|
|
|
|
gst_trace_read_tsc (&tscstop);
|
|
|
|
/*printf("time %llu, %llu %lld\n", tscstart, tscstop, tscstop-tscstart); */
|
|
|
|
if (tscstop - tscstart < tscmin)
|
|
|
|
tscmin = tscstop - tscstart;
|
|
|
|
if (tscstop - tscstart > tscmax)
|
|
|
|
tscmax = tscstop - tscstart;
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
/* clip */
|
|
|
|
for (i = 0; i < DCTSIZE2; i++) {
|
2004-03-14 22:34:34 +00:00
|
|
|
if (testout[i] < -256)
|
2004-03-15 19:32:28 +00:00
|
|
|
testout[i] = -256;
|
2004-03-14 22:34:34 +00:00
|
|
|
else if (testout[i] > 255)
|
2004-03-15 19:32:28 +00:00
|
|
|
testout[i] = 255;
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* accumulate error stats */
|
|
|
|
for (i = 0; i < DCTSIZE2; i++) {
|
|
|
|
register int err = testout[i] - refout[i];
|
2004-03-14 22:34:34 +00:00
|
|
|
|
2001-12-23 20:21:19 +00:00
|
|
|
sumerrs[i] += err;
|
|
|
|
sumsqerrs[i] += err * err;
|
2004-03-14 22:34:34 +00:00
|
|
|
if (err < 0)
|
2004-03-15 19:32:28 +00:00
|
|
|
err = -err;
|
2004-03-14 22:34:34 +00:00
|
|
|
if (maxerr[i] < err)
|
2004-03-15 19:32:28 +00:00
|
|
|
maxerr[i] = err;
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (curiter % 100 == 99) {
|
2004-03-14 22:34:34 +00:00
|
|
|
fprintf (stderr, ".");
|
|
|
|
fflush (stderr);
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
}
|
2004-03-14 22:34:34 +00:00
|
|
|
fprintf (stderr, "\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
/* print results */
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
printf
|
|
|
|
("IEEE test conditions: -L = %ld, +H = %ld, sign = %ld, #iters = %ld\n",
|
|
|
|
minpix, maxpix, sign, niters);
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Speed, min time %lld, max %lld\n", tscmin, tscmax);
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Peak absolute values of errors:\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
for (i = 0, j = 0; i < DCTSIZE2; i++) {
|
2004-03-14 22:34:34 +00:00
|
|
|
if (j < maxerr[i])
|
|
|
|
j = maxerr[i];
|
|
|
|
printf ("%4d", maxerr[i]);
|
|
|
|
if ((i % DCTSIZE) == DCTSIZE - 1)
|
|
|
|
printf ("\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Worst peak error = %d (%s spec limit 1)\n\n", j,
|
|
|
|
meets ((double) j, 1.0));
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Mean square errors:\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
max = total = 0.0;
|
|
|
|
for (i = 0; i < DCTSIZE2; i++) {
|
2004-03-14 22:34:34 +00:00
|
|
|
double err = (double) sumsqerrs[i] / ((double) niters);
|
|
|
|
|
2001-12-23 20:21:19 +00:00
|
|
|
total += (double) sumsqerrs[i];
|
2004-03-14 22:34:34 +00:00
|
|
|
if (max < err)
|
|
|
|
max = err;
|
|
|
|
printf (" %8.4f", err);
|
|
|
|
if ((i % DCTSIZE) == DCTSIZE - 1)
|
|
|
|
printf ("\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Worst pmse = %.6f (%s spec limit 0.06)\n", max, meets (max, 0.06));
|
|
|
|
total /= (double) (64 * niters);
|
|
|
|
printf ("Overall mse = %.6f (%s spec limit 0.02)\n\n", total,
|
|
|
|
meets (total, 0.02));
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Mean errors:\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
max = total = 0.0;
|
|
|
|
for (i = 0; i < DCTSIZE2; i++) {
|
2004-03-14 22:34:34 +00:00
|
|
|
double err = (double) sumerrs[i] / ((double) niters);
|
|
|
|
|
2001-12-23 20:21:19 +00:00
|
|
|
total += (double) sumerrs[i];
|
2004-03-14 22:34:34 +00:00
|
|
|
printf (" %8.4f", err);
|
|
|
|
if (err < 0.0)
|
|
|
|
err = -err;
|
|
|
|
if (max < err)
|
|
|
|
max = err;
|
|
|
|
if ((i % DCTSIZE) == DCTSIZE - 1)
|
|
|
|
printf ("\n");
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Worst mean error = %.6f (%s spec limit 0.015)\n", max,
|
|
|
|
meets (max, 0.015));
|
|
|
|
total /= (double) (64 * niters);
|
|
|
|
printf ("Overall mean error = %.6f (%s spec limit 0.0015)\n\n", total,
|
|
|
|
meets (total, 0.0015));
|
2001-12-23 20:21:19 +00:00
|
|
|
|
|
|
|
/* test for 0 input giving 0 output */
|
2004-03-14 22:34:34 +00:00
|
|
|
memset (testout, 0, sizeof (DCTELEM) * DCTSIZE2);
|
|
|
|
gst_idct_convert (idct, testout);
|
|
|
|
for (i = 0, j = 0; i < DCTSIZE2; i++) {
|
2001-12-23 20:21:19 +00:00
|
|
|
if (testout[i]) {
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("Position %d of IDCT(0) = %d (FAILS)\n", i, testout[i]);
|
2001-12-23 20:21:19 +00:00
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
2004-03-14 22:34:34 +00:00
|
|
|
printf ("%d elements of IDCT(0) were not zero\n\n\n", j);
|
2001-12-23 20:21:19 +00:00
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
exit (0);
|
2001-12-23 20:21:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
void
|
|
|
|
usage (char *msg)
|
2001-12-23 20:21:19 +00:00
|
|
|
{
|
|
|
|
if (msg != NULL)
|
2004-03-14 22:34:34 +00:00
|
|
|
fprintf (stderr, "\nerror: %s\n", msg);
|
|
|
|
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
fprintf (stderr, "usage: ieeetest minpix maxpix sign niters\n");
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
fprintf (stderr, " test = 1 - 5\n");
|
|
|
|
fprintf (stderr, " minpix = -L value per IEEE spec\n");
|
|
|
|
fprintf (stderr, " maxpix = H value per IEEE spec\n");
|
|
|
|
fprintf (stderr, " sign = +1 for normal, -1 to run negated test\n");
|
|
|
|
fprintf (stderr, " niters = # iterations (10000 for full test)\n");
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
|
|
|
|
exit (1);
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Pseudo-random generator specified by IEEE 1180 */
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
long
|
|
|
|
ieeerand (long L, long H)
|
2001-12-23 20:21:19 +00:00
|
|
|
{
|
|
|
|
static long randx = 1;
|
|
|
|
static double z = (double) 0x7fffffff;
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
long i, j;
|
2001-12-23 20:21:19 +00:00
|
|
|
double x;
|
|
|
|
|
|
|
|
randx = (randx * 1103515245) + 12345;
|
|
|
|
i = randx & 0x7ffffffe;
|
|
|
|
x = ((double) i) / z;
|
2004-03-14 22:34:34 +00:00
|
|
|
x *= (L + H + 1);
|
2001-12-23 20:21:19 +00:00
|
|
|
j = x;
|
2004-03-14 22:34:34 +00:00
|
|
|
return j - L;
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Reference double-precision FDCT and IDCT */
|
|
|
|
|
|
|
|
|
|
|
|
/* The cosine lookup table */
|
|
|
|
/* coslu[a][b] = C(b)/2 * cos[(2a+1)b*pi/16] */
|
|
|
|
double coslu[8][8];
|
|
|
|
|
|
|
|
|
|
|
|
/* Routine to initialise the cosine lookup table */
|
2004-03-14 22:34:34 +00:00
|
|
|
void
|
|
|
|
dct_init (void)
|
2001-12-23 20:21:19 +00:00
|
|
|
{
|
2004-03-14 22:34:34 +00:00
|
|
|
int a, b;
|
2001-12-23 20:21:19 +00:00
|
|
|
double tmp;
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
for (a = 0; a < 8; a++)
|
|
|
|
for (b = 0; b < 8; b++) {
|
|
|
|
tmp = cos ((double) ((a + a + 1) * b) * (3.14159265358979323846 / 16.0));
|
|
|
|
if (b == 0)
|
2004-03-15 19:32:28 +00:00
|
|
|
tmp /= sqrt (2.0);
|
2001-12-23 20:21:19 +00:00
|
|
|
coslu[a][b] = tmp * 0.5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
void
|
|
|
|
ref_fdct (DCTELEM block[8][8])
|
2001-12-23 20:21:19 +00:00
|
|
|
{
|
2004-03-14 22:34:34 +00:00
|
|
|
int x, y, u, v;
|
2001-12-23 20:21:19 +00:00
|
|
|
double tmp, tmp2;
|
|
|
|
double res[8][8];
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
for (v = 0; v < 8; v++) {
|
|
|
|
for (u = 0; u < 8; u++) {
|
2001-12-23 20:21:19 +00:00
|
|
|
tmp = 0.0;
|
2004-03-14 22:34:34 +00:00
|
|
|
for (y = 0; y < 8; y++) {
|
2004-03-15 19:32:28 +00:00
|
|
|
tmp2 = 0.0;
|
|
|
|
for (x = 0; x < 8; x++) {
|
|
|
|
tmp2 += (double) block[y][x] * coslu[x][u];
|
|
|
|
}
|
|
|
|
tmp += coslu[y][v] * tmp2;
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
res[v][u] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
for (v = 0; v < 8; v++) {
|
|
|
|
for (u = 0; u < 8; u++) {
|
2001-12-23 20:21:19 +00:00
|
|
|
tmp = res[v][u];
|
|
|
|
if (tmp < 0.0) {
|
2004-03-15 19:32:28 +00:00
|
|
|
x = -((int) (0.5 - tmp));
|
2001-12-23 20:21:19 +00:00
|
|
|
} else {
|
2004-03-15 19:32:28 +00:00
|
|
|
x = (int) (tmp + 0.5);
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
block[v][u] = (DCTELEM) x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
void
|
|
|
|
ref_idct (DCTELEM block[8][8])
|
2001-12-23 20:21:19 +00:00
|
|
|
{
|
2004-03-14 22:34:34 +00:00
|
|
|
int x, y, u, v;
|
2001-12-23 20:21:19 +00:00
|
|
|
double tmp, tmp2;
|
|
|
|
double res[8][8];
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
for (y = 0; y < 8; y++) {
|
|
|
|
for (x = 0; x < 8; x++) {
|
2001-12-23 20:21:19 +00:00
|
|
|
tmp = 0.0;
|
2004-03-14 22:34:34 +00:00
|
|
|
for (v = 0; v < 8; v++) {
|
2004-03-15 19:32:28 +00:00
|
|
|
tmp2 = 0.0;
|
|
|
|
for (u = 0; u < 8; u++) {
|
|
|
|
tmp2 += (double) block[v][u] * coslu[x][u];
|
|
|
|
}
|
|
|
|
tmp += coslu[y][v] * tmp2;
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
res[y][x] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-14 22:34:34 +00:00
|
|
|
for (v = 0; v < 8; v++) {
|
|
|
|
for (u = 0; u < 8; u++) {
|
2001-12-23 20:21:19 +00:00
|
|
|
tmp = res[v][u];
|
|
|
|
if (tmp < 0.0) {
|
2004-03-15 19:32:28 +00:00
|
|
|
x = -((int) (0.5 - tmp));
|
2001-12-23 20:21:19 +00:00
|
|
|
} else {
|
2004-03-15 19:32:28 +00:00
|
|
|
x = (int) (tmp + 0.5);
|
2001-12-23 20:21:19 +00:00
|
|
|
}
|
|
|
|
block[v][u] = (DCTELEM) x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|