fdct8x8_test.cc 7.32 KB
Newer Older
Daniel Kang's avatar
Daniel Kang committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include "third_party/googletest/src/include/gtest/gtest.h"

extern "C" {
18
#include "vp9_rtcd.h"
Scott LaVarnway's avatar
Scott LaVarnway committed
19
void vp9_short_idct8x8_add_c(short *input, uint8_t *output, int pitch);
Daniel Kang's avatar
Daniel Kang committed
20 21 22 23 24 25 26 27
}

#include "acm_random.h"
#include "vpx/vpx_integer.h"

using libvpx_test::ACMRandom;

namespace {
James Zern's avatar
James Zern committed
28 29
void fdct8x8(int16_t *in, int16_t *out, uint8_t* /*dst*/,
             int stride, int /*tx_type*/) {
Jingning Han's avatar
Jingning Han committed
30 31
  vp9_short_fdct8x8_c(in, out, stride);
}
James Zern's avatar
James Zern committed
32 33
void idct8x8_add(int16_t* /*in*/, int16_t *out, uint8_t *dst,
                 int stride, int /*tx_type*/) {
Jingning Han's avatar
Jingning Han committed
34 35
  vp9_short_idct8x8_add_c(out, dst, stride >> 1);
}
James Zern's avatar
James Zern committed
36 37
void fht8x8(int16_t *in, int16_t *out, uint8_t* /*dst*/,
            int stride, int tx_type) {
38 39 40 41 42
  // TODO(jingning): need to refactor this to test both _c and _sse2 functions,
  // when we have all inverse dct functions done sse2.
#if HAVE_SSE2
  vp9_short_fht8x8_sse2(in, out, stride >> 1, tx_type);
#else
Jingning Han's avatar
Jingning Han committed
43
  vp9_short_fht8x8_c(in, out, stride >> 1, tx_type);
44
#endif
Jingning Han's avatar
Jingning Han committed
45
}
James Zern's avatar
James Zern committed
46
void iht8x8_add(int16_t* /*in*/, int16_t *out, uint8_t *dst,
Jingning Han's avatar
Jingning Han committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
                int stride, int tx_type) {
  vp9_short_iht8x8_add_c(out, dst, stride >> 1, tx_type);
}

class FwdTrans8x8Test : public ::testing::TestWithParam<int> {
 public:
  FwdTrans8x8Test() { SetUpTestTxfm(); }
  ~FwdTrans8x8Test() {}

  void SetUpTestTxfm() {
    tx_type_ = GetParam();
    if (tx_type_ == 0) {
      fwd_txfm = fdct8x8;
      inv_txfm = idct8x8_add;
    } else {
      fwd_txfm = fht8x8;
      inv_txfm = iht8x8_add;
    }
  }

 protected:
  void RunFwdTxfm(int16_t *in, int16_t *out, uint8_t *dst,
                  int stride, int tx_type) {
    (*fwd_txfm)(in, out, dst, stride, tx_type);
  }
  void RunInvTxfm(int16_t *in, int16_t *out, uint8_t *dst,
                  int stride, int tx_type) {
    (*inv_txfm)(in, out, dst, stride, tx_type);
  }

  int tx_type_;
  void (*fwd_txfm)(int16_t*, int16_t*, uint8_t*, int, int);
  void (*inv_txfm)(int16_t*, int16_t*, uint8_t*, int, int);
};
Daniel Kang's avatar
Daniel Kang committed
81

Jingning Han's avatar
Jingning Han committed
82
TEST_P(FwdTrans8x8Test, SignBiasCheck) {
Daniel Kang's avatar
Daniel Kang committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96
  ACMRandom rnd(ACMRandom::DeterministicSeed());
  int16_t test_input_block[64];
  int16_t test_output_block[64];
  const int pitch = 16;
  int count_sign_block[64][2];
  const int count_test_block = 100000;

  memset(count_sign_block, 0, sizeof(count_sign_block));

  for (int i = 0; i < count_test_block; ++i) {
    // Initialize a test block with input range [-255, 255].
    for (int j = 0; j < 64; ++j)
      test_input_block[j] = rnd.Rand8() - rnd.Rand8();

Jingning Han's avatar
Jingning Han committed
97
    RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_);
Daniel Kang's avatar
Daniel Kang committed
98 99 100 101 102 103 104 105 106 107

    for (int j = 0; j < 64; ++j) {
      if (test_output_block[j] < 0)
        ++count_sign_block[j][0];
      else if (test_output_block[j] > 0)
        ++count_sign_block[j][1];
    }
  }

