| 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 |