blockiness_test.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. #include <limits.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <tuple>
  14. #include "third_party/googletest/src/include/gtest/gtest.h"
  15. #include "./vpx_config.h"
  16. #if CONFIG_VP9_ENCODER
  17. #include "./vp9_rtcd.h"
  18. #endif
  19. #include "test/acm_random.h"
  20. #include "test/clear_system_state.h"
  21. #include "test/register_state_check.h"
  22. #include "test/util.h"
  23. #include "vpx_mem/vpx_mem.h"
  24. #include "vp9/encoder/vp9_blockiness.h"
  25. using libvpx_test::ACMRandom;
  26. namespace {
  27. class BlockinessTestBase : public ::testing::Test {
  28. public:
  29. BlockinessTestBase(int width, int height) : width_(width), height_(height) {}
  30. static void SetUpTestCase() {
  31. source_data_ = reinterpret_cast<uint8_t *>(
  32. vpx_memalign(kDataAlignment, kDataBufferSize));
  33. reference_data_ = reinterpret_cast<uint8_t *>(
  34. vpx_memalign(kDataAlignment, kDataBufferSize));
  35. }
  36. static void TearDownTestCase() {
  37. vpx_free(source_data_);
  38. source_data_ = NULL;
  39. vpx_free(reference_data_);
  40. reference_data_ = NULL;
  41. }
  42. virtual void TearDown() { libvpx_test::ClearSystemState(); }
  43. protected:
  44. // Handle frames up to 640x480
  45. static const int kDataAlignment = 16;
  46. static const int kDataBufferSize = 640 * 480;
  47. virtual void SetUp() {
  48. source_stride_ = (width_ + 31) & ~31;
  49. reference_stride_ = width_ * 2;
  50. rnd_.Reset(ACMRandom::DeterministicSeed());
  51. }
  52. void FillConstant(uint8_t *data, int stride, uint8_t fill_constant, int width,
  53. int height) {
  54. for (int h = 0; h < height; ++h) {
  55. for (int w = 0; w < width; ++w) {
  56. data[h * stride + w] = fill_constant;
  57. }
  58. }
  59. }
  60. void FillConstant(uint8_t *data, int stride, uint8_t fill_constant) {
  61. FillConstant(data, stride, fill_constant, width_, height_);
  62. }
  63. void FillRandom(uint8_t *data, int stride, int width, int height) {
  64. for (int h = 0; h < height; ++h) {
  65. for (int w = 0; w < width; ++w) {
  66. data[h * stride + w] = rnd_.Rand8();
  67. }
  68. }
  69. }
  70. void FillRandom(uint8_t *data, int stride) {
  71. FillRandom(data, stride, width_, height_);
  72. }
  73. void FillRandomBlocky(uint8_t *data, int stride) {
  74. for (int h = 0; h < height_; h += 4) {
  75. for (int w = 0; w < width_; w += 4) {
  76. FillRandom(data + h * stride + w, stride, 4, 4);
  77. }
  78. }
  79. }
  80. void FillCheckerboard(uint8_t *data, int stride) {
  81. for (int h = 0; h < height_; h += 4) {
  82. for (int w = 0; w < width_; w += 4) {
  83. if (((h / 4) ^ (w / 4)) & 1) {
  84. FillConstant(data + h * stride + w, stride, 255, 4, 4);
  85. } else {
  86. FillConstant(data + h * stride + w, stride, 0, 4, 4);
  87. }
  88. }
  89. }
  90. }
  91. void Blur(uint8_t *data, int stride, int taps) {
  92. int sum = 0;
  93. int half_taps = taps / 2;
  94. for (int h = 0; h < height_; ++h) {
  95. for (int w = 0; w < taps; ++w) {
  96. sum += data[w + h * stride];
  97. }
  98. for (int w = taps; w < width_; ++w) {
  99. sum += data[w + h * stride] - data[w - taps + h * stride];
  100. data[w - half_taps + h * stride] = (sum + half_taps) / taps;
  101. }
  102. }
  103. for (int w = 0; w < width_; ++w) {
  104. for (int h = 0; h < taps; ++h) {
  105. sum += data[h + w * stride];
  106. }
  107. for (int h = taps; h < height_; ++h) {
  108. sum += data[w + h * stride] - data[(h - taps) * stride + w];
  109. data[(h - half_taps) * stride + w] = (sum + half_taps) / taps;
  110. }
  111. }
  112. }
  113. int width_, height_;
  114. static uint8_t *source_data_;
  115. int source_stride_;
  116. static uint8_t *reference_data_;
  117. int reference_stride_;
  118. ACMRandom rnd_;
  119. };
  120. #if CONFIG_VP9_ENCODER
  121. typedef std::tuple<int, int> BlockinessParam;
  122. class BlockinessVP9Test
  123. : public BlockinessTestBase,
  124. public ::testing::WithParamInterface<BlockinessParam> {
  125. public:
  126. BlockinessVP9Test() : BlockinessTestBase(GET_PARAM(0), GET_PARAM(1)) {}
  127. protected:
  128. double GetBlockiness() const {
  129. return vp9_get_blockiness(source_data_, source_stride_, reference_data_,
  130. reference_stride_, width_, height_);
  131. }
  132. };
  133. #endif // CONFIG_VP9_ENCODER
  134. uint8_t *BlockinessTestBase::source_data_ = NULL;
  135. uint8_t *BlockinessTestBase::reference_data_ = NULL;
  136. #if CONFIG_VP9_ENCODER
  137. TEST_P(BlockinessVP9Test, SourceBlockierThanReference) {
  138. // Source is blockier than reference.
  139. FillRandomBlocky(source_data_, source_stride_);
  140. FillConstant(reference_data_, reference_stride_, 128);
  141. const double super_blocky = GetBlockiness();
  142. EXPECT_DOUBLE_EQ(0.0, super_blocky)
  143. << "Blocky source should produce 0 blockiness.";
  144. }
  145. TEST_P(BlockinessVP9Test, ReferenceBlockierThanSource) {
  146. // Source is blockier than reference.
  147. FillConstant(source_data_, source_stride_, 128);
  148. FillRandomBlocky(reference_data_, reference_stride_);
  149. const double super_blocky = GetBlockiness();
  150. EXPECT_GT(super_blocky, 0.0)
  151. << "Blocky reference should score high for blockiness.";
  152. }
  153. TEST_P(BlockinessVP9Test, BlurringDecreasesBlockiness) {
  154. // Source is blockier than reference.
  155. FillConstant(source_data_, source_stride_, 128);
  156. FillRandomBlocky(reference_data_, reference_stride_);
  157. const double super_blocky = GetBlockiness();
  158. Blur(reference_data_, reference_stride_, 4);
  159. const double less_blocky = GetBlockiness();
  160. EXPECT_GT(super_blocky, less_blocky)
  161. << "A straight blur should decrease blockiness.";
  162. }
  163. TEST_P(BlockinessVP9Test, WorstCaseBlockiness) {
  164. // Source is blockier than reference.
  165. FillConstant(source_data_, source_stride_, 128);
  166. FillCheckerboard(reference_data_, reference_stride_);
  167. const double super_blocky = GetBlockiness();
  168. Blur(reference_data_, reference_stride_, 4);
  169. const double less_blocky = GetBlockiness();
  170. EXPECT_GT(super_blocky, less_blocky)
  171. << "A straight blur should decrease blockiness.";
  172. }
  173. #endif // CONFIG_VP9_ENCODER
  174. using std::make_tuple;
  175. //------------------------------------------------------------------------------
  176. // C functions
  177. #if CONFIG_VP9_ENCODER
  178. const BlockinessParam c_vp9_tests[] = { make_tuple(320, 240),
  179. make_tuple(318, 242),
  180. make_tuple(318, 238) };
  181. INSTANTIATE_TEST_CASE_P(C, BlockinessVP9Test, ::testing::ValuesIn(c_vp9_tests));
  182. #endif
  183. } // namespace