av1_inv_txfm2d_test.cc 8.09 KB
Newer Older
Angie Chiang's avatar
Angie Chiang committed
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Angie Chiang's avatar
Angie Chiang committed
3
 *
4 5 6 7 8 9
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Angie Chiang's avatar
Angie Chiang committed
10 11 12 13 14
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
15
#include <vector>
Angie Chiang's avatar
Angie Chiang committed
16

Yaowu Xu's avatar
Yaowu Xu committed
17
#include "./av1_rtcd.h"
Angie Chiang's avatar
Angie Chiang committed
18
#include "test/acm_random.h"
19
#include "test/util.h"
Yaowu Xu's avatar
Yaowu Xu committed
20
#include "test/av1_txfm_test.h"
21
#include "av1/common/av1_inv_txfm1d_cfg.h"
Angie Chiang's avatar
Angie Chiang committed
22

23 24 25
using libaom_test::ACMRandom;
using libaom_test::Fwd_Txfm2d_Func;
using libaom_test::Inv_Txfm2d_Func;
Johann's avatar
Johann committed
26 27 28
using libaom_test::bd;
using libaom_test::compute_avg_abs_error;
using libaom_test::input_base;
Angie Chiang's avatar
Angie Chiang committed
29

30 31
using std::vector;

Angie Chiang's avatar
Angie Chiang committed
32 33
namespace {

Yaowu Xu's avatar
Yaowu Xu committed
34
// AV1InvTxfm2dParam argument list:
35
// tx_type_, tx_size_, max_error_, max_avg_error_
Yaowu Xu's avatar
Yaowu Xu committed
36
typedef std::tr1::tuple<TX_TYPE, TX_SIZE, int, double> AV1InvTxfm2dParam;
37

Yaowu Xu's avatar
Yaowu Xu committed
38
class AV1InvTxfm2d : public ::testing::TestWithParam<AV1InvTxfm2dParam> {
39 40 41 42 43 44 45 46 47
 public:
  virtual void SetUp() {
    tx_type_ = GET_PARAM(0);
    tx_size_ = GET_PARAM(1);
    max_error_ = GET_PARAM(2);
    max_avg_error_ = GET_PARAM(3);
  }

