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 <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "media/audio/audio_parameters.h" | 10 #include "media/audio/audio_parameters.h" |
11 #include "media/base/limits.h" | 11 #include "media/base/limits.h" |
12 | 12 |
13 namespace media { | 13 namespace media { |
14 | 14 |
15 static const uint8 kUint8Bias = 128; | |
16 static const int16 kUint8Min = -kUint8Bias; | |
17 static const int16 kUint8Max = kUint8Bias - 1; | |
18 | |
15 static bool IsAligned(void* ptr) { | 19 static bool IsAligned(void* ptr) { |
16 return (reinterpret_cast<uintptr_t>(ptr) & | 20 return (reinterpret_cast<uintptr_t>(ptr) & |
17 (AudioBus::kChannelAlignment - 1)) == 0U; | 21 (AudioBus::kChannelAlignment - 1)) == 0U; |
18 } | 22 } |
19 | 23 |
20 // Calculates the required size for an AudioBus with the given params, sets | 24 // Calculates the required size for an AudioBus with the given params, sets |
21 // |aligned_frames| to the actual frame length of each channel array. | 25 // |aligned_frames| to the actual frame length of each channel array. |
22 static int CalculateMemorySizeInternal(int channels, int frames, | 26 static int CalculateMemorySizeInternal(int channels, int frames, |
23 int* out_aligned_frames) { | 27 int* out_aligned_frames) { |
24 // Choose a size such that each channel will be aligned by | 28 // Choose a size such that each channel will be aligned by |
25 // kChannelAlignment when stored in a contiguous block. | 29 // kChannelAlignment when stored in a contiguous block. |
26 int aligned_frames = | 30 int aligned_frames = |
27 ((frames * sizeof(float) + AudioBus::kChannelAlignment - 1) & | 31 ((frames * sizeof(float) + AudioBus::kChannelAlignment - 1) & |
28 ~(AudioBus::kChannelAlignment - 1)) / sizeof(float); | 32 ~(AudioBus::kChannelAlignment - 1)) / sizeof(float); |
29 | 33 |
30 if (out_aligned_frames) | 34 if (out_aligned_frames) |
31 *out_aligned_frames = aligned_frames; | 35 *out_aligned_frames = aligned_frames; |
32 | 36 |
33 return sizeof(float) * channels * aligned_frames; | 37 return sizeof(float) * channels * aligned_frames; |
34 } | 38 } |
35 | 39 |
36 // |Format| is the destination type, |Fixed| is a type larger than |Format| | 40 // |Format| is the destination type, |Fixed| is a type larger than |Format| |
37 // such that operations can be made without overflowing. | 41 // such that operations can be made without overflowing. |
38 template<class Format, class Fixed> | 42 template<class Format, class Fixed> |
39 static void FromInterleavedInternal(const void* src, int start_frame, | 43 static void FromInterleavedInternal(const void* src, int start_frame, |
40 int frames, AudioBus* dest) { | 44 int frames, AudioBus* dest, |
45 Format bias, float min, float max) { | |
41 const Format* source = static_cast<const Format*>(src); | 46 const Format* source = static_cast<const Format*>(src); |
42 | 47 const int channels = dest->channels(); |
43 static const Fixed kBias = std::numeric_limits<Format>::is_signed ? 0 : | |
44 std::numeric_limits<Format>::max() / 2 + 1; | |
45 static const float kMaxScale = 1.0f / (kBias ? kBias - 1 : | |
46 std::numeric_limits<Format>::max()); | |
47 static const float kMinScale = 1.0f / (kBias ? kBias : | |
48 -static_cast<Fixed>(std::numeric_limits<Format>::min())); | |
49 | |
50 int channels = dest->channels(); | |
51 for (int ch = 0; ch < channels; ++ch) { | 48 for (int ch = 0; ch < channels; ++ch) { |
52 float* channel_data = dest->channel(ch); | 49 float* channel_data = dest->channel(ch); |
53 for (int i = start_frame, offset = ch; i < start_frame + frames; | 50 for (int i = start_frame, offset = ch; i < start_frame + frames; |
54 ++i, offset += channels) { | 51 ++i, offset += channels) { |
55 Fixed v = static_cast<Fixed>(source[offset]) - kBias; | 52 const Fixed v = static_cast<Fixed>(source[offset]) - bias; |
56 channel_data[i] = v * (v < 0 ? kMinScale : kMaxScale); | 53 channel_data[i] = v * (v < 0 ? -min : max); |
57 } | 54 } |
58 } | 55 } |
59 } | 56 } |
60 | 57 |
61 // |Format| is the destination type, |Fixed| is a type larger than |Format| | 58 // |Format| is the destination type, |Fixed| is a type larger than |Format| |
62 // such that operations can be made without overflowing. | 59 // such that operations can be made without overflowing. |
63 template<class Format, class Fixed> | 60 template<class Format, class Fixed> |
64 static void ToInterleavedInternal(const AudioBus* source, int start_frame, | 61 static void ToInterleavedInternal(const AudioBus* source, int start_frame, |
65 int frames, void* dst) { | 62 int frames, void* dst, |
63 Format bias, Fixed min, Fixed max) { | |
66 Format* dest = static_cast<Format*>(dst); | 64 Format* dest = static_cast<Format*>(dst); |
67 | 65 const int channels = source->channels(); |
68 static const Format kBias = std::numeric_limits<Format>::is_signed ? 0 : | |
69 std::numeric_limits<Format>::max() / 2 + 1; | |
70 static const Fixed kMaxValue = kBias ? kBias - 1 : | |
71 std::numeric_limits<Format>::max(); | |
72 static const Fixed kMinValue = kBias ? -kBias : | |
73 std::numeric_limits<Format>::min(); | |
74 | |
75 int channels = source->channels(); | |
76 for (int ch = 0; ch < channels; ++ch) { | 66 for (int ch = 0; ch < channels; ++ch) { |
77 const float* channel_data = source->channel(ch); | 67 const float* channel_data = source->channel(ch); |
78 for (int i = start_frame, offset = ch; i < start_frame + frames; | 68 for (int i = start_frame, offset = ch; i < start_frame + frames; |
79 ++i, offset += channels) { | 69 ++i, offset += channels) { |
80 float v = channel_data[i]; | 70 const float v = channel_data[i]; |
81 Fixed sample = v * (v < 0 ? -kMinValue : kMaxValue); | |
82 | 71 |
83 if (sample > kMaxValue) | 72 Fixed sample; |
84 sample = kMaxValue; | 73 if (v < 0) |
85 else if (sample < kMinValue) | 74 sample = static_cast<Fixed>(v * -min) & min; |
DaleCurtis
2013/04/08 21:00:30
Sadly, this is actually just plain wrong. I'm not
DaleCurtis
2013/04/09 00:40:34
Fixed. Using the ternary here compiles into a cmov
| |
86 sample = kMinValue; | 75 else |
76 sample = static_cast<Fixed>(v * max) & max; | |
DaleCurtis
2013/04/08 21:00:30
Ditto.
| |
87 | 77 |
88 dest[offset] = static_cast<Format>(sample) + kBias; | 78 dest[offset] = static_cast<Format>(sample) + bias; |
89 } | 79 } |
90 } | 80 } |
91 } | 81 } |
92 | 82 |
93 static void ValidateConfig(size_t channels, int frames) { | 83 static void ValidateConfig(size_t channels, int frames) { |
94 CHECK_GT(frames, 0); | 84 CHECK_GT(frames, 0); |
95 CHECK_LE(channels, static_cast<size_t>(limits::kMaxChannels)); | 85 CHECK_LE(channels, static_cast<size_t>(limits::kMaxChannels)); |
96 } | 86 } |
97 | 87 |
98 static void CheckOverflow(int start_frame, int frames, int total_frames) { | 88 static void CheckOverflow(int start_frame, int frames, int total_frames) { |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 for (int i = 0; i < channels; ++i) | 228 for (int i = 0; i < channels; ++i) |
239 channel_data_.push_back(data + i * aligned_frames); | 229 channel_data_.push_back(data + i * aligned_frames); |
240 } | 230 } |
241 | 231 |
242 // TODO(dalecurtis): See if intrinsic optimizations help any here. | 232 // TODO(dalecurtis): See if intrinsic optimizations help any here. |
243 void AudioBus::FromInterleavedPartial(const void* source, int start_frame, | 233 void AudioBus::FromInterleavedPartial(const void* source, int start_frame, |
244 int frames, int bytes_per_sample) { | 234 int frames, int bytes_per_sample) { |
245 CheckOverflow(start_frame, frames, frames_); | 235 CheckOverflow(start_frame, frames, frames_); |
246 switch (bytes_per_sample) { | 236 switch (bytes_per_sample) { |
247 case 1: | 237 case 1: |
248 FromInterleavedInternal<uint8, int16>(source, start_frame, frames, this); | 238 FromInterleavedInternal<uint8, int16>( |
239 source, start_frame, frames, this, | |
240 kUint8Bias, 1.0f / kUint8Min, 1.0f / kUint8Max); | |
249 break; | 241 break; |
250 case 2: | 242 case 2: |
251 FromInterleavedInternal<int16, int32>(source, start_frame, frames, this); | 243 FromInterleavedInternal<int16, int32>( |
244 source, start_frame, frames, this, | |
245 0, 1.0f / kint16min, 1.0f / kint16max); | |
252 break; | 246 break; |
253 case 4: | 247 case 4: |
254 FromInterleavedInternal<int32, int64>(source, start_frame, frames, this); | 248 FromInterleavedInternal<int32, int64>( |
249 source, start_frame, frames, this, | |
250 0, 1.0f / kint32min, 1.0f / kint32max); | |
255 break; | 251 break; |
256 default: | 252 default: |
257 NOTREACHED() << "Unsupported bytes per sample encountered."; | 253 NOTREACHED() << "Unsupported bytes per sample encountered."; |
258 ZeroFramesPartial(start_frame, frames); | 254 ZeroFramesPartial(start_frame, frames); |
259 return; | 255 return; |
260 } | 256 } |
261 | 257 |
262 // Don't clear remaining frames if this is a partial deinterleave. | 258 // Don't clear remaining frames if this is a partial deinterleave. |
263 if (!start_frame) { | 259 if (!start_frame) { |
264 // Zero any remaining frames. | 260 // Zero any remaining frames. |
(...skipping 10 matching lines...) Expand all Loading... | |
275 void* dest) const { | 271 void* dest) const { |
276 ToInterleavedPartial(0, frames, bytes_per_sample, dest); | 272 ToInterleavedPartial(0, frames, bytes_per_sample, dest); |
277 } | 273 } |
278 | 274 |
279 // TODO(dalecurtis): See if intrinsic optimizations help any here. | 275 // TODO(dalecurtis): See if intrinsic optimizations help any here. |
280 void AudioBus::ToInterleavedPartial(int start_frame, int frames, | 276 void AudioBus::ToInterleavedPartial(int start_frame, int frames, |
281 int bytes_per_sample, void* dest) const { | 277 int bytes_per_sample, void* dest) const { |
282 CheckOverflow(start_frame, frames, frames_); | 278 CheckOverflow(start_frame, frames, frames_); |
283 switch (bytes_per_sample) { | 279 switch (bytes_per_sample) { |
284 case 1: | 280 case 1: |
285 ToInterleavedInternal<uint8, int16>(this, start_frame, frames, dest); | 281 ToInterleavedInternal<uint8, int16>( |
282 this, start_frame, frames, dest, | |
283 kUint8Bias, kUint8Min, kUint8Max); | |
286 break; | 284 break; |
287 case 2: | 285 case 2: |
288 ToInterleavedInternal<int16, int32>(this, start_frame, frames, dest); | 286 ToInterleavedInternal<int16, int32>( |
287 this, start_frame, frames, dest, 0, kint16min, kint16max); | |
289 break; | 288 break; |
290 case 4: | 289 case 4: |
291 ToInterleavedInternal<int32, int64>(this, start_frame, frames, dest); | 290 ToInterleavedInternal<int32, int64>( |
291 this, start_frame, frames, dest, 0, kint32min, kint32max); | |
292 break; | 292 break; |
293 default: | 293 default: |
294 NOTREACHED() << "Unsupported bytes per sample encountered."; | 294 NOTREACHED() << "Unsupported bytes per sample encountered."; |
295 memset(dest, 0, frames * bytes_per_sample); | 295 memset(dest, 0, frames * bytes_per_sample); |
296 return; | 296 return; |
297 } | 297 } |
298 } | 298 } |
299 | 299 |
300 void AudioBus::CopyTo(AudioBus* dest) const { | 300 void AudioBus::CopyTo(AudioBus* dest) const { |
301 CHECK_EQ(channels(), dest->channels()); | 301 CHECK_EQ(channels(), dest->channels()); |
302 CHECK_EQ(frames(), dest->frames()); | 302 CHECK_EQ(frames(), dest->frames()); |
303 | 303 |
304 // Since we don't know if the other AudioBus is wrapped or not (and we don't | 304 // Since we don't know if the other AudioBus is wrapped or not (and we don't |
305 // want to care), just copy using the public channel() accessors. | 305 // want to care), just copy using the public channel() accessors. |
306 for (int i = 0; i < channels(); ++i) | 306 for (int i = 0; i < channels(); ++i) |
307 memcpy(dest->channel(i), channel(i), sizeof(*channel(i)) * frames()); | 307 memcpy(dest->channel(i), channel(i), sizeof(*channel(i)) * frames()); |
308 } | 308 } |
309 | 309 |
310 } // namespace media | 310 } // namespace media |
OLD | NEW |