blob: edc194d63d55323257d2561aad36822e64e26d14 [file] [log] [blame]
Daniel Kang58156f12012-06-26 18:11:33 -07001/*
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
17extern "C" {
Yaowu Xuafffa3d2013-09-05 08:45:56 -070018#include "./vp9_rtcd.h"
Daniel Kang58156f12012-06-26 18:11:33 -070019}
20
Yaowu Xuafffa3d2013-09-05 08:45:56 -070021#include "test/acm_random.h"
Daniel Kang58156f12012-06-26 18:11:33 -070022#include "vpx/vpx_integer.h"
Jingning Han9b744ce2013-06-26 11:59:46 -070023#include "vpx_ports/mem.h"
Daniel Kang58156f12012-06-26 18:11:33 -070024
Daniel Kang26641c72012-06-28 16:26:31 -070025using libvpx_test::ACMRandom;
26
Daniel Kang58156f12012-06-26 18:11:33 -070027namespace {
James Zerne4f38c82013-06-26 11:09:08 -070028void fdct4x4(int16_t *in, int16_t *out, uint8_t* /*dst*/,
Jingning Han29b6e732013-06-21 16:00:44 -070029 int stride, int /*tx_type*/) {
Jingning Han362809d2013-06-18 10:46:33 -070030 vp9_short_fdct4x4_c(in, out, stride);
31}
James Zerne4f38c82013-06-26 11:09:08 -070032void idct4x4_add(int16_t* /*in*/, int16_t *out, uint8_t *dst,
Jingning Han29b6e732013-06-21 16:00:44 -070033 int stride, int /*tx_type*/) {
Dmitry Kovalev3a060252013-10-04 14:17:06 -070034 vp9_idct4x4_16_add_c(out, dst, stride >> 1);
Jingning Han362809d2013-06-18 10:46:33 -070035}
James Zerne4f38c82013-06-26 11:09:08 -070036void fht4x4(int16_t *in, int16_t *out, uint8_t* /*dst*/,
Jingning Han29b6e732013-06-21 16:00:44 -070037 int stride, int tx_type) {
Jingning Han362809d2013-06-18 10:46:33 -070038 vp9_short_fht4x4_c(in, out, stride >> 1, tx_type);
39}
James Zerne4f38c82013-06-26 11:09:08 -070040void iht4x4_add(int16_t* /*in*/, int16_t *out, uint8_t *dst,
Jingning Han362809d2013-06-18 10:46:33 -070041 int stride, int tx_type) {
Dmitry Kovalev7ef57392013-10-11 13:31:32 -070042 vp9_iht4x4_16_add_c(out, dst, stride >> 1, tx_type);
Jingning Han362809d2013-06-18 10:46:33 -070043}
Daniel Kang58156f12012-06-26 18:11:33 -070044
Jingning Han362809d2013-06-18 10:46:33 -070045class FwdTrans4x4Test : public ::testing::TestWithParam<int> {
46 public:
Jingning Han6094bf32013-07-12 20:05:05 -070047 virtual ~FwdTrans4x4Test() {}
48 virtual void SetUp() {
Jingning Hanab362622013-06-21 11:45:47 -070049 tx_type_ = GetParam();
50 if (tx_type_ == 0) {
Jingning Han29b6e732013-06-21 16:00:44 -070051 fwd_txfm_ = fdct4x4;
52 inv_txfm_ = idct4x4_add;
Jingning Han362809d2013-06-18 10:46:33 -070053 } else {
Jingning Han29b6e732013-06-21 16:00:44 -070054 fwd_txfm_ = fht4x4;
55 inv_txfm_ = iht4x4_add;
Jingning Han362809d2013-06-18 10:46:33 -070056 }
57 }
58
59 protected:
60 void RunFwdTxfm(int16_t *in, int16_t *out, uint8_t *dst,
61 int stride, int tx_type) {
Jingning Han29b6e732013-06-21 16:00:44 -070062 (*fwd_txfm_)(in, out, dst, stride, tx_type);
Jingning Han362809d2013-06-18 10:46:33 -070063 }
64
65 void RunInvTxfm(int16_t *in, int16_t *out, uint8_t *dst,
66 int stride, int tx_type) {
Jingning Han29b6e732013-06-21 16:00:44 -070067 (*inv_txfm_)(in, out, dst, stride, tx_type);
Jingning Han362809d2013-06-18 10:46:33 -070068 }
69
Jingning Hanab362622013-06-21 11:45:47 -070070 int tx_type_;
Jingning Han29b6e732013-06-21 16:00:44 -070071 void (*fwd_txfm_)(int16_t *in, int16_t *out, uint8_t *dst,
Jingning Han362809d2013-06-18 10:46:33 -070072 int stride, int tx_type);
Jingning Han29b6e732013-06-21 16:00:44 -070073 void (*inv_txfm_)(int16_t *in, int16_t *out, uint8_t *dst,
Jingning Han362809d2013-06-18 10:46:33 -070074 int stride, int tx_type);
75};
76
77TEST_P(FwdTrans4x4Test, SignBiasCheck) {
Daniel Kang58156f12012-06-26 18:11:33 -070078 ACMRandom rnd(ACMRandom::DeterministicSeed());
Jingning Han9b744ce2013-06-26 11:59:46 -070079 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 16);
80 DECLARE_ALIGNED_ARRAY(16, int16_t, test_output_block, 16);
Daniel Kang58156f12012-06-26 18:11:33 -070081 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 Kang58156f12012-06-26 18:11:33 -070086 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 Hanab362622013-06-21 11:45:47 -070091 RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_);
Daniel Kang58156f12012-06-26 18:11:33 -070092
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 Han362809d2013-06-18 10:46:33 -0700105 << "Error: 4x4 FDCT/FHT has a sign bias > 1%"
106 << " for input range [-255, 255] at index " << j
Jingning Hanab362622013-06-21 11:45:47 -0700107 << " tx_type " << tx_type_;
Daniel Kang58156f12012-06-26 18:11:33 -0700108 }
109
110 memset(count_sign_block, 0, sizeof(count_sign_block));
Daniel Kang58156f12012-06-26 18:11:33 -0700111 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 Hanab362622013-06-21 11:45:47 -0700116 RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type_);
Daniel Kang58156f12012-06-26 18:11:33 -0700117
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 Han362809d2013-06-18 10:46:33 -0700130 << "Error: 4x4 FDCT/FHT has a sign bias > 10%"
Daniel Kang58156f12012-06-26 18:11:33 -0700131 << " for input range [-15, 15] at index " << j;
132 }
Jingning Han362809d2013-06-18 10:46:33 -0700133}
Daniel Kang58156f12012-06-26 18:11:33 -0700134
Jingning Han362809d2013-06-18 10:46:33 -0700135TEST_P(FwdTrans4x4Test, RoundTripErrorCheck) {
Daniel Kang58156f12012-06-26 18:11:33 -0700136 ACMRandom rnd(ACMRandom::DeterministicSeed());
Jingning Han362809d2013-06-18 10:46:33 -0700137
Daniel Kang58156f12012-06-26 18:11:33 -0700138 int max_error = 0;
Yaowu Xubc484eb2013-08-08 18:25:03 -0700139 int total_error = 0;
Daniel Kang58156f12012-06-26 18:11:33 -0700140 const int count_test_block = 1000000;
141 for (int i = 0; i < count_test_block; ++i) {
Jingning Han9b744ce2013-06-26 11:59:46 -0700142 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 Kang58156f12012-06-26 18:11:33 -0700146
Scott LaVarnwayba48a112013-05-20 13:03:17 -0400147 for (int j = 0; j < 16; ++j) {
148 src[j] = rnd.Rand8();
149 dst[j] = rnd.Rand8();
150 }
Daniel Kang58156f12012-06-26 18:11:33 -0700151 // Initialize a test block with input range [-255, 255].
152 for (int j = 0; j < 16; ++j)
Scott LaVarnwayba48a112013-05-20 13:03:17 -0400153 test_input_block[j] = src[j] - dst[j];
Daniel Kang58156f12012-06-26 18:11:33 -0700154
Daniel Kang58156f12012-06-26 18:11:33 -0700155 const int pitch = 8;
Jingning Hanab362622013-06-21 11:45:47 -0700156 RunFwdTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_);
Yaowu Xu95ee7f12012-08-24 09:59:49 -0700157
158 for (int j = 0; j < 16; ++j) {
Yaowu Xuafffa3d2013-09-05 08:45:56 -0700159 if (test_temp_block[j] > 0) {
Yaowu Xu95ee7f12012-08-24 09:59:49 -0700160 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 Han362809d2013-06-18 10:46:33 -0700170 // inverse transform and reconstruct the pixel block
Jingning Hanab362622013-06-21 11:45:47 -0700171 RunInvTxfm(test_input_block, test_temp_block, dst, pitch, tx_type_);
Daniel Kang58156f12012-06-26 18:11:33 -0700172
173 for (int j = 0; j < 16; ++j) {
Scott LaVarnwayba48a112013-05-20 13:03:17 -0400174 const int diff = dst[j] - src[j];
Daniel Kang58156f12012-06-26 18:11:33 -0700175 const int error = diff * diff;
176 if (max_error < error)
177 max_error = error;
178 total_error += error;
179 }
180 }
Daniel Kang58156f12012-06-26 18:11:33 -0700181 EXPECT_GE(1, max_error)
Jingning Han362809d2013-06-18 10:46:33 -0700182 << "Error: FDCT/IDCT or FHT/IHT has an individual roundtrip error > 1";
Daniel Kang58156f12012-06-26 18:11:33 -0700183
184 EXPECT_GE(count_test_block, total_error)
Jingning Han362809d2013-06-18 10:46:33 -0700185 << "Error: FDCT/IDCT or FHT/IHT has average "
Jingning Han29b6e732013-06-21 16:00:44 -0700186 << "roundtrip error > 1 per block";
Jingning Han362809d2013-06-18 10:46:33 -0700187}
Daniel Kang58156f12012-06-26 18:11:33 -0700188
Jingning Han362809d2013-06-18 10:46:33 -0700189INSTANTIATE_TEST_CASE_P(VP9, FwdTrans4x4Test, ::testing::Range(0, 4));
Daniel Kang58156f12012-06-26 18:11:33 -0700190} // namespace