Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 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" { |
Yaowu Xu | afffa3d | 2013-09-05 08:45:56 -0700 | [diff] [blame] | 18 | #include "./vp9_rtcd.h" |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 19 | } |
| 20 | |
Yaowu Xu | afffa3d | 2013-09-05 08:45:56 -0700 | [diff] [blame] | 21 | #include "test/acm_random.h" |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 22 | #include "vpx/vpx_integer.h" |
Jingning Han | 9b744ce | 2013-06-26 11:59:46 -0700 | [diff] [blame] | 23 | #include "vpx_ports/mem.h" |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 24 | |
Daniel Kang | 26641c7 | 2012-06-28 16:26:31 -0700 | [diff] [blame] | 25 | using libvpx_test::ACMRandom; |
| 26 | |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 27 | namespace { |
James Zern | e4f38c8 | 2013-06-26 11:09:08 -0700 | [diff] [blame] | 28 | void fdct4x4(int16_t *in, int16_t *out, uint8_t* /*dst*/, |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 29 | int stride, int /*tx_type*/) { |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 30 | vp9_short_fdct4x4_c(in, out, stride); |
| 31 | } |
James Zern | e4f38c8 | 2013-06-26 11:09:08 -0700 | [diff] [blame] | 32 | void idct4x4_add(int16_t* /*in*/, int16_t *out, uint8_t *dst, |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 33 | int stride, int /*tx_type*/) { |
Dmitry Kovalev | 3a06025 | 2013-10-04 14:17:06 -0700 | [diff] [blame] | 34 | vp9_idct4x4_16_add_c(out, dst, stride >> 1); |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 35 | } |
James Zern | e4f38c8 | 2013-06-26 11:09:08 -0700 | [diff] [blame] | 36 | void fht4x4(int16_t *in, int16_t *out, uint8_t* /*dst*/, |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 37 | int stride, int tx_type) { |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 38 | vp9_short_fht4x4_c(in, out, stride >> 1, tx_type); |
| 39 | } |
James Zern | e4f38c8 | 2013-06-26 11:09:08 -0700 | [diff] [blame] | 40 | void iht4x4_add(int16_t* /*in*/, int16_t *out, uint8_t *dst, |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 41 | int stride, int tx_type) { |
Dmitry Kovalev | 7ef5739 | 2013-10-11 13:31:32 -0700 | [diff] [blame] | 42 | vp9_iht4x4_16_add_c(out, dst, stride >> 1, tx_type); |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 43 | } |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 44 | |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 45 | class FwdTrans4x4Test : public ::testing::TestWithParam<int> { |
| 46 | public: |
Jingning Han | 6094bf3 | 2013-07-12 20:05:05 -0700 | [diff] [blame] | 47 | virtual ~FwdTrans4x4Test() {} |
| 48 | virtual void SetUp() { |
Jingning Han | ab36262 | 2013-06-21 11:45:47 -0700 | [diff] [blame] | 49 | tx_type_ = GetParam(); |
| 50 | if (tx_type_ == 0) { |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 51 | fwd_txfm_ = fdct4x4; |
| 52 | inv_txfm_ = idct4x4_add; |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 53 | } else { |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 54 | fwd_txfm_ = fht4x4; |
| 55 | inv_txfm_ = iht4x4_add; |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 56 | } |
| 57 | } |
| 58 | |
| 59 | protected: |
| 60 | void RunFwdTxfm(int16_t *in, int16_t *out, uint8_t *dst, |
| 61 | int stride, int tx_type) { |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 62 | (*fwd_txfm_)(in, out, dst, stride, tx_type); |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | void RunInvTxfm(int16_t *in, int16_t *out, uint8_t *dst, |
| 66 | int stride, int tx_type) { |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 67 | (*inv_txfm_)(in, out, dst, stride, tx_type); |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 68 | } |
| 69 | |
Jingning Han | ab36262 | 2013-06-21 11:45:47 -0700 | [diff] [blame] | 70 | int tx_type_; |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 71 | void (*fwd_txfm_)(int16_t *in, int16_t *out, uint8_t *dst, |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 72 | int stride, int tx_type); |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 73 | void (*inv_txfm_)(int16_t *in, int16_t *out, uint8_t *dst, |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 74 | int stride, int tx_type); |
| 75 | }; |
| 76 | |
| 77 | TEST_P(FwdTrans4x4Test, SignBiasCheck) { |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 78 | ACMRandom rnd(ACMRandom::DeterministicSeed()); |
Jingning Han | 9b744ce | 2013-06-26 11:59:46 -0700 | [diff] [blame] | 79 | DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 16); |
| 80 | DECLARE_ALIGNED_ARRAY(16, int16_t, test_output_block, 16); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 81 | const int pitch = 8; |
| 82 | int count_sign_block[16][2]; |
| 83 | const int count_test_block = 1000000; |
| 84 | |
| 85 | memset(count_sign_block, 0, sizeof(count_sign_block)); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 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 | |
Jingning Han | ab36262 | 2013-06-21 11:45:47 -0700 | [diff] [blame] | 91 | RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 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 | for (int j = 0; j < 16; ++j) { |
| 102 | const bool bias_acceptable = (abs(count_sign_block[j][0] - |
| 103 | count_sign_block[j][1]) < 10000); |
| 104 | EXPECT_TRUE(bias_acceptable) |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 105 | << "Error: 4x4 FDCT/FHT has a sign bias > 1%" |
| 106 | << " for input range [-255, 255] at index " << j |
Jingning Han | ab36262 | 2013-06-21 11:45:47 -0700 | [diff] [blame] | 107 | << " tx_type " << tx_type_; |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | memset(count_sign_block, 0, sizeof(count_sign_block)); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 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 | |
Jingning Han | ab36262 | 2013-06-21 11:45:47 -0700 | [diff] [blame] | 116 | RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 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 | for (int j = 0; j < 16; ++j) { |
| 127 | const bool bias_acceptable = (abs(count_sign_block[j][0] - |
| 128 | count_sign_block[j][1]) < 100000); |
| 129 | EXPECT_TRUE(bias_acceptable) |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 130 | << "Error: 4x4 FDCT/FHT has a sign bias > 10%" |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 131 | << " for input range [-15, 15] at index " << j; |
| 132 | } |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 133 | } |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 134 | |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 135 | TEST_P(FwdTrans4x4Test, RoundTripErrorCheck) { |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 136 | ACMRandom rnd(ACMRandom::DeterministicSeed()); |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 137 | |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 138 | int max_error = 0; |
Yaowu Xu | bc484eb | 2013-08-08 18:25:03 -0700 | [diff] [blame] | 139 | int total_error = 0; |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 140 | const int count_test_block = 1000000; |
| 141 | for (int i = 0; i < count_test_block; ++i) { |
Jingning Han | 9b744ce | 2013-06-26 11:59:46 -0700 | [diff] [blame] | 142 | DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 16); |
| 143 | DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, 16); |
| 144 | DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 16); |
| 145 | DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 16); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 146 | |
Scott LaVarnway | ba48a11 | 2013-05-20 13:03:17 -0400 | [diff] [blame] | 147 | for (int j = 0; j < 16; ++j) { |
| 148 | src[j] = rnd.Rand8(); |
| 149 | dst[j] = rnd.Rand8(); |
| 150 | } |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 151 | // Initialize a test block with input range [-255, 255]. |
| 152 | for (int j = 0; j < 16; ++j) |
Scott LaVarnway | ba48a11 | 2013-05-20 13:03:17 -0400 | [diff] [blame] | 153 | test_input_block[j] = src[j] - dst[j]; |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 154 | |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 155 | const int pitch = 8; |
Jingning Han | ab36262 | 2013-06-21 11:45:47 -0700 | [diff] [blame] | 156 | RunFwdTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_); |
Yaowu Xu | 95ee7f1 | 2012-08-24 09:59:49 -0700 | [diff] [blame] | 157 | |
| 158 | for (int j = 0; j < 16; ++j) { |
Yaowu Xu | afffa3d | 2013-09-05 08:45:56 -0700 | [diff] [blame] | 159 | if (test_temp_block[j] > 0) { |
Yaowu Xu | 95ee7f1 | 2012-08-24 09:59:49 -0700 | [diff] [blame] | 160 | test_temp_block[j] += 2; |
| 161 | test_temp_block[j] /= 4; |
| 162 | test_temp_block[j] *= 4; |
| 163 | } else { |
| 164 | test_temp_block[j] -= 2; |
| 165 | test_temp_block[j] /= 4; |
| 166 | test_temp_block[j] *= 4; |
| 167 | } |
| 168 | } |
| 169 | |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 170 | // inverse transform and reconstruct the pixel block |
Jingning Han | ab36262 | 2013-06-21 11:45:47 -0700 | [diff] [blame] | 171 | RunInvTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 172 | |
| 173 | for (int j = 0; j < 16; ++j) { |
Scott LaVarnway | ba48a11 | 2013-05-20 13:03:17 -0400 | [diff] [blame] | 174 | const int diff = dst[j] - src[j]; |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 175 | const int error = diff * diff; |
| 176 | if (max_error < error) |
| 177 | max_error = error; |
| 178 | total_error += error; |
| 179 | } |
| 180 | } |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 181 | EXPECT_GE(1, max_error) |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 182 | << "Error: FDCT/IDCT or FHT/IHT has an individual roundtrip error > 1"; |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 183 | |
| 184 | EXPECT_GE(count_test_block, total_error) |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 185 | << "Error: FDCT/IDCT or FHT/IHT has average " |
Jingning Han | 29b6e73 | 2013-06-21 16:00:44 -0700 | [diff] [blame] | 186 | << "roundtrip error > 1 per block"; |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 187 | } |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 188 | |
Jingning Han | 362809d | 2013-06-18 10:46:33 -0700 | [diff] [blame] | 189 | INSTANTIATE_TEST_CASE_P(VP9, FwdTrans4x4Test, ::testing::Range(0, 4)); |
Daniel Kang | 58156f1 | 2012-06-26 18:11:33 -0700 | [diff] [blame] | 190 | } // namespace |