home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Meia / source / idct_test.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  9.0 KB  |  331 lines

  1. // IDCT test module for VirtualDub
  2. //
  3. // This code is based on a test harness released into the public domain by
  4. // Tom Lane, the comment block of which is reproduced below:
  5. //
  6.     /*
  7.      * ieeetest.c --- test IDCT code against the IEEE Std 1180-1990 spec
  8.      *
  9.      * Note that this does only one pass of the test.
  10.      * Six invocations of ieeetest are needed to complete the entire spec.
  11.      * The shell script "doieee" performs the complete test.
  12.      *
  13.      * Written by Tom Lane (tgl@cs.cmu.edu).
  14.      * Released to public domain 11/22/93.
  15.      */
  16. //
  17. // As Mr. Lane graciously released his test harness into the public domain,
  18. // I think it only fair that I do the same for mine that is based on his.
  19. // Note that this applies only to this module, and not to other parts of
  20. // VirtualDub.
  21. //
  22. // Modified by Avery Lee <phaeron@virtualdub.org>
  23. // Released to public domain 06/07/2003.
  24. //
  25.  
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <math.h>
  30.  
  31. #include <vd2/Meia/MPEGIDCT.h>
  32.  
  33. namespace {
  34.     typedef int DCTELEM;
  35.  
  36.     inline DCTELEM fastround(double v) {
  37.         return v>0 ? (DCTELEM)(v+0.5) : -(DCTELEM)(0.5-v);
  38.     }
  39.  
  40.     // Pseudo-random generator specified by IEEE 1180
  41.     class IEEE1180Random {
  42.     public:
  43.         IEEE1180Random() : seed(1) {}
  44.  
  45.         long seed;
  46.  
  47.         long operator()(long L, long H) {
  48.           static double z = (double) 0x7fffffff;
  49.  
  50.           long i,j;
  51.           double x;
  52.  
  53.           seed = (seed * 1103515245) + 12345;
  54.           i = seed & 0x7ffffffe;
  55.           x = ((double) i) / z;
  56.           x *= (L+H+1);
  57.           j = (long)x;
  58.           return j-L;
  59.         }
  60.     };
  61.  
  62.     class IDCTTest {
  63.     public:
  64.         IDCTTest(const VDMPEGIDCTSet& idct);
  65.  
  66.         bool Test(VDIDCTComplianceResult& result);
  67.  
  68.     protected:
  69.         bool RunSingleTest(long minpix, long maxpix, long sign, long niters, VDIDCTTestResult& result);
  70.         void RunTestIDCT(DCTELEM block[64]);
  71.         void ReferenceFDCT(DCTELEM block[8][8]);
  72.         void ReferenceIDCT(DCTELEM block[8][8]);
  73.  
  74.         const VDMPEGIDCTSet& mIDCT;
  75.         double    mBasis[8][8];        // mBasis[a][b] = C(b)/2 * cos[(2a+1)b*pi/16]
  76.     };
  77.  
  78.     IDCTTest::IDCTTest(const VDMPEGIDCTSet& idct) : mIDCT(idct) {
  79.         // init DCT basis function lookup table
  80.         for(int a=0; a<8; ++a) {
  81.             for(int b=0; b<8; ++b) {
  82.                 double tmp = cos(((a+a+1)*b) * (3.14159265358979323846 / 16.0));
  83.                 if(b==0)
  84.                     tmp /= sqrt(2.0);
  85.                 mBasis[a][b] = tmp * 0.5;
  86.             }
  87.         }
  88.     }
  89.  
  90.     bool IDCTTest::Test(VDIDCTComplianceResult& result) {
  91.         bool passed;
  92.         
  93.         passed  = RunSingleTest(-256, 255,  1, 10000, result.tests[0]);
  94.         passed &= RunSingleTest(  -5,   5,  1, 10000, result.tests[1]);
  95.         passed &= RunSingleTest(-300, 300,  1, 10000, result.tests[2]);
  96.         passed &= RunSingleTest(-256, 255, -1, 10000, result.tests[3]);
  97.         passed &= RunSingleTest(  -5,   5, -1, 10000, result.tests[4]);
  98.         passed &= RunSingleTest(-300, 300, -1, 10000, result.tests[5]);
  99.  
  100.         /* test for 0 input giving 0 output */
  101.         DCTELEM testout[64]={0};
  102.         RunTestIDCT(testout);
  103.         result.mbZeroTestOK = true;
  104.         for (int i = 0; i < 64; i++) {
  105.             if (testout[i]) {
  106.                 result.mbZeroTestOK = false;
  107.                 passed = false;
  108.                 break;
  109.             }
  110.         }
  111.  
  112.         return result.mbPassed = passed;
  113.     }
  114.  
  115.     bool IDCTTest::RunSingleTest(long minpix, long maxpix, long sign, long niters, VDIDCTTestResult& result) {
  116.         memset(&result, 0, sizeof result);
  117.  
  118.         result.mRangeLow    = minpix;
  119.         result.mRangeHigh    = maxpix;
  120.         result.mSign        = sign;
  121.         result.mIterations    = niters;
  122.         
  123.         long curiter;
  124.         int i;
  125.         double max, total;
  126.         DCTELEM   block[64];    /* random source data */
  127.         DCTELEM   refcoefs[64]; /* coefs from reference FDCT */
  128.         DCTELEM   refout[64];    /* output from reference IDCT */
  129.         DCTELEM   testout[64]; /* output from test IDCT */
  130.         
  131.         /* Loop once per generated random-data block */
  132.         
  133.         IEEE1180Random randgen;
  134.         
  135.         for (curiter = 0; curiter < niters; curiter++) {
  136.             
  137.             /* generate a pseudo-random block of data */
  138.             for (i = 0; i < 64; i++)
  139.                 block[i] = (DCTELEM) (randgen(-minpix,maxpix) * sign);
  140.             
  141.             /* perform reference FDCT */
  142.             memcpy(refcoefs, block, sizeof(DCTELEM)*64);
  143.             ReferenceFDCT((DCTELEM (*)[8])refcoefs);
  144.             /* clip */
  145.             for (i = 0; i < 64; i++) {
  146.                 if (refcoefs[i] < -2048) refcoefs[i] = -2048;
  147.                 else if (refcoefs[i] > 2047) refcoefs[i] = 2047;
  148.             }
  149.             
  150.             /* perform reference IDCT */
  151.             memcpy(refout, refcoefs, sizeof(DCTELEM)*64);
  152.             ReferenceIDCT((DCTELEM (*)[8])refout);
  153.             /* clip */
  154.             for (i = 0; i < 64; i++) {
  155.                 if (refout[i] < -256) refout[i] = -256;
  156.                 else if (refout[i] > 255) refout[i] = 255;
  157.             }
  158.             
  159.             /* perform test IDCT */
  160.             memcpy(testout, refcoefs, sizeof(DCTELEM)*64);
  161.             RunTestIDCT(testout);
  162.             /* clip */
  163.             for (i = 0; i < 64; i++) {
  164.                 if (testout[i] < -256) testout[i] = -256;
  165.                 else if (testout[i] > 255) testout[i] = 255;
  166.             }
  167.             
  168.             /* accumulate error stats */
  169.             for (i = 0; i < 64; i++) {
  170.                 register int err = testout[i] - refout[i];
  171.                 result.mMeanErrors[i] += err;
  172.                 result.mSquaredErrors[i] += err * err;
  173.                 if (err < 0) err = -err;
  174.                 if (result.mMaxErrors[i] < err) result.mMaxErrors[i] = err;
  175.             }
  176.         }
  177.                 
  178.         for (i = 0; i < 64; i++) {
  179.             if (result.mMaxErrors[i] > result.mMaximumError)
  180.                 result.mMaximumError = result.mMaxErrors[i];
  181.         }
  182.         result.mbMaxErrorOK = result.mMaximumError <= 1;
  183.         
  184.         max = total = 0.0;
  185.         for (i = 0; i < 64; i++) {
  186.             double err = result.mSquaredErrors[i] /= (double) niters;
  187.             total += err;
  188.             if (max < err) max = err;
  189.         }
  190.         total /= 64.0;
  191.  
  192.         result.mWorstSquaredError = max;
  193.         result.mAverageSquaredError = total;
  194.         result.mbWorstSquaredErrorOK = (max <= 0.06);
  195.         result.mbAverageSquaredErrorOK = (total <= 0.02);
  196.         
  197.         max = total = 0.0;
  198.         for (i = 0; i < 64; i++) {
  199.             double err = result.mMeanErrors[i] /= (double) niters;
  200.             total += err;
  201.             if (err < 0.0) err = -err;
  202.             if (max < err) max = err;
  203.         }
  204.         total /= 64.0;
  205.         result.mWorstError = max;
  206.         result.mAverageError = total;
  207.         result.mbWorstErrorOK = (max <= 0.015);
  208.         result.mbAverageErrorOK = (total <= 0.0015);
  209.  
  210.         return result.mbMaxErrorOK && result.mbWorstSquaredErrorOK && result.mbAverageSquaredErrorOK && result.mbWorstErrorOK && result.mbAverageErrorOK;
  211.     }
  212.  
  213.     void IDCTTest::RunTestIDCT(DCTELEM block[64]) {
  214.         static const int zigzag_std[64]={
  215.              0,  1,  8, 16,  9,  2,  3, 10,
  216.             17, 24, 32, 25, 18, 11,  4,  5,
  217.             12, 19, 26, 33, 40, 48, 41, 34,
  218.             27, 20, 13,  6,  7, 14, 21, 28,
  219.             35, 42, 49, 56, 57, 50, 43, 36,
  220.             29, 22, 15, 23, 30, 37, 44, 51,
  221.             58, 59, 52, 45, 38, 31, 39, 46,
  222.             53, 60, 61, 54, 47, 55, 62, 63,
  223.         };
  224.  
  225.         int i;
  226.  
  227.         const int *scan = mIDCT.pAltScan?mIDCT.pAltScan:zigzag_std;
  228.         if (mIDCT.pPrescaler) {
  229.             int tmp[64];
  230.             for(i=0; i<64; ++i) {
  231.                 const int dst = scan[i];
  232.                 tmp[dst] = (block[zigzag_std[i]] * mIDCT.pPrescaler[dst] + 128) >> 8;
  233.             }
  234.  
  235.             mIDCT.pTest(tmp, 63);
  236.  
  237.             for(i=0; i<64; ++i)
  238.                 block[i] = tmp[i];
  239.         } else {
  240.             short tmp[64];
  241.             for(i=0; i<64; ++i) {
  242.                 const int dst = scan[i];
  243.                 tmp[dst] = block[zigzag_std[i]];
  244.             }
  245.  
  246.             mIDCT.pTest(tmp, 63);
  247.  
  248.             for(i=0; i<64; ++i)
  249.                 block[i] = tmp[i];
  250.         }
  251.     }
  252.  
  253.     // I hate waiting.
  254.     void IDCTTest::ReferenceFDCT(DCTELEM block[8][8]) {
  255.         int x,y;
  256.         double tmp;
  257.         double res[8][8];
  258.         
  259.         // row transform
  260.         for (y=0; y<8; y++) {
  261.             for (x=0; x<8; x++) {
  262.                 tmp = (double) block[y][0] * mBasis[0][x]
  263.                     + (double) block[y][1] * mBasis[1][x]
  264.                     + (double) block[y][2] * mBasis[2][x]
  265.                     + (double) block[y][3] * mBasis[3][x]
  266.                     + (double) block[y][4] * mBasis[4][x]
  267.                     + (double) block[y][5] * mBasis[5][x]
  268.                     + (double) block[y][6] * mBasis[6][x]
  269.                     + (double) block[y][7] * mBasis[7][x];
  270.                 res[y][x] = tmp;
  271.             }
  272.         }
  273.         
  274.         // column transform
  275.         for (x=0; x<8; x++) {
  276.             for (y=0; y<8; y++) {
  277.                 tmp = res[0][x] * mBasis[0][y]
  278.                     + res[1][x] * mBasis[1][y]
  279.                     + res[2][x] * mBasis[2][y]
  280.                     + res[3][x] * mBasis[3][y]
  281.                     + res[4][x] * mBasis[4][y]
  282.                     + res[5][x] * mBasis[5][y]
  283.                     + res[6][x] * mBasis[6][y]
  284.                     + res[7][x] * mBasis[7][y];
  285.                 block[y][x] = (DCTELEM) fastround(tmp);
  286.             }
  287.         }    
  288.     }
  289.  
  290.  
  291.     void IDCTTest::ReferenceIDCT(DCTELEM block[8][8]) {
  292.         int x,y;
  293.         double tmp;
  294.         double res[8][8];
  295.         
  296.         // row transform
  297.         for (y=0; y<8; y++) {
  298.             for (x=0; x<8; x++) {
  299.                 tmp = (double) block[y][0] * mBasis[x][0]
  300.                     + (double) block[y][1] * mBasis[x][1]
  301.                     + (double) block[y][2] * mBasis[x][2]
  302.                     + (double) block[y][3] * mBasis[x][3]
  303.                     + (double) block[y][4] * mBasis[x][4]
  304.                     + (double) block[y][5] * mBasis[x][5]
  305.                     + (double) block[y][6] * mBasis[x][6]
  306.                     + (double) block[y][7] * mBasis[x][7];
  307.                 res[y][x] = tmp;
  308.             }
  309.         }
  310.         
  311.         // column transform
  312.         for (x=0; x<8; x++) {
  313.             for (y=0; y<8; y++) {
  314.                 tmp = res[0][x] * mBasis[y][0]
  315.                     + res[1][x] * mBasis[y][1]
  316.                     + res[2][x] * mBasis[y][2]
  317.                     + res[3][x] * mBasis[y][3]
  318.                     + res[4][x] * mBasis[y][4]
  319.                     + res[5][x] * mBasis[y][5]
  320.                     + res[6][x] * mBasis[y][6]
  321.                     + res[7][x] * mBasis[y][7];
  322.                 block[y][x] = (DCTELEM) fastround(tmp);
  323.             }
  324.         }    
  325.     }
  326. }
  327.  
  328. bool VDTestVideoIDCTCompliance(const VDMPEGIDCTSet& idct, VDIDCTComplianceResult& result) {
  329.     return IDCTTest(idct).Test(result);
  330. }
  331.