Home | History | Annotate | Download | only in test
      1 /*
      2 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 
     12 #include <math.h>
     13 #include <stddef.h>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 #include <sys/types.h>
     18 
     19 
     20 extern "C" {
     21 #include "./vp8_rtcd.h"
     22 }
     23 
     24 #include "test/acm_random.h"
     25 #include "third_party/googletest/src/include/gtest/gtest.h"
     26 #include "vpx/vpx_integer.h"
     27 
     28 
     29 namespace {
     30 
     31 const int cospi8sqrt2minus1 = 20091;
     32 const int sinpi8sqrt2 = 35468;
     33 
     34 void reference_idct4x4(const int16_t *input, int16_t *output) {
     35   const int16_t *ip = input;
     36   int16_t *op = output;
     37 
     38   for (int i = 0; i < 4; ++i) {
     39     const int a1 = ip[0] + ip[8];
     40     const int b1 = ip[0] - ip[8];
     41     const int temp1 = (ip[4] * sinpi8sqrt2) >> 16;
     42     const int temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
     43     const int c1 = temp1 - temp2;
     44     const int temp3 = ip[4] + ((ip[4] * cospi8sqrt2minus1) >> 16);
     45     const int temp4 = (ip[12] * sinpi8sqrt2) >> 16;
     46     const int d1 = temp3 + temp4;
     47     op[0] = a1 + d1;
     48     op[12] = a1 - d1;
     49     op[4] = b1 + c1;
     50     op[8] = b1 - c1;
     51     ++ip;
     52     ++op;
     53   }
     54   ip = output;
     55   op = output;
     56   for (int i = 0; i < 4; ++i) {
     57     const int a1 = ip[0] + ip[2];
     58     const int b1 = ip[0] - ip[2];
     59     const int temp1 = (ip[1] * sinpi8sqrt2) >> 16;
     60     const int temp2 = ip[3] + ((ip[3] * cospi8sqrt2minus1) >> 16);
     61     const int c1 = temp1 - temp2;
     62     const int temp3 = ip[1] + ((ip[1] * cospi8sqrt2minus1) >> 16);
     63     const int temp4 = (ip[3] * sinpi8sqrt2) >> 16;
     64     const int d1 = temp3 + temp4;
     65     op[0] = (a1 + d1 + 4) >> 3;
     66     op[3] = (a1 - d1 + 4) >> 3;
     67     op[1] = (b1 + c1 + 4) >> 3;
     68     op[2] = (b1 - c1 + 4) >> 3;
     69     ip += 4;
     70     op += 4;
     71   }
     72 }
     73 
     74 using libvpx_test::ACMRandom;
     75 
     76 TEST(Vp8FdctTest, SignBiasCheck) {
     77   ACMRandom rnd(ACMRandom::DeterministicSeed());
     78   int16_t test_input_block[16];
     79   int16_t test_output_block[16];
     80   const int pitch = 8;
     81   int count_sign_block[16][2];
     82   const int count_test_block = 1000000;
     83 
     84   memset(count_sign_block, 0, sizeof(count_sign_block));
     85 
     86   for (int i = 0; i < count_test_block; ++i) {
     87     // Initialize a test block with input range [-255, 255].
     88     for (int j = 0; j < 16; ++j)
     89       test_input_block[j] = rnd.Rand8() - rnd.Rand8();
     90 
     91     vp8_short_fdct4x4_c(test_input_block, test_output_block, pitch);
     92 
     93     for (int j = 0; j < 16; ++j) {
     94       if (test_output_block[j] < 0)
     95         ++count_sign_block[j][0];
     96       else if (test_output_block[j] > 0)
     97         ++count_sign_block[j][1];
     98     }
     99   }
    100 
    101   bool bias_acceptable = true;
    102   for (int j = 0; j < 16; ++j)
    103     bias_acceptable = bias_acceptable &&
    104     (abs(count_sign_block[j][0] - count_sign_block[j][1]) < 10000);
    105 
    106   EXPECT_EQ(true, bias_acceptable)
    107     << "Error: 4x4 FDCT has a sign bias > 1% for input range [-255, 255]";
    108 
    109   memset(count_sign_block, 0, sizeof(count_sign_block));
    110 
    111   for (int i = 0; i < count_test_block; ++i) {
    112     // Initialize a test block with input range [-15, 15].
    113     for (int j = 0; j < 16; ++j)
    114       test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4);
    115 
    116     vp8_short_fdct4x4_c(test_input_block, test_output_block, pitch);
    117 
    118     for (int j = 0; j < 16; ++j) {
    119       if (test_output_block[j] < 0)
    120         ++count_sign_block[j][0];
    121       else if (test_output_block[j] > 0)
    122         ++count_sign_block[j][1];
    123     }
    124   }
    125 
    126   bias_acceptable = true;
    127   for (int j = 0; j < 16; ++j)
    128     bias_acceptable = bias_acceptable &&
    129     (abs(count_sign_block[j][0] - count_sign_block[j][1]) < 100000);
    130 
    131   EXPECT_EQ(true, bias_acceptable)
    132     << "Error: 4x4 FDCT has a sign bias > 10% for input range [-15, 15]";
    133 };
    134 
    135 TEST(Vp8FdctTest, RoundTripErrorCheck) {
    136   ACMRandom rnd(ACMRandom::DeterministicSeed());
    137   int max_error = 0;
    138   double total_error = 0;
    139   const int count_test_block = 1000000;
    140   for (int i = 0; i < count_test_block; ++i) {
    141     int16_t test_input_block[16];
    142     int16_t test_temp_block[16];
    143     int16_t test_output_block[16];
    144 
    145     // Initialize a test block with input range [-255, 255].
    146     for (int j = 0; j < 16; ++j)
    147       test_input_block[j] = rnd.Rand8() - rnd.Rand8();
    148 
    149     const int pitch = 8;
    150     vp8_short_fdct4x4_c(test_input_block, test_temp_block, pitch);
    151     reference_idct4x4(test_temp_block, test_output_block);
    152 
    153     for (int j = 0; j < 16; ++j) {
    154       const int diff = test_input_block[j] - test_output_block[j];
    155       const int error = diff * diff;
    156       if (max_error < error)
    157         max_error = error;
    158       total_error += error;
    159     }
    160   }
    161 
    162   EXPECT_GE(1, max_error )
    163     << "Error: FDCT/IDCT has an individual roundtrip error > 1";
    164 
    165   EXPECT_GE(count_test_block, total_error)
    166     << "Error: FDCT/IDCT has average roundtrip error > 1 per block";
    167 };
    168 
    169 }  // namespace
    170