  for (int j = 0; j < 64; ++j) {
108 109 110
    const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
    const int max_diff = 1125;
    EXPECT_LT(diff, max_diff)
Jingning Han's avatar
Jingning Han committed
111
        << "Error: 8x8 FDCT/FHT has a sign bias > "
112 113 114 115 116
        << 1. * max_diff / count_test_block * 100 << "%"
        << " for input range [-255, 255] at index " << j
        << " count0: " << count_sign_block[j][0]
        << " count1: " << count_sign_block[j][1]
        << " diff: " << diff;
Daniel Kang's avatar
Daniel Kang committed
117 118 119 120 121 122 123 124 125
  }

  memset(count_sign_block, 0, sizeof(count_sign_block));

  for (int i = 0; i < count_test_block; ++i) {
    // Initialize a test block with input range [-15, 15].
    for (int j = 0; j < 64; ++j)
      test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4);

Jingning Han's avatar
Jingning Han committed
126
    RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_);
Daniel Kang's avatar
Daniel Kang committed
127 128 129 130 131 132 133 134 135 136

    for (int j = 0; j < 64; ++j) {
      if (test_output_block[j] < 0)
        ++count_sign_block[j][0];
      else if (test_output_block[j] > 0)
        ++count_sign_block[j][1];
    }
  }

  for (int j = 0; j < 64; ++j) {
137 138 139
    const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
    const int max_diff = 10000;
    EXPECT_LT(diff, max_diff)
Jingning Han's avatar
Jingning Han committed
140
        << "Error: 4x4 FDCT/FHT has a sign bias > "
141 142 143 144 145
        << 1. * max_diff / count_test_block * 100 << "%"
        << " for input range [-15, 15] at index " << j
        << " count0: " << count_sign_block[j][0]
        << " count1: " << count_sign_block[j][1]
        << " diff: " << diff;
Daniel Kang's avatar
Daniel Kang committed
146
  }
Jingning Han's avatar
Jingning Han committed
147
}
Daniel Kang's avatar
Daniel Kang committed
148

Jingning Han's avatar
Jingning Han committed
149
TEST_P(FwdTrans8x8Test, RoundTripErrorCheck) {
Daniel Kang's avatar
Daniel Kang committed
150 151 152 153 154 155 156
  ACMRandom rnd(ACMRandom::DeterministicSeed());
  int max_error = 0;
  double total_error = 0;
  const int count_test_block = 100000;
  for (int i = 0; i < count_test_block; ++i) {
    int16_t test_input_block[64];
    int16_t test_temp_block[64];
Scott LaVarnway's avatar
Scott LaVarnway committed
157
    uint8_t dst[64], src[64];
Daniel Kang's avatar
Daniel Kang committed
158

Scott LaVarnway's avatar
Scott LaVarnway committed
159 160 161 162
    for (int j = 0; j < 64; ++j) {
      src[j] = rnd.Rand8();
      dst[j] = rnd.Rand8();
    }
Daniel Kang's avatar
Daniel Kang committed
163 164
    // Initialize a test block with input range [-255, 255].
    for (int j = 0; j < 64; ++j)
Scott LaVarnway's avatar
Scott LaVarnway committed
165
      test_input_block[j] = src[j] - dst[j];
Daniel Kang's avatar
Daniel Kang committed
166 167

    const int pitch = 16;
Jingning Han's avatar
Jingning Han committed
168
    RunFwdTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_);
169 170 171 172 173 174 175 176 177 178 179
    for (int j = 0; j < 64; ++j){
        if(test_temp_block[j] > 0) {
          test_temp_block[j] += 2;
          test_temp_block[j] /= 4;
          test_temp_block[j] *= 4;
        } else {
          test_temp_block[j] -= 2;
          test_temp_block[j] /= 4;
          test_temp_block[j] *= 4;
        }
    }
Jingning Han's avatar
Jingning Han committed
180
    RunInvTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_);
