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) { |
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(), | |
278 1.0f / std::numeric_limits<int32_t>::max()); | |
279 break; | 230 break; |
280 default: | 231 default: |
281 NOTREACHED() << "Unsupported bytes per sample encountered."; | 232 NOTREACHED() << "Unsupported bytes per sample encountered: " |
282 ZeroFramesPartial(start_frame, frames); | 233 << bytes_per_sample; |
283 return; | 234 ZeroFrames(frames); |
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 } | 235 } |
291 } | 236 } |
292 | 237 |
293 void AudioBus::FromInterleaved(const void* source, int frames, | 238 // Forwards to non-deprecated version. |
294 int bytes_per_sample) { | 239 void AudioBus::FromInterleavedPartial(const void* source, |
295 FromInterleavedPartial(source, 0, frames, bytes_per_sample); | 240 int start_frame, |
296 } | 241 int frames, |
297 | 242 int bytes_per_sample) { |
298 void AudioBus::ToInterleaved(int frames, int bytes_per_sample, | |
299 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) { | 243 switch (bytes_per_sample) { |
308 case 1: | 244 case 1: |
309 ToInterleavedInternal<uint8_t, int16_t, kUint8Bias>( | 245 FromInterleavedPartial<UnsignedInt8SampleTypeTraits>( |
310 this, start_frame, frames, dest, std::numeric_limits<int8_t>::min(), | 246 reinterpret_cast<const uint8_t*>(source), start_frame, frames); |
311 std::numeric_limits<int8_t>::max()); | |
312 break; | 247 break; |
313 case 2: | 248 case 2: |
314 ToInterleavedInternal<int16_t, int16_t, 0>( | 249 FromInterleavedPartial<SignedInt16SampleTypeTraits>( |
315 this, start_frame, frames, dest, std::numeric_limits<int16_t>::min(), | 250 reinterpret_cast<const int16_t*>(source), start_frame, frames); |
316 std::numeric_limits<int16_t>::max()); | |
317 break; | 251 break; |
318 case 4: | 252 case 4: |
319 ToInterleavedInternal<int32_t, int32_t, 0>( | 253 FromInterleavedPartial<SignedInt32SampleTypeTraits>( |
320 this, start_frame, frames, dest, std::numeric_limits<int32_t>::min(), | 254 reinterpret_cast<const int32_t*>(source), start_frame, frames); |
321 std::numeric_limits<int32_t>::max()); | |
322 break; | 255 break; |
323 default: | 256 default: |
324 NOTREACHED() << "Unsupported bytes per sample encountered."; | 257 NOTREACHED() << "Unsupported bytes per sample encountered: " |
325 memset(dest, 0, frames * bytes_per_sample); | 258 << bytes_per_sample; |
326 return; | 259 ZeroFramesPartial(start_frame, frames); |
327 } | 260 } |
328 } | 261 } |
329 | 262 |
| 263 // Forwards to non-deprecated version. |
| 264 void AudioBus::ToInterleaved(int frames, |
| 265 int bytes_per_sample, |
| 266 void* dest) const { |
| 267 switch (bytes_per_sample) { |
| 268 case 1: |
| 269 ToInterleaved<UnsignedInt8SampleTypeTraits>( |
| 270 frames, reinterpret_cast<uint8_t*>(dest)); |
| 271 break; |
| 272 case 2: |
| 273 ToInterleaved<SignedInt16SampleTypeTraits>( |
| 274 frames, reinterpret_cast<int16_t*>(dest)); |
| 275 break; |
| 276 case 4: |
| 277 ToInterleaved<SignedInt32SampleTypeTraits>( |
| 278 frames, reinterpret_cast<int32_t*>(dest)); |
| 279 break; |
| 280 default: |
| 281 NOTREACHED() << "Unsupported bytes per sample encountered: " |
| 282 << bytes_per_sample; |
| 283 } |
| 284 } |
| 285 |
| 286 // Forwards to non-deprecated version. |
| 287 void AudioBus::ToInterleavedPartial(int start_frame, |
| 288 int frames, |
| 289 int bytes_per_sample, |
| 290 void* dest) const { |
| 291 switch (bytes_per_sample) { |
| 292 case 1: |
| 293 ToInterleavedPartial<UnsignedInt8SampleTypeTraits>( |
| 294 start_frame, frames, reinterpret_cast<uint8_t*>(dest)); |
| 295 break; |
| 296 case 2: |
| 297 ToInterleavedPartial<SignedInt16SampleTypeTraits>( |
| 298 start_frame, frames, reinterpret_cast<int16_t*>(dest)); |
| 299 break; |
| 300 case 4: |
| 301 ToInterleavedPartial<SignedInt32SampleTypeTraits>( |
| 302 start_frame, frames, reinterpret_cast<int32_t*>(dest)); |
| 303 break; |
| 304 default: |
| 305 NOTREACHED() << "Unsupported bytes per sample encountered: " |
| 306 << bytes_per_sample; |
| 307 } |
| 308 } |
| 309 |
330 void AudioBus::CopyTo(AudioBus* dest) const { | 310 void AudioBus::CopyTo(AudioBus* dest) const { |
331 CopyPartialFramesTo(0, frames(), 0, dest); | 311 CopyPartialFramesTo(0, frames(), 0, dest); |
332 } | 312 } |
333 | 313 |
334 void AudioBus::CopyPartialFramesTo(int source_start_frame, | 314 void AudioBus::CopyPartialFramesTo(int source_start_frame, |
335 int frame_count, | 315 int frame_count, |
336 int dest_start_frame, | 316 int dest_start_frame, |
337 AudioBus* dest) const { | 317 AudioBus* dest) const { |
338 CHECK_EQ(channels(), dest->channels()); | 318 CHECK_EQ(channels(), dest->channels()); |
339 CHECK_LE(source_start_frame + frame_count, frames()); | 319 CHECK_LE(source_start_frame + frame_count, frames()); |
(...skipping 29 matching lines...) Expand all Loading... |
369 return scoped_refptr<AudioBusRefCounted>( | 349 return scoped_refptr<AudioBusRefCounted>( |
370 new AudioBusRefCounted(channels, frames)); | 350 new AudioBusRefCounted(channels, frames)); |
371 } | 351 } |
372 | 352 |
373 AudioBusRefCounted::AudioBusRefCounted(int channels, int frames) | 353 AudioBusRefCounted::AudioBusRefCounted(int channels, int frames) |
374 : AudioBus(channels, frames) {} | 354 : AudioBus(channels, frames) {} |
375 | 355 |
376 AudioBusRefCounted::~AudioBusRefCounted() {} | 356 AudioBusRefCounted::~AudioBusRefCounted() {} |
377 | 357 |
378 } // namespace media | 358 } // namespace media |
OLD | NEW |