Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(662)

Side by Side Diff: media/base/audio_discard_helper_unittest.cc

Issue 259453003: Introduce AudioDiscardHelper. Refactor audio decoders to use it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix x64 type. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/base/audio_discard_helper.cc ('k') | media/base/test_helpers.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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 #include "base/memory/scoped_ptr.h"
6 #include "media/base/audio_buffer.h"
7 #include "media/base/audio_bus.h"
8 #include "media/base/audio_discard_helper.h"
9 #include "media/base/buffers.h"
10 #include "media/base/decoder_buffer.h"
11 #include "media/base/test_helpers.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace media {
15
16 static const float kDataStep = 0.01f;
17 static const size_t kSampleRate = 48000;
18
19 static scoped_refptr<DecoderBuffer> CreateEncodedBuffer(
20 base::TimeDelta timestamp,
21 base::TimeDelta duration) {
22 scoped_refptr<DecoderBuffer> result(new DecoderBuffer(1));
23 result->set_timestamp(timestamp);
24 result->set_duration(duration);
25 return result;
26 }
27
28 static scoped_refptr<AudioBuffer> CreateDecodedBuffer(int frames) {
29 return MakeAudioBuffer(kSampleFormatPlanarF32,
30 CHANNEL_LAYOUT_MONO,
31 1,
32 kSampleRate,
33 0.0f,
34 kDataStep,
35 frames,
36 kNoTimestamp(),
37 kNoTimestamp());
38 }
39
40 static float ExtractDecodedData(const scoped_refptr<AudioBuffer>& buffer,
41 int index) {
42 // This is really inefficient, but we can't access the raw AudioBuffer if any
43 // start trimming has been applied.
44 scoped_ptr<AudioBus> temp_bus = AudioBus::Create(buffer->channel_count(), 1);
45 buffer->ReadFrames(1, index, 0, temp_bus.get());
46 return temp_bus->channel(0)[0];
47 }
48
49 TEST(AudioDiscardHelperTest, TimeDeltaToFrames) {
50 AudioDiscardHelper discard_helper(kSampleRate);
51
52 EXPECT_EQ(0u, discard_helper.TimeDeltaToFrames(base::TimeDelta()));
53 EXPECT_EQ(
54 kSampleRate / 100,
55 discard_helper.TimeDeltaToFrames(base::TimeDelta::FromMilliseconds(10)));
56
57 // Ensure partial frames are rounded down correctly. The equation below
58 // calculates a frame count with a fractional part < 0.5.
59 const int small_remainder =
60 base::Time::kMicrosecondsPerSecond * (kSampleRate - 0.9) / kSampleRate;
61 EXPECT_EQ(kSampleRate - 1,
62 discard_helper.TimeDeltaToFrames(
63 base::TimeDelta::FromMicroseconds(small_remainder)));
64
65 // Ditto, but rounded up using a fractional part > 0.5.
66 const int large_remainder =
67 base::Time::kMicrosecondsPerSecond * (kSampleRate - 0.4) / kSampleRate;
68 EXPECT_EQ(kSampleRate,
69 discard_helper.TimeDeltaToFrames(
70 base::TimeDelta::FromMicroseconds(large_remainder)));
71 }
72
73 TEST(AudioDiscardHelperTest, BasicProcessBuffers) {
74 AudioDiscardHelper discard_helper(kSampleRate);
75 ASSERT_FALSE(discard_helper.initialized());
76
77 const base::TimeDelta kTimestamp = base::TimeDelta();
78
79 // Use an estimated duration which doesn't match the number of decoded frames
80 // to ensure the helper is correctly setting durations based on output frames.
81 const base::TimeDelta kEstimatedDuration =
82 base::TimeDelta::FromMilliseconds(9);
83 const base::TimeDelta kActualDuration = base::TimeDelta::FromMilliseconds(10);
84 const int kTestFrames = discard_helper.TimeDeltaToFrames(kActualDuration);
85
86 scoped_refptr<DecoderBuffer> encoded_buffer =
87 CreateEncodedBuffer(kTimestamp, kEstimatedDuration);
88 scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
89
90 // Verify the basic case where nothing is discarded.
91 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
92 ASSERT_TRUE(discard_helper.initialized());
93 EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
94 EXPECT_EQ(kActualDuration, decoded_buffer->duration());
95 EXPECT_EQ(kTestFrames, decoded_buffer->frame_count());
96
97 // Verify a Reset() takes us back to an uninitialized state.
98 discard_helper.Reset(0);
99 ASSERT_FALSE(discard_helper.initialized());
100
101 // Verify a NULL output buffer returns false.
102 ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, NULL));
103 }
104
105 TEST(AudioDiscardHelperTest, NegativeTimestampClampsToZero) {
106 AudioDiscardHelper discard_helper(kSampleRate);
107 ASSERT_FALSE(discard_helper.initialized());
108
109 const base::TimeDelta kTimestamp = -base::TimeDelta::FromSeconds(1);
110 const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10);
111 const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration);
112
113 scoped_refptr<DecoderBuffer> encoded_buffer =
114 CreateEncodedBuffer(kTimestamp, kDuration);
115 scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
116
117 // Verify the basic case where nothing is discarded.
118 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
119 ASSERT_TRUE(discard_helper.initialized());
120 EXPECT_EQ(base::TimeDelta(), decoded_buffer->timestamp());
121 EXPECT_EQ(kDuration, decoded_buffer->duration());
122 EXPECT_EQ(kTestFrames, decoded_buffer->frame_count());
123 }
124
125 TEST(AudioDiscardHelperTest, ProcessBuffersWithInitialDiscard) {
126 AudioDiscardHelper discard_helper(kSampleRate);
127 ASSERT_FALSE(discard_helper.initialized());
128
129 const base::TimeDelta kTimestamp = base::TimeDelta();
130 const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10);
131 const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration);
132
133 // Tell the helper we want to discard half of the initial frames.
134 const int kDiscardFrames = kTestFrames / 2;
135 discard_helper.Reset(kDiscardFrames);
136
137 scoped_refptr<DecoderBuffer> encoded_buffer =
138 CreateEncodedBuffer(kTimestamp, kDuration);
139 scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
140
141 // Verify half the frames end up discarded.
142 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
143 ASSERT_TRUE(discard_helper.initialized());
144 EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
145 EXPECT_EQ(kDuration / 2, decoded_buffer->duration());
146 EXPECT_EQ(kDiscardFrames, decoded_buffer->frame_count());
147 ASSERT_FLOAT_EQ(kDiscardFrames * kDataStep,
148 ExtractDecodedData(decoded_buffer, 0));
149 }
150
151 TEST(AudioDiscardHelperTest, ProcessBuffersWithLargeInitialDiscard) {
152 AudioDiscardHelper discard_helper(kSampleRate);
153 ASSERT_FALSE(discard_helper.initialized());
154
155 const base::TimeDelta kTimestamp = base::TimeDelta();
156 const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10);
157 const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration);
158
159 // Tell the helper we want to discard 1.5 buffers worth of frames.
160 discard_helper.Reset(kTestFrames * 1.5);
161
162 scoped_refptr<DecoderBuffer> encoded_buffer =
163 CreateEncodedBuffer(kTimestamp, kDuration);
164 scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
165
166 // The first call should fail since no output buffer remains.
167 ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
168 ASSERT_TRUE(discard_helper.initialized());
169
170 // Generate another set of buffers and expect half the output frames.
171 encoded_buffer = CreateEncodedBuffer(kTimestamp + kDuration, kDuration);
172 decoded_buffer = CreateDecodedBuffer(kTestFrames);
173 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
174
175 // The timestamp should match that of the initial buffer.
176 const int kDiscardFrames = kTestFrames / 2;
177 EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
178 EXPECT_EQ(kDuration / 2, decoded_buffer->duration());
179 EXPECT_EQ(kDiscardFrames, decoded_buffer->frame_count());
180 ASSERT_FLOAT_EQ(kDiscardFrames * kDataStep,
181 ExtractDecodedData(decoded_buffer, 0));
182 }
183
184 TEST(AudioDiscardHelperTest, AllowNonMonotonicTimestamps) {
185 AudioDiscardHelper discard_helper(kSampleRate);
186 ASSERT_FALSE(discard_helper.initialized());
187
188 const base::TimeDelta kTimestamp = base::TimeDelta();
189 const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10);
190 const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration);
191
192 scoped_refptr<DecoderBuffer> encoded_buffer =
193 CreateEncodedBuffer(kTimestamp, kDuration);
194 scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
195
196 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
197 ASSERT_TRUE(discard_helper.initialized());
198 EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
199 EXPECT_EQ(kDuration, decoded_buffer->duration());
200 EXPECT_EQ(kTestFrames, decoded_buffer->frame_count());
201
202 // Process the same input buffer again to ensure input timestamps which go
203 // backwards in time are not errors.
204 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
205 EXPECT_EQ(kTimestamp + kDuration, decoded_buffer->timestamp());
206 EXPECT_EQ(kDuration, decoded_buffer->duration());
207 EXPECT_EQ(kTestFrames, decoded_buffer->frame_count());
208 }
209
210 TEST(AudioDiscardHelperTest, DiscardPadding) {
211 AudioDiscardHelper discard_helper(kSampleRate);
212 ASSERT_FALSE(discard_helper.initialized());
213
214 const base::TimeDelta kTimestamp = base::TimeDelta();
215 const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10);
216 const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration);
217
218 scoped_refptr<DecoderBuffer> encoded_buffer =
219 CreateEncodedBuffer(kTimestamp, kDuration);
220 scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
221
222 // Set a discard padding equivalent to half the buffer.
223 encoded_buffer->set_discard_padding(kDuration / 2);
224
225 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
226 ASSERT_TRUE(discard_helper.initialized());
227 EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
228 EXPECT_EQ(kDuration / 2, decoded_buffer->duration());
229 EXPECT_EQ(kTestFrames / 2, decoded_buffer->frame_count());
230 ASSERT_FLOAT_EQ(0, ExtractDecodedData(decoded_buffer, 0));
231 }
232
233 TEST(AudioDiscardHelperTest, InitialDiscardAndDiscardPadding) {
234 AudioDiscardHelper discard_helper(kSampleRate);
235 ASSERT_FALSE(discard_helper.initialized());
236
237 const base::TimeDelta kTimestamp = base::TimeDelta();
238 const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10);
239 const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration);
240
241 scoped_refptr<DecoderBuffer> encoded_buffer =
242 CreateEncodedBuffer(kTimestamp, kDuration);
243 scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
244
245 // Set a discard padding equivalent to a quarter of the buffer.
246 encoded_buffer->set_discard_padding(kDuration / 4);
247
248 // Set an initial discard of a quarter of the buffer.
249 const int kDiscardFrames = kTestFrames / 4;
250 discard_helper.Reset(kDiscardFrames);
251
252 ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
253 ASSERT_TRUE(discard_helper.initialized());
254 EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
255 EXPECT_EQ(kDuration / 2, decoded_buffer->duration());
256 EXPECT_EQ(kTestFrames / 2, decoded_buffer->frame_count());
257 ASSERT_FLOAT_EQ(kDiscardFrames * kDataStep,
258 ExtractDecodedData(decoded_buffer, 0));
259 }
260
261 } // namespace media
OLDNEW
« no previous file with comments | « media/base/audio_discard_helper.cc ('k') | media/base/test_helpers.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698