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