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