Chromium Code Reviews| 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 |