fdct8x8_test.cc 7.61 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
/*
 *  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"
16
#include "vpx_ports/mem.h"
Daniel Kang's avatar
Daniel Kang committed
17 18

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

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

using libvpx_test::ACMRandom;

namespace {
James Zern's avatar
James Zern committed
29 30
void fdct8x8(int16_t *in, int16_t *out, uint8_t* /*dst*/,
             int stride, int /*tx_type*/) {
Jingning Han's avatar
Jingning Han committed
31 32
  vp9_short_fdct8x8_c(in, out, stride);
}
James Zern's avatar
James Zern committed
33 34
void idct8x8_add(int16_t* /*in*/, int16_t *out, uint8_t *dst,
                 int stride, int /*tx_type*/) {
Jingning Han's avatar
Jingning Han committed
35 36
  vp9_short_idct8x8_add_c(out, dst, stride >> 1);
}
James Zern's avatar
James Zern committed
37 38
void fht8x8(int16_t *in, int16_t *out, uint8_t* /*dst*/,
            int stride, int tx_type) {
39 40 41 42 43
  // 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
44
  vp9_short_fht8x8_c(in, out, stride >> 1, tx_type);
45
#endif
Jingning Han's avatar
Jingning Han committed
46
}
James Zern's avatar
James Zern committed
47
void iht8x8_add(int16_t* /*in*/, int16_t *out, uint8_t *dst,
Jingning Han's avatar
Jingning Han committed
48 49 50 51 52 53
                int stride, int tx_type) {
  vp9_short_iht8x8_add_c(out, dst, stride >> 1, tx_type);
}

class FwdTrans8x8Test : public ::testing::TestWithParam<int> {
 public:
54 55
  virtual ~FwdTrans8x8Test() {}
  virtual void SetUp() {
Jingning Han's avatar
Jingning Han committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    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
80

Jingning Han's avatar
Jingning Han committed
81
TEST_P(FwdTrans8x8Test, SignBiasCheck) {
Daniel Kang's avatar
Daniel Kang committed
82
  ACMRandom rnd(ACMRandom::DeterministicSeed());
83 84
  DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64);
  DECLARE_ALIGNED_ARRAY(16, int16_t, test_output_block, 64);
Daniel Kang's avatar
Daniel Kang committed
85 86 87 88 89 90 91 92 93 94 95
  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
96
    RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_);
Daniel Kang's avatar
Daniel Kang committed
97 98 99 100 101 102 103 104 105 106

    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) {
107 108 109
    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
110
        << "Error: 8x8 FDCT/FHT has a sign bias > "
111 112 113 114 115
        << 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
116 117 118 119 120 121 122 123 124
  }

  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
125
    RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_);
Daniel Kang's avatar
Daniel Kang committed
126 127 128 129 130 131 132 133 134 135

    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) {
136 137 138
    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
139
        << "Error: 4x4 FDCT/FHT has a sign bias > "
140 141 142 143 144
        << 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
145
  }
Jingning Han's avatar
Jingning Han committed
146
}
Daniel Kang's avatar
Daniel Kang committed
147

Jingning Han's avatar
Jingning Han committed
148
TEST_P(FwdTrans8x8Test, RoundTripErrorCheck) {
Daniel Kang's avatar
Daniel Kang committed
149 150 151 152 153
  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) {
154 155 156 157
    DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64);
    DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, 64);
    DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64);
    DECLARE_ALIGNED_ARRAY(16, uint8_t, 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
  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) {
205 206 207 208
    DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64);
    DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, 64);
    DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64);
    DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 64);
Daniel Kang's avatar
Daniel Kang committed
209

Scott LaVarnway's avatar
Scott LaVarnway committed
210 211 212 213 214
    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
215
    for (int j = 0; j < 64; ++j)
Scott LaVarnway's avatar
Scott LaVarnway committed
216
      test_input_block[j] = src[j] - dst[j];
Daniel Kang's avatar
Daniel Kang committed
217 218

    const int pitch = 16;
Jingning Han's avatar
Jingning Han committed
219 220
    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
221 222

    for (int j = 0; j < 64; ++j) {
Scott LaVarnway's avatar
Scott LaVarnway committed
223
      const int diff = dst[j] - src[j];
Daniel Kang's avatar
Daniel Kang committed
224 225 226 227 228 229 230
      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
231
        << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has an"
Daniel Kang's avatar
Daniel Kang committed
232 233
        << " individual roundtrip error > 1";

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

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