consistency_test.cc 6.9 KB

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