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.
5 // MSVC++ requires this to be set before any other includes to get M_PI.
6 #define _USE_MATH_DEFINES
10 #include "base/memory/aligned_memory.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringize_macros.h"
14 #include "media/base/vector_math.h"
15 #include "media/base/vector_math_testing.h"
16 #include "testing/gtest/include/gtest/gtest.h"
22 // Default test values.
23 static const float kScale
= 0.5;
24 static const float kInputFillValue
= 1.0;
25 static const float kOutputFillValue
= 3.0;
26 static const int kVectorSize
= 8192;
28 class VectorMathTest
: public testing::Test
{
32 // Initialize input and output vectors.
33 input_vector_
.reset(static_cast<float*>(base::AlignedAlloc(
34 sizeof(float) * kVectorSize
, vector_math::kRequiredAlignment
)));
35 output_vector_
.reset(static_cast<float*>(base::AlignedAlloc(
36 sizeof(float) * kVectorSize
, vector_math::kRequiredAlignment
)));
39 void FillTestVectors(float input
, float output
) {
40 // Setup input and output vectors.
41 fill(input_vector_
.get(), input_vector_
.get() + kVectorSize
, input
);
42 fill(output_vector_
.get(), output_vector_
.get() + kVectorSize
, output
);
45 void VerifyOutput(float value
) {
46 for (int i
= 0; i
< kVectorSize
; ++i
)
47 ASSERT_FLOAT_EQ(output_vector_
.get()[i
], value
);
51 scoped_ptr_malloc
<float, base::ScopedPtrAlignedFree
> input_vector_
;
52 scoped_ptr_malloc
<float, base::ScopedPtrAlignedFree
> output_vector_
;
54 DISALLOW_COPY_AND_ASSIGN(VectorMathTest
);
57 // Ensure each optimized vector_math::FMAC() method returns the same value.
58 TEST_F(VectorMathTest
, FMAC
) {
59 static const float kResult
= kInputFillValue
* kScale
+ kOutputFillValue
;
63 FillTestVectors(kInputFillValue
, kOutputFillValue
);
65 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
66 VerifyOutput(kResult
);
70 SCOPED_TRACE("FMAC_C");
71 FillTestVectors(kInputFillValue
, kOutputFillValue
);
73 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
74 VerifyOutput(kResult
);
77 #if defined(ARCH_CPU_X86_FAMILY)
79 ASSERT_TRUE(base::CPU().has_sse());
80 SCOPED_TRACE("FMAC_SSE");
81 FillTestVectors(kInputFillValue
, kOutputFillValue
);
82 vector_math::FMAC_SSE(
83 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
84 VerifyOutput(kResult
);
88 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
90 SCOPED_TRACE("FMAC_NEON");
91 FillTestVectors(kInputFillValue
, kOutputFillValue
);
92 vector_math::FMAC_NEON(
93 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
94 VerifyOutput(kResult
);
99 // Ensure each optimized vector_math::FMUL() method returns the same value.
100 TEST_F(VectorMathTest
, FMUL
) {
101 static const float kResult
= kInputFillValue
* kScale
;
104 SCOPED_TRACE("FMUL");
105 FillTestVectors(kInputFillValue
, kOutputFillValue
);
107 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
108 VerifyOutput(kResult
);
112 SCOPED_TRACE("FMUL_C");
113 FillTestVectors(kInputFillValue
, kOutputFillValue
);
115 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
116 VerifyOutput(kResult
);
119 #if defined(ARCH_CPU_X86_FAMILY)
121 ASSERT_TRUE(base::CPU().has_sse());
122 SCOPED_TRACE("FMUL_SSE");
123 FillTestVectors(kInputFillValue
, kOutputFillValue
);
124 vector_math::FMUL_SSE(
125 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
126 VerifyOutput(kResult
);
130 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
132 SCOPED_TRACE("FMUL_NEON");
133 FillTestVectors(kInputFillValue
, kOutputFillValue
);
134 vector_math::FMUL_NEON(
135 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
136 VerifyOutput(kResult
);
143 class EWMATestScenario
{
145 EWMATestScenario(float initial_value
, const float src
[], int len
,
146 float smoothing_factor
)
147 : initial_value_(initial_value
),
148 data_(static_cast<float*>(
150 base::AlignedAlloc(len
* sizeof(float),
151 vector_math::kRequiredAlignment
))),
153 smoothing_factor_(smoothing_factor
),
154 expected_final_avg_(initial_value
),
155 expected_max_(0.0f
) {
157 memcpy(data_
.get(), src
, len
* sizeof(float));
160 // Copy constructor and assignment operator for ::testing::Values(...).
161 EWMATestScenario(const EWMATestScenario
& other
) { *this = other
; }
162 EWMATestScenario
& operator=(const EWMATestScenario
& other
) {
163 this->initial_value_
= other
.initial_value_
;
164 this->smoothing_factor_
= other
.smoothing_factor_
;
165 if (other
.data_len_
== 0) {
168 this->data_
.reset(static_cast<float*>(
169 base::AlignedAlloc(other
.data_len_
* sizeof(float),
170 vector_math::kRequiredAlignment
)));
171 memcpy(this->data_
.get(), other
.data_
.get(),
172 other
.data_len_
* sizeof(float));
174 this->data_len_
= other
.data_len_
;
175 this->expected_final_avg_
= other
.expected_final_avg_
;
176 this->expected_max_
= other
.expected_max_
;
180 EWMATestScenario
ScaledBy(float scale
) const {
181 EWMATestScenario
result(*this);
182 float* p
= result
.data_
.get();
183 float* const p_end
= p
+ result
.data_len_
;
184 for (; p
< p_end
; ++p
)
189 EWMATestScenario
WithImpulse(float value
, int offset
) const {
190 EWMATestScenario
result(*this);
191 result
.data_
.get()[offset
] = value
;
195 EWMATestScenario
HasExpectedResult(float final_avg_value
,
196 float max_value
) const {
197 EWMATestScenario
result(*this);
198 result
.expected_final_avg_
= final_avg_value
;
199 result
.expected_max_
= max_value
;
203 void RunTest() const {
205 SCOPED_TRACE("EWMAAndMaxPower");
206 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower(
207 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
208 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
209 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
213 SCOPED_TRACE("EWMAAndMaxPower_C");
214 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_C(
215 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
216 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
217 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
220 #if defined(ARCH_CPU_X86_FAMILY)
222 ASSERT_TRUE(base::CPU().has_sse());
223 SCOPED_TRACE("EWMAAndMaxPower_SSE");
224 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_SSE(
225 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
226 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
227 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
231 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
233 SCOPED_TRACE("EWMAAndMaxPower_NEON");
234 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_NEON(
235 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
236 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
237 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
243 float initial_value_
;
244 scoped_ptr_malloc
<float, base::ScopedPtrAlignedFree
> data_
;
246 float smoothing_factor_
;
247 float expected_final_avg_
;
253 typedef testing::TestWithParam
<EWMATestScenario
> VectorMathEWMAAndMaxPowerTest
;
255 TEST_P(VectorMathEWMAAndMaxPowerTest
, Correctness
) {
256 GetParam().RunTest();
259 static const float kZeros
[] = { // 32 zeros
260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
261 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
264 static const float kOnes
[] = { // 32 ones
265 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
266 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
269 static const float kCheckerboard
[] = { // 32 alternating 0, 1
270 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
271 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
274 static const float kInverseCheckerboard
[] = { // 32 alternating 1, 0
275 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
276 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
279 INSTANTIATE_TEST_CASE_P(
280 Scenarios
, VectorMathEWMAAndMaxPowerTest
,
282 // Zero-length input: Result should equal initial value.
283 EWMATestScenario(0.0f
, NULL
, 0, 0.0f
).HasExpectedResult(0.0f
, 0.0f
),
284 EWMATestScenario(1.0f
, NULL
, 0, 0.0f
).HasExpectedResult(1.0f
, 0.0f
),
286 // Smoothing factor of zero: Samples have no effect on result.
287 EWMATestScenario(0.0f
, kOnes
, 32, 0.0f
).HasExpectedResult(0.0f
, 1.0f
),
288 EWMATestScenario(1.0f
, kZeros
, 32, 0.0f
).HasExpectedResult(1.0f
, 0.0f
),
290 // Smothing factor of one: Result = last sample squared.
291 EWMATestScenario(0.0f
, kCheckerboard
, 32, 1.0f
)
293 .HasExpectedResult(4.0f
, 4.0f
),
294 EWMATestScenario(1.0f
, kInverseCheckerboard
, 32, 1.0f
)
296 .HasExpectedResult(0.0f
, 4.0f
),
298 // Smoothing factor of 1/4, muted signal.
299 EWMATestScenario(1.0f
, kZeros
, 1, 0.25f
)
300 .HasExpectedResult(powf(0.75, 1.0f
), 0.0f
),
301 EWMATestScenario(1.0f
, kZeros
, 2, 0.25f
)
302 .HasExpectedResult(powf(0.75, 2.0f
), 0.0f
),
303 EWMATestScenario(1.0f
, kZeros
, 3, 0.25f
)
304 .HasExpectedResult(powf(0.75, 3.0f
), 0.0f
),
305 EWMATestScenario(1.0f
, kZeros
, 12, 0.25f
)
306 .HasExpectedResult(powf(0.75, 12.0f
), 0.0f
),
307 EWMATestScenario(1.0f
, kZeros
, 13, 0.25f
)
308 .HasExpectedResult(powf(0.75, 13.0f
), 0.0f
),
309 EWMATestScenario(1.0f
, kZeros
, 14, 0.25f
)
310 .HasExpectedResult(powf(0.75, 14.0f
), 0.0f
),
311 EWMATestScenario(1.0f
, kZeros
, 15, 0.25f
)
312 .HasExpectedResult(powf(0.75, 15.0f
), 0.0f
),
314 // Smoothing factor of 1/4, constant full-amplitude signal.
315 EWMATestScenario(0.0f
, kOnes
, 1, 0.25f
).HasExpectedResult(0.25f
, 1.0f
),
316 EWMATestScenario(0.0f
, kOnes
, 2, 0.25f
)
317 .HasExpectedResult(0.4375f
, 1.0f
),
318 EWMATestScenario(0.0f
, kOnes
, 3, 0.25f
)
319 .HasExpectedResult(0.578125f
, 1.0f
),
320 EWMATestScenario(0.0f
, kOnes
, 12, 0.25f
)
321 .HasExpectedResult(0.96832365f
, 1.0f
),
322 EWMATestScenario(0.0f
, kOnes
, 13, 0.25f
)
323 .HasExpectedResult(0.97624274f
, 1.0f
),
324 EWMATestScenario(0.0f
, kOnes
, 14, 0.25f
)
325 .HasExpectedResult(0.98218205f
, 1.0f
),
326 EWMATestScenario(0.0f
, kOnes
, 15, 0.25f
)
327 .HasExpectedResult(0.98663654f
, 1.0f
),
329 // Smoothing factor of 1/4, checkerboard signal.
330 EWMATestScenario(0.0f
, kCheckerboard
, 1, 0.25f
)
331 .HasExpectedResult(0.0f
, 0.0f
),
332 EWMATestScenario(0.0f
, kCheckerboard
, 2, 0.25f
)
333 .HasExpectedResult(0.25f
, 1.0f
),
334 EWMATestScenario(0.0f
, kCheckerboard
, 3, 0.25f
)
335 .HasExpectedResult(0.1875f
, 1.0f
),
336 EWMATestScenario(0.0f
, kCheckerboard
, 12, 0.25f
)
337 .HasExpectedResult(0.55332780f
, 1.0f
),
338 EWMATestScenario(0.0f
, kCheckerboard
, 13, 0.25f
)
339 .HasExpectedResult(0.41499585f
, 1.0f
),
340 EWMATestScenario(0.0f
, kCheckerboard
, 14, 0.25f
)
341 .HasExpectedResult(0.56124689f
, 1.0f
),
342 EWMATestScenario(0.0f
, kCheckerboard
, 15, 0.25f
)
343 .HasExpectedResult(0.42093517f
, 1.0f
),
345 // Smoothing factor of 1/4, inverse checkerboard signal.
346 EWMATestScenario(0.0f
, kInverseCheckerboard
, 1, 0.25f
)
347 .HasExpectedResult(0.25f
, 1.0f
),
348 EWMATestScenario(0.0f
, kInverseCheckerboard
, 2, 0.25f
)
349 .HasExpectedResult(0.1875f
, 1.0f
),
350 EWMATestScenario(0.0f
, kInverseCheckerboard
, 3, 0.25f
)
351 .HasExpectedResult(0.390625f
, 1.0f
),
352 EWMATestScenario(0.0f
, kInverseCheckerboard
, 12, 0.25f
)
353 .HasExpectedResult(0.41499585f
, 1.0f
),
354 EWMATestScenario(0.0f
, kInverseCheckerboard
, 13, 0.25f
)
355 .HasExpectedResult(0.56124689f
, 1.0f
),
356 EWMATestScenario(0.0f
, kInverseCheckerboard
, 14, 0.25f
)
357 .HasExpectedResult(0.42093517f
, 1.0f
),
358 EWMATestScenario(0.0f
, kInverseCheckerboard
, 15, 0.25f
)
359 .HasExpectedResult(0.56570137f
, 1.0f
),
361 // Smoothing factor of 1/4, impluse signal.
362 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
363 .WithImpulse(2.0f
, 0)
364 .HasExpectedResult(0.562500f
, 4.0f
),
365 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
366 .WithImpulse(2.0f
, 1)
367 .HasExpectedResult(0.75f
, 4.0f
),
368 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
369 .WithImpulse(2.0f
, 2)
370 .HasExpectedResult(1.0f
, 4.0f
),
371 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
372 .WithImpulse(2.0f
, 0)
373 .HasExpectedResult(0.00013394f
, 4.0f
),
374 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
375 .WithImpulse(2.0f
, 1)
376 .HasExpectedResult(0.00017858f
, 4.0f
),
377 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
378 .WithImpulse(2.0f
, 2)
379 .HasExpectedResult(0.00023811f
, 4.0f
),
380 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
381 .WithImpulse(2.0f
, 3)
382 .HasExpectedResult(0.00031748f
, 4.0f
)