OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // MSVC++ requires this to be set before any other includes to get M_PI. | 5 // MSVC++ requires this to be set before any other includes to get M_PI. |
6 #define _USE_MATH_DEFINES | 6 #define _USE_MATH_DEFINES |
7 | 7 |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/format_macros.h" | |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 14 #include "base/time.h" |
14 #include "base/stringprintf.h" | |
15 #include "media/base/sinc_resampler.h" | 15 #include "media/base/sinc_resampler.h" |
16 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
17 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
18 | 18 |
19 using testing::_; | 19 using testing::_; |
20 | 20 |
21 namespace media { | 21 namespace media { |
22 | 22 |
23 static const double kSampleRateRatio = 192000.0 / 44100.0; | |
24 static const double kKernelInterpolationFactor = 0.5; | |
25 | |
23 // Helper class to ensure ChunkedResample() functions properly. | 26 // Helper class to ensure ChunkedResample() functions properly. |
24 class MockSource { | 27 class MockSource { |
25 public: | 28 public: |
26 MOCK_METHOD2(ProvideInput, void(float* destination, int frames)); | 29 MOCK_METHOD2(ProvideInput, void(float* destination, int frames)); |
27 }; | 30 }; |
28 | 31 |
29 // Test requesting multiples of ChunkSize() frames results in the proper number | 32 // Test requesting multiples of ChunkSize() frames results in the proper number |
30 // of callbacks. | 33 // of callbacks. |
31 TEST(SincResamplerTest, ChunkedResample) { | 34 TEST(SincResamplerTest, ChunkedResample) { |
32 MockSource mock_source; | 35 MockSource mock_source; |
33 | 36 |
34 // Choose a high ratio of input to output samples which will result in quick | 37 // Choose a high ratio of input to output samples which will result in quick |
35 // exhaustion of SincResampler's internal buffers. | 38 // exhaustion of SincResampler's internal buffers. |
36 static const double kSampleRateRatio = 192000.0 / 44100.0; | |
37 SincResampler resampler( | 39 SincResampler resampler( |
38 kSampleRateRatio, | 40 kSampleRateRatio, |
39 base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); | 41 base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); |
40 | 42 |
41 static const int kChunks = 2; | 43 static const int kChunks = 2; |
42 int max_chunk_size = resampler.ChunkSize() * kChunks; | 44 int max_chunk_size = resampler.ChunkSize() * kChunks; |
43 scoped_array<float> resampled_destination(new float[max_chunk_size]); | 45 scoped_array<float> resampled_destination(new float[max_chunk_size]); |
44 | 46 |
45 // Verify requesting ChunkSize() frames causes a single callback. | 47 // Verify requesting ChunkSize() frames causes a single callback. |
46 EXPECT_CALL(mock_source, ProvideInput(_, _)).Times(1); | 48 EXPECT_CALL(mock_source, ProvideInput(_, _)).Times(1); |
47 resampler.Resample(resampled_destination.get(), resampler.ChunkSize()); | 49 resampler.Resample(resampled_destination.get(), resampler.ChunkSize()); |
48 | 50 |
49 // Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks. | 51 // Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks. |
50 testing::Mock::VerifyAndClear(&mock_source); | 52 testing::Mock::VerifyAndClear(&mock_source); |
51 EXPECT_CALL(mock_source, ProvideInput(_, _)).Times(kChunks); | 53 EXPECT_CALL(mock_source, ProvideInput(_, _)).Times(kChunks); |
52 resampler.Resample(resampled_destination.get(), max_chunk_size); | 54 resampler.Resample(resampled_destination.get(), max_chunk_size); |
53 } | 55 } |
54 | 56 |
57 // Ensure various optimized Convolve() methods return the same value. Only run | |
58 // this test if other optimized methods exist, otherwise the default Convolve() | |
59 // will be tested by the parameterized SincResampler tests below. | |
60 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) | |
61 TEST(SincResamplerTest, Convolve) { | |
62 // Initialize a dummy resampler. | |
63 MockSource mock_source; | |
64 SincResampler resampler( | |
65 kSampleRateRatio, | |
66 base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); | |
67 | |
68 // Convolve_SSE() is slightly more precise than Conolve_C(), so comparison | |
69 // must be done using an epsilon. | |
70 static const double kEpsilon = 0.00000005; | |
71 | |
72 // Use a kernel from SincResampler as input and kernel data, this has the | |
73 // benefit of already being properly sized and aligned for Convolve_SSE(). | |
74 double result = resampler.Convolve_C( | |
75 resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), | |
76 resampler.kernel_storage_.get(), kKernelInterpolationFactor); | |
77 double result2 = resampler.Convolve_SSE( | |
78 resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), | |
79 resampler.kernel_storage_.get(), kKernelInterpolationFactor); | |
80 EXPECT_NEAR(result2, result, kEpsilon); | |
81 | |
82 // Test Convolve_SSE() w/ unaligned input pointer. | |
83 result = resampler.Convolve_C( | |
84 resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(), | |
85 resampler.kernel_storage_.get(), kKernelInterpolationFactor); | |
86 result2 = resampler.Convolve_SSE( | |
87 resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(), | |
88 resampler.kernel_storage_.get(), kKernelInterpolationFactor); | |
89 EXPECT_NEAR(result2, result, kEpsilon); | |
90 } | |
91 #endif | |
92 | |
93 // Benchmark for the various Convolve() methods. | |
Ami GONE FROM CHROMIUM
2012/07/21 17:25:10
Comment that this is only DISABLED_ for the benefi
DaleCurtis
2012/07/24 00:13:07
Done. --convolve-iterations is runtime settable.
| |
94 TEST(SincResamplerTest, DISABLED_ConvolveBenchmark) { | |
95 // Initialize a dummy resampler. | |
96 MockSource mock_source; | |
97 SincResampler resampler( | |
98 kSampleRateRatio, | |
99 base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); | |
100 | |
101 static const int kConvolveIterations = 50000000; | |
102 | |
103 // Benchmark Convolve_C(). | |
104 base::TimeTicks start = base::TimeTicks::HighResNow(); | |
105 for (int i = 0; i < kConvolveIterations; ++i) { | |
106 resampler.Convolve_C( | |
107 resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), | |
108 resampler.kernel_storage_.get(), kKernelInterpolationFactor); | |
109 } | |
110 base::TimeTicks end = base::TimeTicks::HighResNow(); | |
111 printf("Convolve_C took %" PRId64 "ms for %d iterations.\n", | |
112 (end - start).InMilliseconds(), kConvolveIterations); | |
113 | |
114 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) | |
115 // Benchmark Convolve_SSE() with aligned input pointer. | |
116 start = base::TimeTicks::HighResNow(); | |
117 for (int j = 0; j < kConvolveIterations; ++j) { | |
118 resampler.Convolve_SSE( | |
119 resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), | |
120 resampler.kernel_storage_.get(), kKernelInterpolationFactor); | |
121 } | |
122 end = base::TimeTicks::HighResNow(); | |
123 printf("Convolve_SSE (aligned) took %" PRId64 "ms for %d iterations.\n", | |
124 (end - start).InMilliseconds(), kConvolveIterations); | |
125 | |
126 // Benchmark Convolve_SSE() with unaligned input pointer. | |
127 start = base::TimeTicks::HighResNow(); | |
128 for (int j = 0; j < kConvolveIterations; ++j) { | |
129 resampler.Convolve_SSE( | |
130 resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(), | |
131 resampler.kernel_storage_.get(), kKernelInterpolationFactor); | |
132 } | |
133 end = base::TimeTicks::HighResNow(); | |
134 printf("Convolve_SSE (unaligned) took %" PRId64 "ms for %d iterations.\n", | |
135 (end - start).InMilliseconds(), kConvolveIterations); | |
136 #endif | |
Ami GONE FROM CHROMIUM
2012/07/21 17:25:10
Add an output for the relative improvement between
DaleCurtis
2012/07/24 00:13:07
Done.
| |
137 } | |
138 | |
55 // Fake audio source for testing the resampler. Generates a sinusoidal linear | 139 // Fake audio source for testing the resampler. Generates a sinusoidal linear |
56 // chirp (http://en.wikipedia.org/wiki/Chirp) which can be tuned to stress the | 140 // chirp (http://en.wikipedia.org/wiki/Chirp) which can be tuned to stress the |
57 // resampler for the specific sample rate conversion being used. | 141 // resampler for the specific sample rate conversion being used. |
58 class SinusoidalLinearChirpSource { | 142 class SinusoidalLinearChirpSource { |
59 public: | 143 public: |
60 SinusoidalLinearChirpSource(int sample_rate, int samples, | 144 SinusoidalLinearChirpSource(int sample_rate, int samples, |
61 double max_frequency) | 145 double max_frequency) |
62 : sample_rate_(sample_rate), | 146 : sample_rate_(sample_rate), |
63 total_samples_(samples), | 147 total_samples_(samples), |
64 max_frequency_(max_frequency), | 148 max_frequency_(max_frequency), |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
244 std::tr1::make_tuple(11025, 192000, kResamplingRMSError, -62.61), | 328 std::tr1::make_tuple(11025, 192000, kResamplingRMSError, -62.61), |
245 std::tr1::make_tuple(16000, 192000, kResamplingRMSError, -63.14), | 329 std::tr1::make_tuple(16000, 192000, kResamplingRMSError, -63.14), |
246 std::tr1::make_tuple(22050, 192000, kResamplingRMSError, -62.42), | 330 std::tr1::make_tuple(22050, 192000, kResamplingRMSError, -62.42), |
247 std::tr1::make_tuple(32000, 192000, kResamplingRMSError, -63.38), | 331 std::tr1::make_tuple(32000, 192000, kResamplingRMSError, -63.38), |
248 std::tr1::make_tuple(44100, 192000, kResamplingRMSError, -62.63), | 332 std::tr1::make_tuple(44100, 192000, kResamplingRMSError, -62.63), |
249 std::tr1::make_tuple(48000, 192000, kResamplingRMSError, -73.44), | 333 std::tr1::make_tuple(48000, 192000, kResamplingRMSError, -73.44), |
250 std::tr1::make_tuple(96000, 192000, kResamplingRMSError, -73.52), | 334 std::tr1::make_tuple(96000, 192000, kResamplingRMSError, -73.52), |
251 std::tr1::make_tuple(192000, 192000, kResamplingRMSError, -73.52))); | 335 std::tr1::make_tuple(192000, 192000, kResamplingRMSError, -73.52))); |
252 | 336 |
253 } // namespace media | 337 } // namespace media |
OLD | NEW |