  void RunRoundtripCheck() {
Angie Chiang's avatar
Angie Chiang committed
48 49 50
    int tx_w = tx_size_wide[tx_size_];
    int tx_h = tx_size_high[tx_size_];
    int txfm2d_size = tx_w * tx_h;
51
    const Fwd_Txfm2d_Func fwd_txfm_func =
52
        libaom_test::fwd_txfm_func_ls[tx_size_];
53
    const Inv_Txfm2d_Func inv_txfm_func =
54
        libaom_test::inv_txfm_func_ls[tx_size_];
55 56
    double avg_abs_error = 0;
    ACMRandom rnd(ACMRandom::DeterministicSeed());
Sebastien Alaiwan's avatar
Sebastien Alaiwan committed
57

58
    const int count = 500;
Sebastien Alaiwan's avatar
Sebastien Alaiwan committed
59

60
    for (int ci = 0; ci < count; ci++) {
Yaowu Xu's avatar
Yaowu Xu committed
61
      DECLARE_ALIGNED(16, int16_t, input[64 * 64]) = { 0 };
62
      ASSERT_LE(txfm2d_size, NELEMENTS(input));
63

Angie Chiang's avatar
Angie Chiang committed
64
      for (int ni = 0; ni < txfm2d_size; ++ni) {
65 66
        if (ci == 0) {
          int extreme_input = input_base - 1;
67
          input[ni] = extreme_input;  // extreme case
68
        } else {
69 70 71 72
          input[ni] = rnd.Rand16() % input_base;
        }
      }

Yaowu Xu's avatar
Yaowu Xu committed
73
      DECLARE_ALIGNED(16, uint16_t, expected[64 * 64]) = { 0 };
74 75 76 77 78 79 80 81 82 83 84 85 86
      ASSERT_LE(txfm2d_size, NELEMENTS(expected));
      if (TxfmUsesApproximation()) {
        // Compare reference forward HT + inverse HT vs forward HT + inverse HT.
        double ref_input[64 * 64];
        ASSERT_LE(txfm2d_size, NELEMENTS(ref_input));
        for (int ni = 0; ni < txfm2d_size; ++ni) {
          ref_input[ni] = input[ni];
        }
        double ref_coeffs[64 * 64] = { 0 };
        ASSERT_LE(txfm2d_size, NELEMENTS(ref_coeffs));
        ASSERT_EQ(tx_type_, DCT_DCT);
        libaom_test::reference_hybrid_2d(ref_input, ref_coeffs, tx_type_,
                                         tx_size_);
Yaowu Xu's avatar
Yaowu Xu committed
87
        DECLARE_ALIGNED(16, int32_t, ref_coeffs_int[64 * 64]) = { 0 };
88 89 90 91 92 93 94 95 96
        ASSERT_LE(txfm2d_size, NELEMENTS(ref_coeffs_int));
        for (int ni = 0; ni < txfm2d_size; ++ni) {
          ref_coeffs_int[ni] = (int32_t)round(ref_coeffs[ni]);
        }
        inv_txfm_func(ref_coeffs_int, expected, tx_w, tx_type_, bd);
      } else {
        // Compare original input vs forward HT + inverse HT.
        for (int ni = 0; ni < txfm2d_size; ++ni) {
          expected[ni] = input[ni];
Angie Chiang's avatar
Angie Chiang committed
97
        }
98 99
      }

Yaowu Xu's avatar
Yaowu Xu committed
100
      DECLARE_ALIGNED(16, int32_t, coeffs[64 * 64]) = { 0 };
101
      ASSERT_LE(txfm2d_size, NELEMENTS(coeffs));
102
      fwd_txfm_func(input, coeffs, tx_w, tx_type_, bd);
103

Yaowu Xu's avatar
Yaowu Xu committed
104
      DECLARE_ALIGNED(16, uint16_t, actual[64 * 64]) = { 0 };
105
      ASSERT_LE(txfm2d_size, NELEMENTS(actual));
Angie Chiang's avatar
Angie Chiang committed
106
      inv_txfm_func(coeffs, actual, tx_w, tx_type_, bd);
Angie Chiang's avatar
Angie Chiang committed
107

108
      double actual_max_error = 0;
Angie Chiang's avatar
Angie Chiang committed
109
      for (int ni = 0; ni < txfm2d_size; ++ni) {
110 111 112 113 114 115 116
        const double this_error = abs(expected[ni] - actual[ni]);
        actual_max_error = AOMMAX(actual_max_error, this_error);
      }
      EXPECT_GE(max_error_, actual_max_error)
          << " tx_w: " << tx_w << " tx_h " << tx_h << " tx_type: " << tx_type_;
      if (actual_max_error > max_error_) {  // exit early.
        break;
Angie Chiang's avatar
Angie Chiang committed
117
      }
118
      avg_abs_error += compute_avg_abs_error<uint16_t, uint16_t>(
Angie Chiang's avatar
Angie Chiang committed
119
          expected, actual, txfm2d_size);
Angie Chiang's avatar
Angie Chiang committed
120 121
    }

122
    avg_abs_error /= count;
Angie Chiang's avatar
Angie Chiang committed
123 124
    EXPECT_GE(max_avg_error_, avg_abs_error)
        << " tx_w: " << tx_w << " tx_h " << tx_h << " tx_type: " << tx_type_;
Angie Chiang's avatar
Angie Chiang committed
125
  }
126 127

 private:
128 129 130 131 132 133 134 135 136
  bool TxfmUsesApproximation() {
#if CONFIG_TX64X64
    if (tx_size_wide[tx_size_] == 64 || tx_size_high[tx_size_] == 64) {
      return true;
    }
#endif  // CONFIG_TX64X64
    return false;
  }

137 138 139 140 141 142
  int max_error_;
  double max_avg_error_;
  TX_TYPE tx_type_;
  TX_SIZE tx_size_;
};

143 144
vector<AV1InvTxfm2dParam> GetInvTxfm2dParamList() {
  vector<AV1InvTxfm2dParam> param_list;
145
  for (int t = 0; t < TX_TYPES; ++t) {
146 147
    const TX_TYPE tx_type = static_cast<TX_TYPE>(t);
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_4X4, 2, 0.002));
Angie Chiang's avatar
Angie Chiang committed
148
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_8X8, 2, 0.05));
149 150
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_16X16, 2, 0.04));
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_32X32, 4, 0.4));
151 152
#if CONFIG_TX64X64
    if (tx_type == DCT_DCT) {  // Other types not supported by these tx sizes.
Angie Chiang's avatar
Angie Chiang committed
153
      param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_64X64, 3, 0.3));
