]> granicus.if.org Git - libvpx/blob - test/consistency_test.cc
Merge "Pad 'Left' when building under ASan"
[libvpx] / test / consistency_test.cc
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