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