Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // MSVC++ requires this to be set before any other includes to get M_PI.
      6 #define _USE_MATH_DEFINES
      7 #include <cmath>
      8 
      9 #include "base/memory/aligned_memory.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/stringize_macros.h"
     13 #include "media/base/vector_math.h"
     14 #include "media/base/vector_math_testing.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 using std::fill;
     18 
     19 namespace media {
     20 
     21 // Default test values.
     22 static const float kScale = 0.5;
     23 static const float kInputFillValue = 1.0;
     24 static const float kOutputFillValue = 3.0;
     25 static const int kVectorSize = 8192;
     26 
     27 class VectorMathTest : public testing::Test {
     28  public:
     29 
     30   VectorMathTest() {
     31     // Initialize input and output vectors.
     32     input_vector_.reset(static_cast<float*>(base::AlignedAlloc(
     33         sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
     34     output_vector_.reset(static_cast<float*>(base::AlignedAlloc(
     35         sizeof(float) * kVectorSize, vector_math::kRequiredAlignment)));
     36   }
     37 
     38   void FillTestVectors(float input, float output) {
     39     // Setup input and output vectors.
     40     fill(input_vector_.get(), input_vector_.get() + kVectorSize, input);
     41     fill(output_vector_.get(), output_vector_.get() + kVectorSize, output);
     42   }
     43 
     44   void VerifyOutput(float value) {
     45     for (int i = 0; i < kVectorSize; ++i)
     46       ASSERT_FLOAT_EQ(output_vector_[i], value);
     47   }
     48 
     49  protected:
     50   scoped_ptr<float[], base::AlignedFreeDeleter> input_vector_;
     51   scoped_ptr<float[], base::AlignedFreeDeleter> output_vector_;
     52 
     53   DISALLOW_COPY_AND_ASSIGN(VectorMathTest);
     54 };
     55 
     56 // Ensure each optimized vector_math::FMAC() method returns the same value.
     57 TEST_F(VectorMathTest, FMAC) {
     58   static const float kResult = kInputFillValue * kScale + kOutputFillValue;
     59 
     60   {
     61     SCOPED_TRACE("FMAC");
     62     FillTestVectors(kInputFillValue, kOutputFillValue);
     63     vector_math::FMAC(
     64         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     65     VerifyOutput(kResult);
     66   }
     67 
     68   {
     69     SCOPED_TRACE("FMAC_C");
     70     FillTestVectors(kInputFillValue, kOutputFillValue);
     71     vector_math::FMAC_C(
     72         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     73     VerifyOutput(kResult);
     74   }
     75 
     76 #if defined(ARCH_CPU_X86_FAMILY)
     77   {
     78     SCOPED_TRACE("FMAC_SSE");
     79     FillTestVectors(kInputFillValue, kOutputFillValue);
     80     vector_math::FMAC_SSE(
     81         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     82     VerifyOutput(kResult);
     83   }
     84 #endif
     85 
     86 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
     87   {
     88     SCOPED_TRACE("FMAC_NEON");
     89     FillTestVectors(kInputFillValue, kOutputFillValue);
     90     vector_math::FMAC_NEON(
     91         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
     92     VerifyOutput(kResult);
     93   }
     94 #endif
     95 }
     96 
     97 // Ensure each optimized vector_math::FMUL() method returns the same value.
     98 TEST_F(VectorMathTest, FMUL) {
     99   static const float kResult = kInputFillValue * kScale;
    100 
    101   {
    102     SCOPED_TRACE("FMUL");
    103     FillTestVectors(kInputFillValue, kOutputFillValue);
    104     vector_math::FMUL(
    105         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
    106     VerifyOutput(kResult);
    107   }
    108 
    109   {
    110     SCOPED_TRACE("FMUL_C");
    111     FillTestVectors(kInputFillValue, kOutputFillValue);
    112     vector_math::FMUL_C(
    113         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
    114     VerifyOutput(kResult);
    115   }
    116 
    117 #if defined(ARCH_CPU_X86_FAMILY)
    118   {
    119     SCOPED_TRACE("FMUL_SSE");
    120     FillTestVectors(kInputFillValue, kOutputFillValue);
    121     vector_math::FMUL_SSE(
    122         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
    123     VerifyOutput(kResult);
    124   }
    125 #endif
    126 
    127 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
    128   {
    129     SCOPED_TRACE("FMUL_NEON");
    130     FillTestVectors(kInputFillValue, kOutputFillValue);
    131     vector_math::FMUL_NEON(
    132         input_vector_.get(), kScale, kVectorSize, output_vector_.get());
    133     VerifyOutput(kResult);
    134   }
    135 #endif
    136 }
    137 
    138 TEST_F(VectorMathTest, Crossfade) {
    139   FillTestVectors(0, 1);
    140   vector_math::Crossfade(
    141       input_vector_.get(), kVectorSize, output_vector_.get());
    142   for (int i = 0; i < kVectorSize; ++i) {
    143     ASSERT_FLOAT_EQ(i / static_cast<float>(kVectorSize), output_vector_[i])
    144         << "i=" << i;
    145   }
    146 }
    147 
    148 class EWMATestScenario {
    149  public:
    150   EWMATestScenario(float initial_value, const float src[], int len,
    151                    float smoothing_factor)
    152       : initial_value_(initial_value),
    153         data_(static_cast<float*>(
    154             len == 0 ? NULL :
    155             base::AlignedAlloc(len * sizeof(float),
    156                                vector_math::kRequiredAlignment))),
    157         data_len_(len),
    158         smoothing_factor_(smoothing_factor),
    159         expected_final_avg_(initial_value),
    160         expected_max_(0.0f) {
    161     if (data_len_ > 0)
    162       memcpy(data_.get(), src, len * sizeof(float));
    163   }
    164 
    165   // Copy constructor and assignment operator for ::testing::Values(...).
    166   EWMATestScenario(const EWMATestScenario& other) { *this = other; }
    167   EWMATestScenario& operator=(const EWMATestScenario& other) {
    168     this->initial_value_ = other.initial_value_;
    169     this->smoothing_factor_ = other.smoothing_factor_;
    170     if (other.data_len_ == 0) {
    171       this->data_.reset();
    172     } else {
    173       this->data_.reset(static_cast<float*>(
    174         base::AlignedAlloc(other.data_len_ * sizeof(float),
    175                            vector_math::kRequiredAlignment)));
    176       memcpy(this->data_.get(), other.data_.get(),
    177              other.data_len_ * sizeof(float));
    178     }
    179     this->data_len_ = other.data_len_;
    180     this->expected_final_avg_ = other.expected_final_avg_;
    181     this->expected_max_ = other.expected_max_;
    182     return *this;
    183   }
    184 
    185   EWMATestScenario ScaledBy(float scale) const {
    186     EWMATestScenario result(*this);
    187     float* p = result.data_.get();
    188     float* const p_end = p + result.data_len_;
    189     for (; p < p_end; ++p)
    190       *p *= scale;
    191     return result;
    192   }
    193 
    194   EWMATestScenario WithImpulse(float value, int offset) const {
    195     EWMATestScenario result(*this);
    196     result.data_.get()[offset] = value;
    197     return result;
    198   }
    199 
    200   EWMATestScenario HasExpectedResult(float final_avg_value,
    201                                      float max_value) const {
    202     EWMATestScenario result(*this);
    203     result.expected_final_avg_ = final_avg_value;
    204     result.expected_max_ = max_value;
    205     return result;
    206   }
    207 
    208   void RunTest() const {
    209     {
    210       SCOPED_TRACE("EWMAAndMaxPower");
    211       const std::pair<float, float>& result = vector_math::EWMAAndMaxPower(
    212           initial_value_, data_.get(), data_len_, smoothing_factor_);
    213       EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
    214       EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
    215     }
    216 
    217     {
    218       SCOPED_TRACE("EWMAAndMaxPower_C");
    219       const std::pair<float, float>& result = vector_math::EWMAAndMaxPower_C(
    220           initial_value_, data_.get(), data_len_, smoothing_factor_);
    221       EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
    222       EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
    223     }
    224 
    225 #if defined(ARCH_CPU_X86_FAMILY)
    226     {
    227       SCOPED_TRACE("EWMAAndMaxPower_SSE");
    228       const std::pair<float, float>& result = vector_math::EWMAAndMaxPower_SSE(
    229           initial_value_, data_.get(), data_len_, smoothing_factor_);
    230       EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
    231       EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
    232     }
    233 #endif
    234 
    235 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
    236     {
    237       SCOPED_TRACE("EWMAAndMaxPower_NEON");
    238       const std::pair<float, float>& result = vector_math::EWMAAndMaxPower_NEON(
    239           initial_value_, data_.get(), data_len_, smoothing_factor_);
    240       EXPECT_NEAR(expected_final_avg_, result.first, 0.0000001f);
    241       EXPECT_NEAR(expected_max_, result.second, 0.0000001f);
    242     }
    243 #endif
    244   }
    245 
    246  private:
    247   float initial_value_;
    248   scoped_ptr<float, base::AlignedFreeDeleter> data_;
    249   int data_len_;
    250   float smoothing_factor_;
    251   float expected_final_avg_;
    252   float expected_max_;
    253 };
    254 
    255 typedef testing::TestWithParam<EWMATestScenario> VectorMathEWMAAndMaxPowerTest;
    256 
    257 TEST_P(VectorMathEWMAAndMaxPowerTest, Correctness) {
    258   GetParam().RunTest();
    259 }
    260 
    261 static const float kZeros[] = {  // 32 zeros
    262   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    263   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    264 };
    265 
    266 static const float kOnes[] = {  // 32 ones
    267   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    268   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
    269 };
    270 
    271 static const float kCheckerboard[] = {  // 32 alternating 0, 1
    272   0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
    273   0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
    274 };
    275 
    276 static const float kInverseCheckerboard[] = {  // 32 alternating 1, 0
    277   1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
    278   1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
    279 };
    280 
    281 INSTANTIATE_TEST_CASE_P(
    282     Scenarios, VectorMathEWMAAndMaxPowerTest,
    283     ::testing::Values(
    284          // Zero-length input: Result should equal initial value.
    285          EWMATestScenario(0.0f, NULL, 0, 0.0f).HasExpectedResult(0.0f, 0.0f),
    286          EWMATestScenario(1.0f, NULL, 0, 0.0f).HasExpectedResult(1.0f, 0.0f),
    287 
    288          // Smoothing factor of zero: Samples have no effect on result.
    289          EWMATestScenario(0.0f, kOnes, 32, 0.0f).HasExpectedResult(0.0f, 1.0f),
    290          EWMATestScenario(1.0f, kZeros, 32, 0.0f).HasExpectedResult(1.0f, 0.0f),
    291 
    292          // Smothing factor of one: Result = last sample squared.
    293          EWMATestScenario(0.0f, kCheckerboard, 32, 1.0f)
    294              .ScaledBy(2.0f)
    295              .HasExpectedResult(4.0f, 4.0f),
    296          EWMATestScenario(1.0f, kInverseCheckerboard, 32, 1.0f)
    297              .ScaledBy(2.0f)
    298              .HasExpectedResult(0.0f, 4.0f),
    299 
    300          // Smoothing factor of 1/4, muted signal.
    301          EWMATestScenario(1.0f, kZeros, 1, 0.25f)
    302              .HasExpectedResult(powf(0.75, 1.0f), 0.0f),
    303          EWMATestScenario(1.0f, kZeros, 2, 0.25f)
    304              .HasExpectedResult(powf(0.75, 2.0f), 0.0f),
    305          EWMATestScenario(1.0f, kZeros, 3, 0.25f)
    306              .HasExpectedResult(powf(0.75, 3.0f), 0.0f),
    307          EWMATestScenario(1.0f, kZeros, 12, 0.25f)
    308              .HasExpectedResult(powf(0.75, 12.0f), 0.0f),
    309          EWMATestScenario(1.0f, kZeros, 13, 0.25f)
    310              .HasExpectedResult(powf(0.75, 13.0f), 0.0f),
    311          EWMATestScenario(1.0f, kZeros, 14, 0.25f)
    312              .HasExpectedResult(powf(0.75, 14.0f), 0.0f),
    313          EWMATestScenario(1.0f, kZeros, 15, 0.25f)
    314              .HasExpectedResult(powf(0.75, 15.0f), 0.0f),
    315 
    316          // Smoothing factor of 1/4, constant full-amplitude signal.
    317          EWMATestScenario(0.0f, kOnes, 1, 0.25f).HasExpectedResult(0.25f, 1.0f),
    318          EWMATestScenario(0.0f, kOnes, 2, 0.25f)
    319              .HasExpectedResult(0.4375f, 1.0f),
    320          EWMATestScenario(0.0f, kOnes, 3, 0.25f)
    321              .HasExpectedResult(0.578125f, 1.0f),
    322          EWMATestScenario(0.0f, kOnes, 12, 0.25f)
    323              .HasExpectedResult(0.96832365f, 1.0f),
    324          EWMATestScenario(0.0f, kOnes, 13, 0.25f)
    325              .HasExpectedResult(0.97624274f, 1.0f),
    326          EWMATestScenario(0.0f, kOnes, 14, 0.25f)
    327              .HasExpectedResult(0.98218205f, 1.0f),
    328          EWMATestScenario(0.0f, kOnes, 15, 0.25f)
    329              .HasExpectedResult(0.98663654f, 1.0f),
    330 
    331          // Smoothing factor of 1/4, checkerboard signal.
    332          EWMATestScenario(0.0f, kCheckerboard, 1, 0.25f)
    333              .HasExpectedResult(0.0f, 0.0f),
    334          EWMATestScenario(0.0f, kCheckerboard, 2, 0.25f)
    335              .HasExpectedResult(0.25f, 1.0f),
    336          EWMATestScenario(0.0f, kCheckerboard, 3, 0.25f)
    337              .HasExpectedResult(0.1875f, 1.0f),
    338          EWMATestScenario(0.0f, kCheckerboard, 12, 0.25f)
    339              .HasExpectedResult(0.55332780f, 1.0f),
    340          EWMATestScenario(0.0f, kCheckerboard, 13, 0.25f)
    341              .HasExpectedResult(0.41499585f, 1.0f),
    342          EWMATestScenario(0.0f, kCheckerboard, 14, 0.25f)
    343              .HasExpectedResult(0.56124689f, 1.0f),
    344          EWMATestScenario(0.0f, kCheckerboard, 15, 0.25f)
    345              .HasExpectedResult(0.42093517f, 1.0f),
    346 
    347          // Smoothing factor of 1/4, inverse checkerboard signal.
    348          EWMATestScenario(0.0f, kInverseCheckerboard, 1, 0.25f)
    349              .HasExpectedResult(0.25f, 1.0f),
    350          EWMATestScenario(0.0f, kInverseCheckerboard, 2, 0.25f)
    351              .HasExpectedResult(0.1875f, 1.0f),
    352          EWMATestScenario(0.0f, kInverseCheckerboard, 3, 0.25f)
    353              .HasExpectedResult(0.390625f, 1.0f),
    354          EWMATestScenario(0.0f, kInverseCheckerboard, 12, 0.25f)
    355              .HasExpectedResult(0.41499585f, 1.0f),
    356          EWMATestScenario(0.0f, kInverseCheckerboard, 13, 0.25f)
    357              .HasExpectedResult(0.56124689f, 1.0f),
    358          EWMATestScenario(0.0f, kInverseCheckerboard, 14, 0.25f)
    359              .HasExpectedResult(0.42093517f, 1.0f),
    360          EWMATestScenario(0.0f, kInverseCheckerboard, 15, 0.25f)
    361              .HasExpectedResult(0.56570137f, 1.0f),
    362 
    363          // Smoothing factor of 1/4, impluse signal.
    364          EWMATestScenario(0.0f, kZeros, 3, 0.25f)
    365              .WithImpulse(2.0f, 0)
    366              .HasExpectedResult(0.562500f, 4.0f),
    367          EWMATestScenario(0.0f, kZeros, 3, 0.25f)
    368              .WithImpulse(2.0f, 1)
    369              .HasExpectedResult(0.75f, 4.0f),
    370          EWMATestScenario(0.0f, kZeros, 3, 0.25f)
    371              .WithImpulse(2.0f, 2)
    372              .HasExpectedResult(1.0f, 4.0f),
    373          EWMATestScenario(0.0f, kZeros, 32, 0.25f)
    374              .WithImpulse(2.0f, 0)
    375              .HasExpectedResult(0.00013394f, 4.0f),
    376          EWMATestScenario(0.0f, kZeros, 32, 0.25f)
    377              .WithImpulse(2.0f, 1)
    378              .HasExpectedResult(0.00017858f, 4.0f),
    379          EWMATestScenario(0.0f, kZeros, 32, 0.25f)
    380              .WithImpulse(2.0f, 2)
    381              .HasExpectedResult(0.00023811f, 4.0f),
    382          EWMATestScenario(0.0f, kZeros, 32, 0.25f)
    383              .WithImpulse(2.0f, 3)
    384              .HasExpectedResult(0.00031748f, 4.0f)
    385     ));
    386 
    387 }  // namespace media
    388