diff --git a/test/acm_random.h b/test/acm_random.h new file mode 100644 index 000000000..81f764abe --- /dev/null +++ b/test/acm_random.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#ifndef LIBVPX_TEST_ACM_RANDOM_H_ +#define LIBVPX_TEST_ACM_RANDOM_H_ + +#include + +#include "vpx/vpx_integer.h" + +namespace libvpx_test { + +class ACMRandom { + public: + explicit ACMRandom(int seed) { Reset(seed); } + + void Reset(int seed) { srand(seed); } + + uint8_t Rand8(void) { return (rand() >> 8) & 0xff; } + + int PseudoUniform(int range) { return (rand() >> 8) % range; } + + int operator()(int n) { return PseudoUniform(n); } + + static int DeterministicSeed(void) { return 0xbaba; } +}; + +} // namespace libvpx_test + +#endif // LIBVPX_TEST_ACM_RANDOM_H_ diff --git a/test/boolcoder_test.cc b/test/boolcoder_test.cc index 0c7e2201f..4c93b1686 100644 --- a/test/boolcoder_test.cc +++ b/test/boolcoder_test.cc @@ -8,38 +8,24 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include +#include +#include + +#include "third_party/googletest/src/include/gtest/gtest.h" + extern "C" { #include "vp8/encoder/boolhuff.h" #include "vp8/decoder/dboolhuff.h" } -#include -#include -#include -#include -#include -#include - -#include "third_party/googletest/src/include/gtest/gtest.h" +#include "acm_random.h" #include "vpx/vpx_integer.h" +using libvpx_test::ACMRandom; + namespace { const int num_tests = 10; - -class ACMRandom { - public: - explicit ACMRandom(int seed) { Reset(seed); } - - void Reset(int seed) { srand(seed); } - - uint8_t Rand8(void) { return (rand() >> 8) & 0xff; } - - int PseudoUniform(int range) { return (rand() >> 8) % range; } - - int operator()(int n) { return PseudoUniform(n); } - - static int DeterministicSeed(void) { return 0xbaba; } -}; } // namespace TEST(VP8, TestBitIO) { diff --git a/test/fdct4x4_test.cc b/test/fdct4x4_test.cc index c4ecbdf43..d88ed8df6 100644 --- a/test/fdct4x4_test.cc +++ b/test/fdct4x4_test.cc @@ -19,25 +19,13 @@ extern "C" { #include "vp8/encoder/dct.h" } +#include "acm_random.h" #include "vpx/vpx_integer.h" +using libvpx_test::ACMRandom; + namespace { -class ACMRandom { - public: - explicit ACMRandom(int seed) { Reset(seed); } - - void Reset(int seed) { srand(seed); } - - uint8_t Rand8(void) { return (rand() >> 8) & 0xff; } - - int PseudoUniform(int range) { return (rand() >> 8) % range; } - - int operator()(int n) { return PseudoUniform(n); } - - static int DeterministicSeed(void) { return 0xbaba; } -}; - TEST(Vp8FdctTest, SignBiasCheck) { ACMRandom rnd(ACMRandom::DeterministicSeed()); int16_t test_input_block[16]; diff --git a/test/fdct8x8_test.cc b/test/fdct8x8_test.cc new file mode 100644 index 000000000..47b88acd1 --- /dev/null +++ b/test/fdct8x8_test.cc @@ -0,0 +1,158 @@ +/* + * 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 +#include +#include + +#include "third_party/googletest/src/include/gtest/gtest.h" + +extern "C" { +#include "vp8/encoder/dct.h" +#include "vp8/common/idct.h" +} + +#include "acm_random.h" +#include "vpx/vpx_integer.h" + +using libvpx_test::ACMRandom; + +namespace { + +TEST(VP8Fdct8x8Test, SignBiasCheck) { + 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(); + + vp8_short_fdct8x8_c(test_input_block, test_output_block, pitch); + + 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) { + const bool bias_acceptable = (abs(count_sign_block[j][0] - + count_sign_block[j][1]) < 1000); + EXPECT_TRUE(bias_acceptable) + << "Error: 8x8 FDCT has a sign bias > 1%" + << " for input range [-255, 255] at index " << j; + } + + 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); + + vp8_short_fdct8x8_c(test_input_block, test_output_block, pitch); + + 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) { + const bool bias_acceptable = (abs(count_sign_block[j][0] - + count_sign_block[j][1]) < 10000); + EXPECT_TRUE(bias_acceptable) + << "Error: 8x8 FDCT has a sign bias > 10%" + << " for input range [-15, 15] at index " << j; + } +}; + +TEST(VP8Fdct8x8Test, RoundTripErrorCheck) { + 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]; + int16_t test_output_block[64]; + + // Initialize a test block with input range [-255, 255]. + for (int j = 0; j < 64; ++j) + test_input_block[j] = rnd.Rand8() - rnd.Rand8(); + + const int pitch = 16; + vp8_short_fdct8x8_c(test_input_block, test_temp_block, pitch); + vp8_short_idct8x8_c(test_temp_block, test_output_block, pitch); + + for (int j = 0; j < 64; ++j) { + const int diff = test_input_block[j] - test_output_block[j]; + const int error = diff * diff; + if (max_error < error) + max_error = error; + total_error += error; + } + } + + EXPECT_GE(1, max_error) + << "Error: 8x8 FDCT/IDCT has an individual roundtrip error > 1"; + + EXPECT_GE(count_test_block, total_error) + << "Error: 8x8 FDCT/IDCT has average roundtrip error > 1 per block"; +}; + +TEST(VP8Fdct8x8Test, ExtremalCheck) { + 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]; + int16_t test_output_block[64]; + + // Initialize a test block with input range {-255, 255}. + for (int j = 0; j < 64; ++j) + test_input_block[j] = rnd.Rand8() % 2 ? 255 : -255; + + const int pitch = 16; + vp8_short_fdct8x8_c(test_input_block, test_temp_block, pitch); + vp8_short_idct8x8_c(test_temp_block, test_output_block, pitch); + + for (int j = 0; j < 64; ++j) { + const int diff = test_input_block[j] - test_output_block[j]; + const int error = diff * diff; + if (max_error < error) + max_error = error; + total_error += error; + } + + EXPECT_GE(1, max_error) + << "Error: Extremal 8x8 FDCT/IDCT has an" + << " individual roundtrip error > 1"; + + EXPECT_GE(count_test_block, total_error) + << "Error: Extremal 8x8 FDCT/IDCT has average" + << " roundtrip error > 1 per block"; + } +}; + +} // namespace diff --git a/test/test.mk b/test/test.mk index a9ccaf2d3..601050eb9 100644 --- a/test/test.mk +++ b/test/test.mk @@ -1,6 +1,8 @@ LIBVPX_TEST_SRCS-yes += test.mk +LIBVPX_TEST_SRCS-yes += acm_random.h LIBVPX_TEST_SRCS-yes += boolcoder_test.cc LIBVPX_TEST_SRCS-yes += fdct4x4_test.cc +LIBVPX_TEST_SRCS-yes += fdct8x8_test.cc LIBVPX_TEST_SRCS-yes += test_libvpx.cc LIBVPX_TEST_DATA-yes += hantro_collage_w352h288.yuv