154 155
    }
#endif  // CONFIG_TX64X64
156

Angie Chiang's avatar
Angie Chiang committed
157 158 159 160
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_4X8, 2, 0.09));
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_8X4, 2, 0.11));
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_8X16, 2, 0.03));
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_16X8, 2, 0.06));
161
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_16X32, 3, 0.4));
162
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_32X16, 3, 0.5));
163

164 165
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_4X16, 2, 0.2));
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_16X4, 2, 0.2));
166
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_8X32, 2, 0.2));
167
    param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_32X8, 2, 0.2));
168

169
#if CONFIG_TX64X64
170
    if (tx_type == DCT_DCT) {  // Other types not supported by these tx sizes.
171
      param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_32X64, 5, 0.38));
172
      param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_64X32, 5, 0.39));
173 174
      param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_16X64, 3, 0.38));
      param_list.push_back(AV1InvTxfm2dParam(tx_type, TX_64X16, 3, 0.38));
175
    }
176
#endif  // CONFIG_TX64X64
177 178 179
  }
  return param_list;
}
180

Yaowu Xu's avatar
Yaowu Xu committed
181
INSTANTIATE_TEST_CASE_P(C, AV1InvTxfm2d,
182 183 184
                        ::testing::ValuesIn(GetInvTxfm2dParamList()));

TEST_P(AV1InvTxfm2d, RunRoundtripCheck) { RunRoundtripCheck(); }
185

Angie Chiang's avatar
Angie Chiang committed
186 187 188 189 190
TEST(AV1InvTxfm2d, CfgTest) {
  for (int bd_idx = 0; bd_idx < BD_NUM; ++bd_idx) {
    int bd = libaom_test::bd_arr[bd_idx];
    int8_t low_range = libaom_test::low_range_arr[bd_idx];
    int8_t high_range = libaom_test::high_range_arr[bd_idx];
191
    for (int tx_size = 0; tx_size < TX_SIZES_ALL; ++tx_size) {
Angie Chiang's avatar
Angie Chiang committed
192
      for (int tx_type = 0; tx_type < TX_TYPES; ++tx_type) {
Urvang Joshi's avatar
Urvang Joshi committed
193
#if CONFIG_TX64X64
194 195 196 197
        if ((tx_size_wide[tx_size] == 64 || tx_size_high[tx_size] == 64) &&
            tx_type != DCT_DCT) {
          continue;
        }
Urvang Joshi's avatar
Urvang Joshi committed
198
#endif  // CONFIG_TX64X64
199 200 201
        TXFM_2D_FLIP_CFG cfg;
        av1_get_inv_txfm_cfg(static_cast<TX_TYPE>(tx_type),
                             static_cast<TX_SIZE>(tx_size), &cfg);
Angie Chiang's avatar
Angie Chiang committed
202 203 204
        int8_t stage_range_col[MAX_TXFM_STAGE_NUM];
        int8_t stage_range_row[MAX_TXFM_STAGE_NUM];
        av1_gen_inv_stage_range(stage_range_col, stage_range_row, &cfg,
205
                                (TX_SIZE)tx_size, bd);
Angie Chiang's avatar
Angie Chiang committed
206 207 208 209 210 211 212 213 214 215 216 217
        const TXFM_1D_CFG *col_cfg = cfg.col_cfg;
        const TXFM_1D_CFG *row_cfg = cfg.row_cfg;
        libaom_test::txfm_stage_range_check(stage_range_col, col_cfg->stage_num,
                                            col_cfg->cos_bit, low_range,
                                            high_range);
        libaom_test::txfm_stage_range_check(stage_range_row, row_cfg->stage_num,
                                            row_cfg->cos_bit, low_range,
                                            high_range);
      }
    }
  }
}
218
}  // namespace