Daniel Kang's avatar
Daniel Kang committed
181 182

    for (int j = 0; j < 64; ++j) {
Scott LaVarnway's avatar
Scott LaVarnway committed
183
      const int diff = dst[j] - src[j];
Daniel Kang's avatar
Daniel Kang committed
184 185 186 187 188 189 190 191
      const int error = diff * diff;
      if (max_error < error)
        max_error = error;
      total_error += error;
    }
  }

  EXPECT_GE(1, max_error)
Jingning Han's avatar
Jingning Han committed
192
    << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual roundtrip error > 1";
Daniel Kang's avatar
Daniel Kang committed
193

Daniel Kang's avatar
Daniel Kang committed
194
  EXPECT_GE(count_test_block/5, total_error)
Jingning Han's avatar
Jingning Han committed
195 196 197
    << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip "
        "error > 1/5 per block";
}
Daniel Kang's avatar
Daniel Kang committed
198

Jingning Han's avatar
Jingning Han committed
199
TEST_P(FwdTrans8x8Test, ExtremalCheck) {
Daniel Kang's avatar
Daniel Kang committed
200 201 202 203 204 205 206
  ACMRandom rnd(ACMRandom::DeterministicSeed());
  int max_error = 0;
  double total_error = 0;
  const int count_test_block = 100000;
  for (int i = 0; i < count_test_block; ++i) {
    int16_t test_input_block[64];
    int16_t test_temp_block[64];
Scott LaVarnway's avatar
Scott LaVarnway committed
207
    uint8_t dst[64], src[64];
Daniel Kang's avatar
Daniel Kang committed
208

Scott LaVarnway's avatar
Scott LaVarnway committed
209 210 211 212 213
    for (int j = 0; j < 64; ++j) {
      src[j] = rnd.Rand8() % 2 ? 255 : 0;
      dst[j] = src[j] > 0 ? 0 : 255;
    }
    // Initialize a test block with input range [-255, 255].
Daniel Kang's avatar
Daniel Kang committed
214
    for (int j = 0; j < 64; ++j)
Scott LaVarnway's avatar
Scott LaVarnway committed
215
      test_input_block[j] = src[j] - dst[j];
Daniel Kang's avatar
Daniel Kang committed
216 217

    const int pitch = 16;
Jingning Han's avatar
Jingning Han committed
218 219
    RunFwdTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_);
    RunInvTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_);
Daniel Kang's avatar
Daniel Kang committed
220 221

    for (int j = 0; j < 64; ++j) {
Scott LaVarnway's avatar
Scott LaVarnway committed
222
      const int diff = dst[j] - src[j];
Daniel Kang's avatar
Daniel Kang committed
223 224 225 226 227 228 229
      const int error = diff * diff;
      if (max_error < error)
        max_error = error;
      total_error += error;
    }

    EXPECT_GE(1, max_error)
Jingning Han's avatar
Jingning Han committed
230
        << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has an"
Daniel Kang's avatar
Daniel Kang committed
231 232
        << " individual roundtrip error > 1";

Daniel Kang's avatar
Daniel Kang committed
233
    EXPECT_GE(count_test_block/5, total_error)
Jingning Han's avatar
Jingning Han committed
234
        << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average"
Daniel Kang's avatar
Daniel Kang committed
235
        << " roundtrip error > 1/5 per block";
Daniel Kang's avatar
Daniel Kang committed
236
  }
Jingning Han's avatar
Jingning Han committed
237
}
Daniel Kang's avatar
Daniel Kang committed
238

Jingning Han's avatar
Jingning Han committed
239
INSTANTIATE_TEST_CASE_P(VP9, FwdTrans8x8Test, ::testing::Range(0, 4));
Daniel Kang's avatar
Daniel Kang committed
240
}  // namespace