OLD | NEW |
(Empty) | |
| 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 #include <math.h> |
| 12 #include <stdlib.h> |
| 13 #include <string.h> |
| 14 |
| 15 #include "third_party/googletest/src/include/gtest/gtest.h" |
| 16 |
| 17 extern "C" { |
| 18 #include "vp9/common/vp9_entropy.h" |
| 19 #include "./vp9_rtcd.h" |
| 20 void vp9_short_fdct32x32_c(int16_t *input, int16_t *out, int pitch); |
| 21 void vp9_short_idct32x32_c(short *input, short *output, int pitch); |
| 22 } |
| 23 |
| 24 #include "test/acm_random.h" |
| 25 #include "vpx/vpx_integer.h" |
| 26 |
| 27 using libvpx_test::ACMRandom; |
| 28 |
| 29 namespace { |
| 30 #ifdef _MSC_VER |
| 31 static int round(double x) { |
| 32 if (x < 0) |
| 33 return (int)ceil(x - 0.5); |
| 34 else |
| 35 return (int)floor(x + 0.5); |
| 36 } |
| 37 #endif |
| 38 |
| 39 #if !CONFIG_DWTDCTHYBRID |
| 40 static const double kPi = 3.141592653589793238462643383279502884; |
| 41 static void reference2_32x32_idct_2d(double *input, double *output) { |
| 42 double x; |
| 43 for (int l = 0; l < 32; ++l) { |
| 44 for (int k = 0; k < 32; ++k) { |
| 45 double s = 0; |
| 46 for (int i = 0; i < 32; ++i) { |
| 47 for (int j = 0; j < 32; ++j) { |
| 48 x = cos(kPi * j * (l + 0.5) / 32.0) * |
| 49 cos(kPi * i * (k + 0.5) / 32.0) * input[i * 32 + j] / 1024; |
| 50 if (i != 0) |
| 51 x *= sqrt(2.0); |
| 52 if (j != 0) |
| 53 x *= sqrt(2.0); |
| 54 s += x; |
| 55 } |
| 56 } |
| 57 output[k * 32 + l] = s / 4; |
| 58 } |
| 59 } |
| 60 } |
| 61 |
| 62 static void reference_32x32_dct_1d(double in[32], double out[32], int stride) { |
| 63 const double kInvSqrt2 = 0.707106781186547524400844362104; |
| 64 for (int k = 0; k < 32; k++) { |
| 65 out[k] = 0.0; |
| 66 for (int n = 0; n < 32; n++) |
| 67 out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 64.0); |
| 68 if (k == 0) |
| 69 out[k] = out[k] * kInvSqrt2; |
| 70 } |
| 71 } |
| 72 |
| 73 static void reference_32x32_dct_2d(int16_t input[32*32], double output[32*32]) { |
| 74 // First transform columns |
| 75 for (int i = 0; i < 32; ++i) { |
| 76 double temp_in[32], temp_out[32]; |
| 77 for (int j = 0; j < 32; ++j) |
| 78 temp_in[j] = input[j*32 + i]; |
| 79 reference_32x32_dct_1d(temp_in, temp_out, 1); |
| 80 for (int j = 0; j < 32; ++j) |
| 81 output[j * 32 + i] = temp_out[j]; |
| 82 } |
| 83 // Then transform rows |
| 84 for (int i = 0; i < 32; ++i) { |
| 85 double temp_in[32], temp_out[32]; |
| 86 for (int j = 0; j < 32; ++j) |
| 87 temp_in[j] = output[j + i*32]; |
| 88 reference_32x32_dct_1d(temp_in, temp_out, 1); |
| 89 // Scale by some magic number |
| 90 for (int j = 0; j < 32; ++j) |
| 91 output[j + i * 32] = temp_out[j] / 4; |
| 92 } |
| 93 } |
| 94 |
| 95 |
| 96 TEST(VP9Idct32x32Test, AccuracyCheck) { |
| 97 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 98 const int count_test_block = 1000; |
| 99 for (int i = 0; i < count_test_block; ++i) { |
| 100 int16_t in[1024], coeff[1024]; |
| 101 int16_t out_c[1024]; |
| 102 double out_r[1024]; |
| 103 |
| 104 // Initialize a test block with input range [-255, 255]. |
| 105 for (int j = 0; j < 1024; ++j) |
| 106 in[j] = rnd.Rand8() - rnd.Rand8(); |
| 107 |
| 108 reference_32x32_dct_2d(in, out_r); |
| 109 for (int j = 0; j < 1024; j++) |
| 110 coeff[j] = round(out_r[j]); |
| 111 vp9_short_idct32x32_c(coeff, out_c, 64); |
| 112 for (int j = 0; j < 1024; ++j) { |
| 113 const int diff = out_c[j] - in[j]; |
| 114 const int error = diff * diff; |
| 115 EXPECT_GE(1, error) |
| 116 << "Error: 3x32 IDCT has error " << error |
| 117 << " at index " << j; |
| 118 } |
| 119 |
| 120 vp9_short_fdct32x32_c(in, out_c, 64); |
| 121 for (int j = 0; j < 1024; ++j) { |
| 122 const double diff = coeff[j] - out_c[j]; |
| 123 const double error = diff * diff; |
| 124 EXPECT_GE(1.0, error) |
| 125 << "Error: 32x32 FDCT has error " << error |
| 126 << " at index " << j; |
| 127 } |
| 128 } |
| 129 } |
| 130 #else // CONFIG_DWTDCTHYBRID |
| 131 // TODO(rbultje/debargha): add DWT-specific tests |
| 132 #endif // CONFIG_DWTDCTHYBRID |
| 133 TEST(VP9Fdct32x32Test, AccuracyCheck) { |
| 134 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 135 unsigned int max_error = 0; |
| 136 int64_t total_error = 0; |
| 137 const int count_test_block = 1000; |
| 138 for (int i = 0; i < count_test_block; ++i) { |
| 139 int16_t test_input_block[1024]; |
| 140 int16_t test_temp_block[1024]; |
| 141 int16_t test_output_block[1024]; |
| 142 |
| 143 // Initialize a test block with input range [-255, 255]. |
| 144 for (int j = 0; j < 1024; ++j) |
| 145 test_input_block[j] = rnd.Rand8() - rnd.Rand8(); |
| 146 |
| 147 const int pitch = 64; |
| 148 vp9_short_fdct32x32_c(test_input_block, test_temp_block, pitch); |
| 149 vp9_short_idct32x32_c(test_temp_block, test_output_block, pitch); |
| 150 |
| 151 for (int j = 0; j < 1024; ++j) { |
| 152 const unsigned diff = test_input_block[j] - test_output_block[j]; |
| 153 const unsigned error = diff * diff; |
| 154 if (max_error < error) |
| 155 max_error = error; |
| 156 total_error += error; |
| 157 } |
| 158 } |
| 159 |
| 160 EXPECT_GE(1u, max_error) |
| 161 << "Error: 32x32 FDCT/IDCT has an individual roundtrip error > 1"; |
| 162 |
| 163 EXPECT_GE(count_test_block/10, total_error) |
| 164 << "Error: 32x32 FDCT/IDCT has average roundtrip error > 1/10 per block"; |
| 165 } |
| 166 |
| 167 TEST(VP9Fdct32x32Test, CoeffSizeCheck) { |
| 168 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 169 const int count_test_block = 1000; |
| 170 for (int i = 0; i < count_test_block; ++i) { |
| 171 int16_t input_block[1024], input_extreme_block[1024]; |
| 172 int16_t output_block[1024], output_extreme_block[1024]; |
| 173 |
| 174 // Initialize a test block with input range [-255, 255]. |
| 175 for (int j = 0; j < 1024; ++j) { |
| 176 input_block[j] = rnd.Rand8() - rnd.Rand8(); |
| 177 input_extreme_block[j] = rnd.Rand8() % 2 ? 255 : -255; |
| 178 } |
| 179 if (i == 0) |
| 180 for (int j = 0; j < 1024; ++j) |
| 181 input_extreme_block[j] = 255; |
| 182 |
| 183 const int pitch = 64; |
| 184 vp9_short_fdct32x32_c(input_block, output_block, pitch); |
| 185 vp9_short_fdct32x32_c(input_extreme_block, output_extreme_block, pitch); |
| 186 |
| 187 // The minimum quant value is 4. |
| 188 for (int j = 0; j < 1024; ++j) { |
| 189 EXPECT_GE(4*DCT_MAX_VALUE, abs(output_block[j])) |
| 190 << "Error: 32x32 FDCT has coefficient larger than 4*DCT_MAX_VALUE"; |
| 191 EXPECT_GE(4*DCT_MAX_VALUE, abs(output_extreme_block[j])) |
| 192 << "Error: 32x32 FDCT extreme has coefficient larger than " |
| 193 "4*DCT_MAX_VALUE"; |
| 194 } |
| 195 } |
| 196 } |
| 197 } // namespace |
OLD | NEW |