• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <tuple>
15 
16 #include "third_party/googletest/src/include/gtest/gtest.h"
17 
18 #include "./vpx_config.h"
19 #if CONFIG_VP9_ENCODER
20 #include "./vp9_rtcd.h"
21 #endif
22 
23 #include "test/acm_random.h"
24 #include "test/clear_system_state.h"
25 #include "test/register_state_check.h"
26 #include "test/util.h"
27 
28 #include "vpx_mem/vpx_mem.h"
29 #include "vp9/encoder/vp9_blockiness.h"
30 
31 using libvpx_test::ACMRandom;
32 
33 namespace {
34 class BlockinessTestBase : public ::testing::Test {
35  public:
BlockinessTestBase(int width,int height)36   BlockinessTestBase(int width, int height) : width_(width), height_(height) {}
37 
SetUpTestCase()38   static void SetUpTestCase() {
39     source_data_ = reinterpret_cast<uint8_t *>(
40         vpx_memalign(kDataAlignment, kDataBufferSize));
41     reference_data_ = reinterpret_cast<uint8_t *>(
42         vpx_memalign(kDataAlignment, kDataBufferSize));
43   }
44 
TearDownTestCase()45   static void TearDownTestCase() {
46     vpx_free(source_data_);
47     source_data_ = NULL;
48     vpx_free(reference_data_);
49     reference_data_ = NULL;
50   }
51 
TearDown()52   virtual void TearDown() { libvpx_test::ClearSystemState(); }
53 
54  protected:
55   // Handle frames up to 640x480
56   static const int kDataAlignment = 16;
57   static const int kDataBufferSize = 640 * 480;
58 
SetUp()59   virtual void SetUp() {
60     source_stride_ = (width_ + 31) & ~31;
61     reference_stride_ = width_ * 2;
62     rnd_.Reset(ACMRandom::DeterministicSeed());
63   }
64 
FillConstant(uint8_t * data,int stride,uint8_t fill_constant,int width,int height)65   void FillConstant(uint8_t *data, int stride, uint8_t fill_constant, int width,
66                     int height) {
67     for (int h = 0; h < height; ++h) {
68       for (int w = 0; w < width; ++w) {
69         data[h * stride + w] = fill_constant;
70       }
71     }
72   }
73 
FillConstant(uint8_t * data,int stride,uint8_t fill_constant)74   void FillConstant(uint8_t *data, int stride, uint8_t fill_constant) {
75     FillConstant(data, stride, fill_constant, width_, height_);
76   }
77 
FillRandom(uint8_t * data,int stride,int width,int height)78   void FillRandom(uint8_t *data, int stride, int width, int height) {
79     for (int h = 0; h < height; ++h) {
80       for (int w = 0; w < width; ++w) {
81         data[h * stride + w] = rnd_.Rand8();
82       }
83     }
84   }
85 
FillRandom(uint8_t * data,int stride)86   void FillRandom(uint8_t *data, int stride) {
87     FillRandom(data, stride, width_, height_);
88   }
89 
FillRandomBlocky(uint8_t * data,int stride)90   void FillRandomBlocky(uint8_t *data, int stride) {
91     for (int h = 0; h < height_; h += 4) {
92       for (int w = 0; w < width_; w += 4) {
93         FillRandom(data + h * stride + w, stride, 4, 4);
94       }
95     }
96   }
97 
FillCheckerboard(uint8_t * data,int stride)98   void FillCheckerboard(uint8_t *data, int stride) {
99     for (int h = 0; h < height_; h += 4) {
100       for (int w = 0; w < width_; w += 4) {
101         if (((h / 4) ^ (w / 4)) & 1) {
102           FillConstant(data + h * stride + w, stride, 255, 4, 4);
103         } else {
104           FillConstant(data + h * stride + w, stride, 0, 4, 4);
105         }
106       }
107     }
108   }
109 
Blur(uint8_t * data,int stride,int taps)110   void Blur(uint8_t *data, int stride, int taps) {
111     int sum = 0;
112     int half_taps = taps / 2;
113     for (int h = 0; h < height_; ++h) {
114       for (int w = 0; w < taps; ++w) {
115         sum += data[w + h * stride];
116       }
117       for (int w = taps; w < width_; ++w) {
118         sum += data[w + h * stride] - data[w - taps + h * stride];
119         data[w - half_taps + h * stride] = (sum + half_taps) / taps;
120       }
121     }
122     for (int w = 0; w < width_; ++w) {
123       for (int h = 0; h < taps; ++h) {
124         sum += data[h + w * stride];
125       }
126       for (int h = taps; h < height_; ++h) {
127         sum += data[w + h * stride] - data[(h - taps) * stride + w];
128         data[(h - half_taps) * stride + w] = (sum + half_taps) / taps;
129       }
130     }
131   }
132   int width_, height_;
133   static uint8_t *source_data_;
134   int source_stride_;
135   static uint8_t *reference_data_;
136   int reference_stride_;
137 
138   ACMRandom rnd_;
139 };
140 
141 #if CONFIG_VP9_ENCODER
142 typedef std::tuple<int, int> BlockinessParam;
143 class BlockinessVP9Test
144     : public BlockinessTestBase,
145       public ::testing::WithParamInterface<BlockinessParam> {
146  public:
BlockinessVP9Test()147   BlockinessVP9Test() : BlockinessTestBase(GET_PARAM(0), GET_PARAM(1)) {}
148 
149  protected:
GetBlockiness() const150   double GetBlockiness() const {
151     return vp9_get_blockiness(source_data_, source_stride_, reference_data_,
152                               reference_stride_, width_, height_);
153   }
154 };
155 #endif  // CONFIG_VP9_ENCODER
156 
157 uint8_t *BlockinessTestBase::source_data_ = NULL;
158 uint8_t *BlockinessTestBase::reference_data_ = NULL;
159 
160 #if CONFIG_VP9_ENCODER
TEST_P(BlockinessVP9Test,SourceBlockierThanReference)161 TEST_P(BlockinessVP9Test, SourceBlockierThanReference) {
162   // Source is blockier than reference.
163   FillRandomBlocky(source_data_, source_stride_);
164   FillConstant(reference_data_, reference_stride_, 128);
165   const double super_blocky = GetBlockiness();
166 
167   EXPECT_DOUBLE_EQ(0.0, super_blocky)
168       << "Blocky source should produce 0 blockiness.";
169 }
170 
TEST_P(BlockinessVP9Test,ReferenceBlockierThanSource)171 TEST_P(BlockinessVP9Test, ReferenceBlockierThanSource) {
172   // Source is blockier than reference.
173   FillConstant(source_data_, source_stride_, 128);
174   FillRandomBlocky(reference_data_, reference_stride_);
175   const double super_blocky = GetBlockiness();
176 
177   EXPECT_GT(super_blocky, 0.0)
178       << "Blocky reference should score high for blockiness.";
179 }
180 
TEST_P(BlockinessVP9Test,BlurringDecreasesBlockiness)181 TEST_P(BlockinessVP9Test, BlurringDecreasesBlockiness) {
182   // Source is blockier than reference.
183   FillConstant(source_data_, source_stride_, 128);
184   FillRandomBlocky(reference_data_, reference_stride_);
185   const double super_blocky = GetBlockiness();
186 
187   Blur(reference_data_, reference_stride_, 4);
188   const double less_blocky = GetBlockiness();
189 
190   EXPECT_GT(super_blocky, less_blocky)
191       << "A straight blur should decrease blockiness.";
192 }
193 
TEST_P(BlockinessVP9Test,WorstCaseBlockiness)194 TEST_P(BlockinessVP9Test, WorstCaseBlockiness) {
195   // Source is blockier than reference.
196   FillConstant(source_data_, source_stride_, 128);
197   FillCheckerboard(reference_data_, reference_stride_);
198 
199   const double super_blocky = GetBlockiness();
200 
201   Blur(reference_data_, reference_stride_, 4);
202   const double less_blocky = GetBlockiness();
203 
204   EXPECT_GT(super_blocky, less_blocky)
205       << "A straight blur should decrease blockiness.";
206 }
207 #endif  // CONFIG_VP9_ENCODER
208 
209 using std::make_tuple;
210 
211 //------------------------------------------------------------------------------
212 // C functions
213 
214 #if CONFIG_VP9_ENCODER
215 const BlockinessParam c_vp9_tests[] = { make_tuple(320, 240),
216                                         make_tuple(318, 242),
217                                         make_tuple(318, 238) };
218 INSTANTIATE_TEST_CASE_P(C, BlockinessVP9Test, ::testing::ValuesIn(c_vp9_tests));
219 #endif
220 
221 }  // namespace
222