Home | History | Annotate | Download | only in test
      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