consistency_test.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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_dsp/ssim.h"
  24. #include "vpx_mem/vpx_mem.h"
  25. extern "C" double vpx_get_ssim_metrics(uint8_t *img1, int img1_pitch,
  26. uint8_t *img2, int img2_pitch, int width,
  27. int height, Ssimv *sv2, Metrics *m,
  28. int do_inconsistency);
  29. using libvpx_test::ACMRandom;
  30. namespace {
  31. class ConsistencyTestBase : public ::testing::Test {
  32. public:
  33. ConsistencyTestBase(int width, int height) : width_(width), height_(height) {}
  34. static void SetUpTestCase() {
  35. source_data_[0] = reinterpret_cast<uint8_t *>(
  36. vpx_memalign(kDataAlignment, kDataBufferSize));
  37. reference_data_[0] = reinterpret_cast<uint8_t *>(
  38. vpx_memalign(kDataAlignment, kDataBufferSize));
  39. source_data_[1] = reinterpret_cast<uint8_t *>(
  40. vpx_memalign(kDataAlignment, kDataBufferSize));
  41. reference_data_[1] = reinterpret_cast<uint8_t *>(
  42. vpx_memalign(kDataAlignment, kDataBufferSize));
  43. ssim_array_ = new Ssimv[kDataBufferSize / 16];
  44. }
  45. static void ClearSsim() { memset(ssim_array_, 0, kDataBufferSize / 16); }
  46. static void TearDownTestCase() {
  47. vpx_free(source_data_[0]);
  48. source_data_[0] = NULL;
  49. vpx_free(reference_data_[0]);
  50. reference_data_[0] = NULL;
  51. vpx_free(source_data_[1]);
  52. source_data_[1] = NULL;
  53. vpx_free(reference_data_[1]);
  54. reference_data_[1] = NULL;
  55. delete[] ssim_array_;
  56. }
  57. virtual void TearDown() { libvpx_test::ClearSystemState(); }
  58. protected:
  59. // Handle frames up to 640x480
  60. static const int kDataAlignment = 16;
  61. static const int kDataBufferSize = 640 * 480;
  62. virtual void SetUp() {
  63. source_stride_ = (width_ + 31) & ~31;
  64. reference_stride_ = width_ * 2;
  65. rnd_.Reset(ACMRandom::DeterministicSeed());
  66. }
  67. void FillRandom(uint8_t *data, int stride, int width, int height) {
  68. for (int h = 0; h < height; ++h) {
  69. for (int w = 0; w < width; ++w) {
  70. data[h * stride + w] = rnd_.Rand8();
  71. }
  72. }
  73. }
  74. void FillRandom(uint8_t *data, int stride) {
  75. FillRandom(data, stride, width_, height_);
  76. }
  77. void Copy(uint8_t *reference, uint8_t *source) {
  78. memcpy(reference, source, kDataBufferSize);
  79. }
  80. void Blur(uint8_t *data, int stride, int taps) {
  81. int sum = 0;
  82. int half_taps = taps / 2;
  83. for (int h = 0; h < height_; ++h) {
  84. for (int w = 0; w < taps; ++w) {
  85. sum += data[w + h * stride];
  86. }
  87. for (int w = taps; w < width_; ++w) {
  88. sum += data[w + h * stride] - data[w - taps + h * stride];
  89. data[w - half_taps + h * stride] = (sum + half_taps) / taps;
  90. }
  91. }
  92. for (int w = 0; w < width_; ++w) {
  93. for (int h = 0; h < taps; ++h) {
  94. sum += data[h + w * stride];
  95. }
  96. for (int h = taps; h < height_; ++h) {
  97. sum += data[w + h * stride] - data[(h - taps) * stride + w];
  98. data[(h - half_taps) * stride + w] = (sum + half_taps) / taps;
  99. }
  100. }
  101. }
  102. int width_, height_;
  103. static uint8_t *source_data_[2];
  104. int source_stride_;
  105. static uint8_t *reference_data_[2];
  106. int reference_stride_;
  107. static Ssimv *ssim_array_;
  108. Metrics metrics_;
  109. ACMRandom rnd_;
  110. };
  111. #if CONFIG_VP9_ENCODER
  112. typedef std::tuple<int, int> ConsistencyParam;
  113. class ConsistencyVP9Test
  114. : public ConsistencyTestBase,
  115. public ::testing::WithParamInterface<ConsistencyParam> {
  116. public:
  117. ConsistencyVP9Test() : ConsistencyTestBase(GET_PARAM(0), GET_PARAM(1)) {}
  118. protected:
  119. double CheckConsistency(int frame) {
  120. EXPECT_LT(frame, 2) << "Frame to check has to be less than 2.";
  121. return vpx_get_ssim_metrics(source_data_[frame], source_stride_,
  122. reference_data_[frame], reference_stride_,
  123. width_, height_, ssim_array_, &metrics_, 1);
  124. }
  125. };
  126. #endif // CONFIG_VP9_ENCODER
  127. uint8_t *ConsistencyTestBase::source_data_[2] = { NULL, NULL };
  128. uint8_t *ConsistencyTestBase::reference_data_[2] = { NULL, NULL };
  129. Ssimv *ConsistencyTestBase::ssim_array_ = NULL;
  130. #if CONFIG_VP9_ENCODER
  131. TEST_P(ConsistencyVP9Test, ConsistencyIsZero) {
  132. FillRandom(source_data_[0], source_stride_);
  133. Copy(source_data_[1], source_data_[0]);
  134. Copy(reference_data_[0], source_data_[0]);
  135. Blur(reference_data_[0], reference_stride_, 3);
  136. Copy(reference_data_[1], source_data_[0]);
  137. Blur(reference_data_[1], reference_stride_, 3);
  138. double inconsistency = CheckConsistency(1);
  139. inconsistency = CheckConsistency(0);
  140. EXPECT_EQ(inconsistency, 0.0)
  141. << "Should have 0 inconsistency if they are exactly the same.";
  142. // If sources are not consistent reference frames inconsistency should
  143. // be less than if the source is consistent.
  144. FillRandom(source_data_[0], source_stride_);
  145. FillRandom(source_data_[1], source_stride_);
  146. FillRandom(reference_data_[0], reference_stride_);
  147. FillRandom(reference_data_[1], reference_stride_);
  148. CheckConsistency(0);
  149. inconsistency = CheckConsistency(1);
  150. Copy(source_data_[1], source_data_[0]);
  151. CheckConsistency(0);
  152. double inconsistency2 = CheckConsistency(1);
  153. EXPECT_LT(inconsistency, inconsistency2)
  154. << "Should have less inconsistency if source itself is inconsistent.";
  155. // Less of a blur should be less inconsistent than more blur coming off a
  156. // a frame with no blur.
  157. ClearSsim();
  158. FillRandom(source_data_[0], source_stride_);
  159. Copy(source_data_[1], source_data_[0]);
  160. Copy(reference_data_[0], source_data_[0]);
  161. Copy(reference_data_[1], source_data_[0]);
  162. Blur(reference_data_[1], reference_stride_, 4);
  163. CheckConsistency(0);
  164. inconsistency = CheckConsistency(1);
  165. ClearSsim();
  166. Copy(reference_data_[1], source_data_[0]);
  167. Blur(reference_data_[1], reference_stride_, 8);
  168. CheckConsistency(0);
  169. inconsistency2 = CheckConsistency(1);
  170. EXPECT_LT(inconsistency, inconsistency2)
  171. << "Stronger Blur should produce more inconsistency.";
  172. }
  173. #endif // CONFIG_VP9_ENCODER
  174. using std::make_tuple;
  175. //------------------------------------------------------------------------------
  176. // C functions
  177. #if CONFIG_VP9_ENCODER
  178. const ConsistencyParam c_vp9_tests[] = { make_tuple(320, 240),
  179. make_tuple(318, 242),
  180. make_tuple(318, 238) };
  181. INSTANTIATE_TEST_CASE_P(C, ConsistencyVP9Test,
  182. ::testing::ValuesIn(c_vp9_tests));
  183. #endif
  184. } // namespace