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 #include "media/base/audio_bus.h" | 5 #include "media/base/audio_bus.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/numerics/safe_conversions.h" | 14 #include "base/numerics/safe_conversions.h" |
15 #include "media/base/audio_parameters.h" | 15 #include "media/base/audio_parameters.h" |
16 #include "media/base/audio_sample_types.h" | |
16 #include "media/base/limits.h" | 17 #include "media/base/limits.h" |
17 #include "media/base/vector_math.h" | 18 #include "media/base/vector_math.h" |
18 | 19 |
19 namespace media { | 20 namespace media { |
20 | 21 |
21 static const uint8_t kUint8Bias = 128; | |
22 | |
23 static bool IsAligned(void* ptr) { | 22 static bool IsAligned(void* ptr) { |
24 return (reinterpret_cast<uintptr_t>(ptr) & | 23 return (reinterpret_cast<uintptr_t>(ptr) & |
25 (AudioBus::kChannelAlignment - 1)) == 0U; | 24 (AudioBus::kChannelAlignment - 1)) == 0U; |
26 } | 25 } |
27 | 26 |
28 // Calculates the required size for an AudioBus with the given params, sets | 27 // In order to guarantee that the memory block for each channel starts at an |
29 // |aligned_frames| to the actual frame length of each channel array. | 28 // aligned address when splitting a contiguous block of memory into one block |
30 static int CalculateMemorySizeInternal(int channels, int frames, | 29 // per channel, we may have to make these blocks larger than otherwise needed. |
30 // We do this by allocating space for potentially more frames than requested. | |
31 // This method returns the required size for the contiguous memory block | |
32 // in bytes and outputs the adjusted number of frames via |out_aligned_frames|. | |
33 static int CalculateMemorySizeInternal(int channels, | |
34 int frames, | |
31 int* out_aligned_frames) { | 35 int* out_aligned_frames) { |
32 // Choose a size such that each channel will be aligned by | 36 // Since our internal sample format is float, we can guarantee the alignment |
33 // kChannelAlignment when stored in a contiguous block. | 37 // by making the number of frames an integer multiple of |
38 // AudioBus::kChannelAlignment / sizeof(float). | |
34 int aligned_frames = | 39 int aligned_frames = |
35 ((frames * sizeof(float) + AudioBus::kChannelAlignment - 1) & | 40 ((frames * sizeof(float) + AudioBus::kChannelAlignment - 1) & |
36 ~(AudioBus::kChannelAlignment - 1)) / sizeof(float); | 41 ~(AudioBus::kChannelAlignment - 1)) / sizeof(float); |
37 | 42 |
38 if (out_aligned_frames) | 43 if (out_aligned_frames) |
39 *out_aligned_frames = aligned_frames; | 44 *out_aligned_frames = aligned_frames; |
40 | 45 |
41 return sizeof(float) * channels * aligned_frames; | 46 return sizeof(float) * channels * aligned_frames; |
42 } | 47 } |
43 | 48 |
44 // |Format| is the destination type. If a bias is present, |Fixed| must be a | |
45 // type larger than |Format| such that operations can be made without | |
46 // overflowing. Without a bias |Fixed| must be the same as |Format|. | |
47 template<class Format, class Fixed, Format Bias> | |
48 static void FromInterleavedInternal(const void* src, int start_frame, | |
49 int frames, AudioBus* dest, | |
50 float min, float max) { | |
51 static_assert((Bias == 0 && sizeof(Fixed) == sizeof(Format)) || | |
52 sizeof(Fixed) > sizeof(Format), "invalid deinterleave types"); | |
53 const Format* source = static_cast<const Format*>(src); | |
54 const int channels = dest->channels(); | |
55 for (int ch = 0; ch < channels; ++ch) { | |
56 float* channel_data = dest->channel(ch); | |
57 for (int i = start_frame, offset = ch; i < start_frame + frames; | |
58 ++i, offset += channels) { | |
59 const Fixed v = static_cast<Fixed>(source[offset]) - Bias; | |
60 channel_data[i] = v * (v < 0 ? -min : max); | |
61 } | |
62 } | |
63 } | |
64 | |
65 // |Format| is the destination type. If a bias is present, |Fixed| must be a | |
66 // type larger than |Format| such that operations can be made without | |
67 // overflowing. Without a bias |Fixed| must be the same as |Format|. | |
68 template<class Format, class Fixed, Format Bias> | |
69 static void ToInterleavedInternal(const AudioBus* source, int start_frame, | |
70 int frames, void* dst, Fixed min, Fixed max) { | |
71 static_assert((Bias == 0 && sizeof(Fixed) == sizeof(Format)) || | |
72 sizeof(Fixed) > sizeof(Format), "invalid interleave types"); | |
73 Format* dest = static_cast<Format*>(dst); | |
74 const int channels = source->channels(); | |
75 for (int ch = 0; ch < channels; ++ch) { | |
76 const float* channel_data = source->channel(ch); | |
77 for (int i = start_frame, offset = ch; i < start_frame + frames; | |
78 ++i, offset += channels) { | |
79 const float v = channel_data[i]; | |
80 | |
81 Fixed sample; | |
82 if (v < 0) | |
83 sample = v <= -1 ? min : static_cast<Fixed>(-v * min); | |
84 else | |
85 sample = v >= 1 ? max : static_cast<Fixed>(v * max); | |
86 | |
87 dest[offset] = static_cast<Format>(sample) + Bias; | |
88 } | |
89 } | |
90 } | |
91 | |
92 static void ValidateConfig(int channels, int frames) { | 49 static void ValidateConfig(int channels, int frames) { |
93 CHECK_GT(frames, 0); | 50 CHECK_GT(frames, 0); |
94 CHECK_GT(channels, 0); | 51 CHECK_GT(channels, 0); |
95 CHECK_LE(channels, static_cast<int>(limits::kMaxChannels)); | 52 CHECK_LE(channels, static_cast<int>(limits::kMaxChannels)); |
96 } | 53 } |
97 | 54 |
98 static void CheckOverflow(int start_frame, int frames, int total_frames) { | 55 void AudioBus::CheckOverflow(int start_frame, int frames, int total_frames) { |
mcasas
2016/06/12 09:41:47
This doesn't need to be a member right?
(Uses not
chfremer
2016/06/13 17:44:11
I made this a member, because it called from a now
| |
99 CHECK_GE(start_frame, 0); | 56 CHECK_GE(start_frame, 0); |
100 CHECK_GE(frames, 0); | 57 CHECK_GE(frames, 0); |
101 CHECK_GT(total_frames, 0); | 58 CHECK_GT(total_frames, 0); |
102 int sum = start_frame + frames; | 59 int sum = start_frame + frames; |
103 CHECK_LE(sum, total_frames); | 60 CHECK_LE(sum, total_frames); |
104 CHECK_GE(sum, 0); | 61 CHECK_GE(sum, 0); |
105 } | 62 } |
106 | 63 |
107 AudioBus::AudioBus(int channels, int frames) | 64 AudioBus::AudioBus(int channels, int frames) |
108 : frames_(frames), | 65 : frames_(frames), |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
241 params.channels(), params.frames_per_buffer(), NULL); | 198 params.channels(), params.frames_per_buffer(), NULL); |
242 } | 199 } |
243 | 200 |
244 int AudioBus::CalculateMemorySize(int channels, int frames) { | 201 int AudioBus::CalculateMemorySize(int channels, int frames) { |
245 return CalculateMemorySizeInternal(channels, frames, NULL); | 202 return CalculateMemorySizeInternal(channels, frames, NULL); |
246 } | 203 } |
247 | 204 |
248 void AudioBus::BuildChannelData(int channels, int aligned_frames, float* data) { | 205 void AudioBus::BuildChannelData(int channels, int aligned_frames, float* data) { |
249 DCHECK(IsAligned(data)); | 206 DCHECK(IsAligned(data)); |
250 DCHECK_EQ(channel_data_.size(), 0U); | 207 DCHECK_EQ(channel_data_.size(), 0U); |
251 // Separate audio data out into channels for easy lookup later. Figure out | 208 // Initialize |channel_data_| with pointers into |data|. |
252 channel_data_.reserve(channels); | 209 channel_data_.reserve(channels); |
253 for (int i = 0; i < channels; ++i) | 210 for (int i = 0; i < channels; ++i) |
254 channel_data_.push_back(data + i * aligned_frames); | 211 channel_data_.push_back(data + i * aligned_frames); |
255 } | 212 } |
256 | 213 |
257 // TODO(dalecurtis): See if intrinsic optimizations help any here. | 214 // Forwards to non-deprecated version. |
258 void AudioBus::FromInterleavedPartial(const void* source, int start_frame, | 215 void AudioBus::FromInterleaved(const void* source, |
259 int frames, int bytes_per_sample) { | 216 int frames, |
260 CheckOverflow(start_frame, frames, frames_); | 217 int bytes_per_sample) { |
261 switch (bytes_per_sample) { | 218 switch (bytes_per_sample) { |
262 case 1: | 219 case 1: |
263 FromInterleavedInternal<uint8_t, int16_t, kUint8Bias>( | 220 FromInterleaved<UnsignedInt8SampleTypeTraits>( |
264 source, start_frame, frames, this, | 221 reinterpret_cast<const uint8_t*>(source), frames); |
265 1.0f / std::numeric_limits<int8_t>::min(), | |
266 1.0f / std::numeric_limits<int8_t>::max()); | |
267 break; | 222 break; |
268 case 2: | 223 case 2: |
269 FromInterleavedInternal<int16_t, int16_t, 0>( | 224 FromInterleaved<SignedInt16SampleTypeTraits>( |
270 source, start_frame, frames, this, | 225 reinterpret_cast<const int16_t*>(source), frames); |
271 1.0f / std::numeric_limits<int16_t>::min(), | |
272 1.0f / std::numeric_limits<int16_t>::max()); | |
273 break; | 226 break; |
274 case 4: | 227 case 4: |
275 FromInterleavedInternal<int32_t, int32_t, 0>( | 228 FromInterleaved<SignedInt32SampleTypeTraits>( |
276 source, start_frame, frames, this, | 229 reinterpret_cast<const int32_t*>(source), frames); |
277 1.0f / std::numeric_limits<int32_t>::min(), | 230 break; |
278 1.0f / std::numeric_limits<int32_t>::max()); | 231 default: |
232 NOTREACHED() << "Unsupported bytes per sample encountered."; | |
mcasas
2016/06/12 09:41:47
nit:
... encountered: " << bytes_per_sample;
chfremer
2016/06/13 17:44:11
Done.
| |
233 ZeroFrames(frames); | |
234 } | |
235 } | |
236 | |
237 // Forwards to non-deprecated version. | |
238 void AudioBus::FromInterleavedPartial(const void* source, | |
239 int start_frame, | |
240 int frames, | |
241 int bytes_per_sample) { | |
242 switch (bytes_per_sample) { | |
243 case 1: | |
244 FromInterleavedPartial<UnsignedInt8SampleTypeTraits>( | |
245 reinterpret_cast<const uint8_t*>(source), start_frame, frames); | |
246 break; | |
247 case 2: | |
248 FromInterleavedPartial<SignedInt16SampleTypeTraits>( | |
249 reinterpret_cast<const int16_t*>(source), start_frame, frames); | |
250 break; | |
251 case 4: | |
252 FromInterleavedPartial<SignedInt32SampleTypeTraits>( | |
253 reinterpret_cast<const int32_t*>(source), start_frame, frames); | |
279 break; | 254 break; |
280 default: | 255 default: |
281 NOTREACHED() << "Unsupported bytes per sample encountered."; | 256 NOTREACHED() << "Unsupported bytes per sample encountered."; |
mcasas
2016/06/12 09:41:48
idem nit
chfremer
2016/06/13 17:44:11
Done.
| |
282 ZeroFramesPartial(start_frame, frames); | 257 ZeroFramesPartial(start_frame, frames); |
283 return; | |
284 } | |
285 | |
286 // Don't clear remaining frames if this is a partial deinterleave. | |
287 if (!start_frame) { | |
288 // Zero any remaining frames. | |
289 ZeroFramesPartial(frames, frames_ - frames); | |
290 } | 258 } |
291 } | 259 } |
292 | 260 |
293 void AudioBus::FromInterleaved(const void* source, int frames, | 261 // Forwards to non-deprecated version. |
294 int bytes_per_sample) { | 262 void AudioBus::ToInterleaved(int frames, |
295 FromInterleavedPartial(source, 0, frames, bytes_per_sample); | 263 int bytes_per_sample, |
296 } | |
297 | |
298 void AudioBus::ToInterleaved(int frames, int bytes_per_sample, | |
299 void* dest) const { | 264 void* dest) const { |
300 ToInterleavedPartial(0, frames, bytes_per_sample, dest); | |
301 } | |
302 | |
303 // TODO(dalecurtis): See if intrinsic optimizations help any here. | |
304 void AudioBus::ToInterleavedPartial(int start_frame, int frames, | |
305 int bytes_per_sample, void* dest) const { | |
306 CheckOverflow(start_frame, frames, frames_); | |
307 switch (bytes_per_sample) { | 265 switch (bytes_per_sample) { |
308 case 1: | 266 case 1: |
309 ToInterleavedInternal<uint8_t, int16_t, kUint8Bias>( | 267 ToInterleaved<UnsignedInt8SampleTypeTraits>( |
310 this, start_frame, frames, dest, std::numeric_limits<int8_t>::min(), | 268 frames, reinterpret_cast<uint8_t*>(dest)); |
311 std::numeric_limits<int8_t>::max()); | |
312 break; | 269 break; |
313 case 2: | 270 case 2: |
314 ToInterleavedInternal<int16_t, int16_t, 0>( | 271 ToInterleaved<SignedInt16SampleTypeTraits>( |
315 this, start_frame, frames, dest, std::numeric_limits<int16_t>::min(), | 272 frames, reinterpret_cast<int16_t*>(dest)); |
316 std::numeric_limits<int16_t>::max()); | |
317 break; | 273 break; |
318 case 4: | 274 case 4: |
319 ToInterleavedInternal<int32_t, int32_t, 0>( | 275 ToInterleaved<SignedInt32SampleTypeTraits>( |
320 this, start_frame, frames, dest, std::numeric_limits<int32_t>::min(), | 276 frames, reinterpret_cast<int32_t*>(dest)); |
321 std::numeric_limits<int32_t>::max()); | |
322 break; | 277 break; |
323 default: | 278 default: |
324 NOTREACHED() << "Unsupported bytes per sample encountered."; | 279 NOTREACHED() << "Unsupported bytes per sample encountered."; |
325 memset(dest, 0, frames * bytes_per_sample); | |
326 return; | |
327 } | 280 } |
328 } | 281 } |
329 | 282 |
283 // Forwards to non-deprecated version. | |
284 void AudioBus::ToInterleavedPartial(int start_frame, | |
285 int frames, | |
286 int bytes_per_sample, | |
287 void* dest) const { | |
288 switch (bytes_per_sample) { | |
289 case 1: | |
290 ToInterleavedPartial<UnsignedInt8SampleTypeTraits>( | |
291 start_frame, frames, reinterpret_cast<uint8_t*>(dest)); | |
292 break; | |
293 case 2: | |
294 ToInterleavedPartial<SignedInt16SampleTypeTraits>( | |
295 start_frame, frames, reinterpret_cast<int16_t*>(dest)); | |
296 break; | |
297 case 4: | |
298 ToInterleavedPartial<SignedInt32SampleTypeTraits>( | |
299 start_frame, frames, reinterpret_cast<int32_t*>(dest)); | |
300 break; | |
301 default: | |
302 NOTREACHED() << "Unsupported bytes per sample encountered."; | |
303 } | |
304 } | |
305 | |
330 void AudioBus::CopyTo(AudioBus* dest) const { | 306 void AudioBus::CopyTo(AudioBus* dest) const { |
331 CopyPartialFramesTo(0, frames(), 0, dest); | 307 CopyPartialFramesTo(0, frames(), 0, dest); |
332 } | 308 } |
333 | 309 |
334 void AudioBus::CopyPartialFramesTo(int source_start_frame, | 310 void AudioBus::CopyPartialFramesTo(int source_start_frame, |
335 int frame_count, | 311 int frame_count, |
336 int dest_start_frame, | 312 int dest_start_frame, |
337 AudioBus* dest) const { | 313 AudioBus* dest) const { |
338 CHECK_EQ(channels(), dest->channels()); | 314 CHECK_EQ(channels(), dest->channels()); |
339 CHECK_LE(source_start_frame + frame_count, frames()); | 315 CHECK_LE(source_start_frame + frame_count, frames()); |
(...skipping 29 matching lines...) Expand all Loading... | |
369 return scoped_refptr<AudioBusRefCounted>( | 345 return scoped_refptr<AudioBusRefCounted>( |
370 new AudioBusRefCounted(channels, frames)); | 346 new AudioBusRefCounted(channels, frames)); |
371 } | 347 } |
372 | 348 |
373 AudioBusRefCounted::AudioBusRefCounted(int channels, int frames) | 349 AudioBusRefCounted::AudioBusRefCounted(int channels, int frames) |
374 : AudioBus(channels, frames) {} | 350 : AudioBus(channels, frames) {} |
375 | 351 |
376 AudioBusRefCounted::~AudioBusRefCounted() {} | 352 AudioBusRefCounted::~AudioBusRefCounted() {} |
377 | 353 |
378 } // namespace media | 354 } // namespace media |
OLD | NEW |