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 #ifndef MEDIA_BASE_AUDIO_BUS_H_ | 5 #ifndef MEDIA_BASE_AUDIO_BUS_H_ |
6 #define MEDIA_BASE_AUDIO_BUS_H_ | 6 #define MEDIA_BASE_AUDIO_BUS_H_ |
7 | 7 |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <memory> | 10 #include <memory> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/memory/aligned_memory.h" | 14 #include "base/memory/aligned_memory.h" |
15 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
16 #include "media/base/media_export.h" | 16 #include "media/base/media_export.h" |
17 | 17 |
18 namespace media { | 18 namespace media { |
19 class AudioParameters; | 19 class AudioParameters; |
20 | 20 |
21 // Scoped container for "busing" audio channel data around. Each channel is | 21 // Represents a sequence of audio frames containing frames() audio samples for |
22 // stored in planar format and guaranteed to be aligned by kChannelAlignment. | 22 // each of channels() channels. The data is stored as a set of contiguous |
23 // AudioBus objects can be created normally or via wrapping. Normally, AudioBus | 23 // float arrays with one array per channel. The memory for the arrays is either |
24 // will dice up a contiguous memory block for channel data. When wrapped, | 24 // allocated and owned by the AudioBus or it is provided to one of the factory |
25 // AudioBus instead routes requests for channel data to the wrapped object. | 25 // methods. AudioBus guarantees that it allocates memory such that float array |
| 26 // for each channel is aligned by AudioBus::kChannelAlignment bytes and it |
| 27 // requires the same for memory passed to its Wrap...() factory methods. |
| 28 // TODO(chfremer): There are currently no unit tests involving CreateWrapper and |
| 29 // SetChannelData, so we need to add them. |
| 30 // TODO(chfremer): Add unit tests to verify zeroing out happens on |
| 31 // FromInterleaved() but not on FromInterleavedPartial(). |
26 class MEDIA_EXPORT AudioBus { | 32 class MEDIA_EXPORT AudioBus { |
27 public: | 33 public: |
28 // Guaranteed alignment of each channel's data; use 16-byte alignment for easy | 34 // Guaranteed alignment of each channel's data; use 16-byte alignment for easy |
29 // SSE optimizations. | 35 // SSE optimizations. |
30 enum { kChannelAlignment = 16 }; | 36 enum { kChannelAlignment = 16 }; |
31 | 37 |
32 // Creates a new AudioBus and allocates |channels| of length |frames|. Uses | 38 // Creates a new AudioBus and allocates |channels| of length |frames|. Uses |
33 // channels() and frames_per_buffer() from AudioParameters if given. | 39 // channels() and frames_per_buffer() from AudioParameters if given. |
34 static std::unique_ptr<AudioBus> Create(int channels, int frames); | 40 static std::unique_ptr<AudioBus> Create(int channels, int frames); |
35 static std::unique_ptr<AudioBus> Create(const AudioParameters& params); | 41 static std::unique_ptr<AudioBus> Create(const AudioParameters& params); |
36 | 42 |
37 // Creates a new AudioBus with the given number of channels, but zero length. | 43 // Creates a new AudioBus with the given number of channels, but zero length. |
38 // It's expected to be used with SetChannelData() and set_frames() to | 44 // Clients are expected to subsequently call SetChannelData() and set_frames() |
39 // wrap externally allocated memory. | 45 // to wrap externally allocated memory. |
40 static std::unique_ptr<AudioBus> CreateWrapper(int channels); | 46 static std::unique_ptr<AudioBus> CreateWrapper(int channels); |
41 | 47 |
42 // Creates a new AudioBus from an existing channel vector. Does not transfer | 48 // Creates a new AudioBus from an existing channel vector. Does not transfer |
43 // ownership of |channel_data| to AudioBus; i.e., |channel_data| must outlive | 49 // ownership of |channel_data| to AudioBus; i.e., |channel_data| must outlive |
44 // the returned AudioBus. Each channel must be aligned by kChannelAlignment. | 50 // the returned AudioBus. Each channel must be aligned by kChannelAlignment. |
45 static std::unique_ptr<AudioBus> WrapVector( | 51 static std::unique_ptr<AudioBus> WrapVector( |
46 int frames, | 52 int frames, |
47 const std::vector<float*>& channel_data); | 53 const std::vector<float*>& channel_data); |
48 | 54 |
49 // Creates a new AudioBus by wrapping an existing block of memory. Block must | 55 // Creates a new AudioBus by wrapping an existing block of memory. Block must |
50 // be at least CalculateMemorySize() bytes in size. |data| must outlive the | 56 // be at least CalculateMemorySize() bytes in size. |data| must outlive the |
51 // returned AudioBus. |data| must be aligned by kChannelAlignment. | 57 // returned AudioBus. |data| must be aligned by kChannelAlignment. |
52 static std::unique_ptr<AudioBus> WrapMemory(int channels, | 58 static std::unique_ptr<AudioBus> WrapMemory(int channels, |
53 int frames, | 59 int frames, |
54 void* data); | 60 void* data); |
55 static std::unique_ptr<AudioBus> WrapMemory(const AudioParameters& params, | 61 static std::unique_ptr<AudioBus> WrapMemory(const AudioParameters& params, |
56 void* data); | 62 void* data); |
| 63 |
| 64 // Based on the given number of channels and frames, calculates the minimum |
| 65 // required size in bytes of a contiguous block of memory to be passed to |
| 66 // AudioBus for storage of the audio data. |
| 67 // Uses channels() and frames_per_buffer() from AudioParameters if given. |
| 68 static int CalculateMemorySize(int channels, int frames); |
57 static int CalculateMemorySize(const AudioParameters& params); | 69 static int CalculateMemorySize(const AudioParameters& params); |
58 | 70 |
59 // Calculates the required size for an AudioBus given the number of channels | 71 // Methods that are expected to be called after AudioBus::CreateWrapper() in |
60 // and frames. | 72 // order to wrap externally allocated memory. Note: It is illegal to call |
61 static int CalculateMemorySize(int channels, int frames); | 73 // these methods when using a factory method other than CreateWrapper(). |
| 74 void SetChannelData(int channel, float* data); |
| 75 void set_frames(int frames); |
62 | 76 |
63 // Helper methods for converting an AudioBus from and to interleaved integer | 77 // Overwrites the sample values stored in this AudioBus instance with values |
64 // data. Expects interleaving to be [ch0, ch1, ..., chN, ch0, ch1, ...] with | 78 // from a given interleaved |source_buffer| with expected layout |
65 // |bytes_per_sample| per value. Values are scaled and bias corrected during | 79 // [ch0, ch1, ..., chN, ch0, ch1, ...] and sample values in the format |
66 // conversion. ToInterleaved() will also clip values to format range. | 80 // corresponding to the given SourceSampleTypeTraits. |
67 // Handles uint8_t, int16_t, and int32_t currently. FromInterleaved() will | 81 // The sample values are converted to float values by means of the method |
68 // zero out | 82 // convert_to_float32() provided by the SourceSampleTypeTraits. For a list of |
69 // any unfilled frames when |frames| is less than frames(). | 83 // ready-to-use SampleTypeTraits, see file audio_sample_types.h. |
| 84 // If |num_frames_to_write| is less than frames(), the remaining frames are |
| 85 // zeroed out. If |num_frames_to_write| is more than frames(), this results in |
| 86 // undefined behavior. |
| 87 template <class SourceSampleTypeTraits> |
| 88 void FromInterleaved( |
| 89 const typename SourceSampleTypeTraits::ValueType* source_buffer, |
| 90 int num_frames_to_write); |
| 91 |
| 92 // DEPRECATED |
| 93 // Please use the version templated with SourceSampleTypeTraits instead. |
70 void FromInterleaved(const void* source, int frames, int bytes_per_sample); | 94 void FromInterleaved(const void* source, int frames, int bytes_per_sample); |
71 void ToInterleaved(int frames, int bytes_per_sample, void* dest) const; | |
72 void ToInterleavedPartial(int start_frame, int frames, int bytes_per_sample, | |
73 void* dest) const; | |
74 | 95 |
75 // Similar to FromInterleaved() above, but meant for streaming sources. Does | 96 // Similar to FromInterleaved...(), but overwrites the frames starting at a |
76 // not zero out remaining frames, the caller is responsible for doing so using | 97 // given offset |write_offset_in_frames| and does not zero out frames that are |
77 // ZeroFramesPartial(). Frames are deinterleaved from the start of |source| | 98 // not overwritten. |
78 // to channel(x)[start_frame]. | 99 template <class SourceSampleTypeTraits> |
| 100 void FromInterleavedPartial( |
| 101 const typename SourceSampleTypeTraits::ValueType* source_buffer, |
| 102 int write_offset_in_frames, |
| 103 int num_frames_to_write); |
| 104 |
| 105 // DEPRECATED |
| 106 // Please use the version templated with SourceSampleTypeTraits instead. |
79 void FromInterleavedPartial(const void* source, int start_frame, int frames, | 107 void FromInterleavedPartial(const void* source, int start_frame, int frames, |
80 int bytes_per_sample); | 108 int bytes_per_sample); |
81 | 109 |
| 110 // Reads the sample values stored in this AudioBus instance and places them |
| 111 // into the given |dest_buffer| in interleaved format using the sample format |
| 112 // specified by TargetSampleTypeTraits. For a list of ready-to-use |
| 113 // SampleTypeTraits, see file audio_sample_types.h. If |num_frames_to_read| is |
| 114 // larger than frames(), this results in undefined behavior. |
| 115 template <class TargetSampleTypeTraits> |
| 116 void ToInterleaved( |
| 117 int num_frames_to_read, |
| 118 typename TargetSampleTypeTraits::ValueType* dest_buffer) const; |
| 119 |
| 120 // DEPRECATED |
| 121 // Please use the version templated with TargetSampleTypeTraits instead. |
| 122 void ToInterleaved(int frames, int bytes_per_sample, void* dest) const; |
| 123 |
| 124 // Similar to ToInterleaved(), but reads the frames starting at a given |
| 125 // offset |read_offset_in_frames|. |
| 126 template <class TargetSampleTypeTraits> |
| 127 void ToInterleavedPartial( |
| 128 int read_offset_in_frames, |
| 129 int num_frames_to_read, |
| 130 typename TargetSampleTypeTraits::ValueType* dest_buffer) const; |
| 131 |
| 132 // DEPRECATED |
| 133 // Please use the version templated with TargetSampleTypeTraits instead. |
| 134 void ToInterleavedPartial(int start_frame, |
| 135 int frames, |
| 136 int bytes_per_sample, |
| 137 void* dest) const; |
| 138 |
82 // Helper method for copying channel data from one AudioBus to another. Both | 139 // Helper method for copying channel data from one AudioBus to another. Both |
83 // AudioBus object must have the same frames() and channels(). | 140 // AudioBus object must have the same frames() and channels(). |
84 void CopyTo(AudioBus* dest) const; | 141 void CopyTo(AudioBus* dest) const; |
85 | 142 |
86 // Helper method to copy frames from one AudioBus to another. Both AudioBus | 143 // Helper method to copy frames from one AudioBus to another. Both AudioBus |
87 // objects must have the same number of channels(). |source_start_frame| is | 144 // objects must have the same number of channels(). |source_start_frame| is |
88 // the starting offset. |dest_start_frame| is the starting offset in |dest|. | 145 // the starting offset. |dest_start_frame| is the starting offset in |dest|. |
89 // |frame_count| is the number of frames to copy. | 146 // |frame_count| is the number of frames to copy. |
90 void CopyPartialFramesTo(int source_start_frame, | 147 void CopyPartialFramesTo(int source_start_frame, |
91 int frame_count, | 148 int frame_count, |
92 int dest_start_frame, | 149 int dest_start_frame, |
93 AudioBus* dest) const; | 150 AudioBus* dest) const; |
94 | 151 |
95 // Returns a raw pointer to the requested channel. Pointer is guaranteed to | 152 // Returns a raw pointer to the requested channel. Pointer is guaranteed to |
96 // have a 16-byte alignment. Warning: Do not rely on having sane (i.e. not | 153 // have a 16-byte alignment. Warning: Do not rely on having sane (i.e. not |
97 // inf, nan, or between [-1.0, 1.0]) values in the channel data. | 154 // inf, nan, or between [-1.0, 1.0]) values in the channel data. |
98 float* channel(int channel) { return channel_data_[channel]; } | 155 float* channel(int channel) { return channel_data_[channel]; } |
99 const float* channel(int channel) const { return channel_data_[channel]; } | 156 const float* channel(int channel) const { return channel_data_[channel]; } |
100 void SetChannelData(int channel, float* data); | |
101 | 157 |
| 158 // Returns the number of channels. |
102 int channels() const { return static_cast<int>(channel_data_.size()); } | 159 int channels() const { return static_cast<int>(channel_data_.size()); } |
| 160 // Returns the number of frames. |
103 int frames() const { return frames_; } | 161 int frames() const { return frames_; } |
104 void set_frames(int frames); | |
105 | 162 |
106 // Helper method for zeroing out all channels of audio data. | 163 // Helper method for zeroing out all channels of audio data. |
107 void Zero(); | 164 void Zero(); |
108 void ZeroFrames(int frames); | 165 void ZeroFrames(int frames); |
109 void ZeroFramesPartial(int start_frame, int frames); | 166 void ZeroFramesPartial(int start_frame, int frames); |
110 | 167 |
111 // Checks if all frames are zero. | 168 // Checks if all frames are zero. |
112 bool AreFramesZero() const; | 169 bool AreFramesZero() const; |
113 | 170 |
114 // Scale internal channel values by |volume| >= 0. If an invalid value | 171 // Scale internal channel values by |volume| >= 0. If an invalid value |
115 // is provided, no adjustment is done. | 172 // is provided, no adjustment is done. |
116 void Scale(float volume); | 173 void Scale(float volume); |
117 | 174 |
118 // Swaps channels identified by |a| and |b|. The caller needs to make sure | 175 // Swaps channels identified by |a| and |b|. The caller needs to make sure |
119 // the channels are valid. | 176 // the channels are valid. |
120 void SwapChannels(int a, int b); | 177 void SwapChannels(int a, int b); |
121 | 178 |
122 virtual ~AudioBus(); | 179 virtual ~AudioBus(); |
123 | 180 |
124 protected: | 181 protected: |
125 AudioBus(int channels, int frames); | 182 AudioBus(int channels, int frames); |
126 AudioBus(int channels, int frames, float* data); | 183 AudioBus(int channels, int frames, float* data); |
127 AudioBus(int frames, const std::vector<float*>& channel_data); | 184 AudioBus(int frames, const std::vector<float*>& channel_data); |
128 explicit AudioBus(int channels); | 185 explicit AudioBus(int channels); |
129 | 186 |
130 private: | 187 private: |
131 // Helper method for building |channel_data_| from a block of memory. |data| | 188 // Helper method for building |channel_data_| from a block of memory. |data| |
132 // must be at least BlockSize() bytes in size. | 189 // must be at least CalculateMemorySize(...) bytes in size. |
133 void BuildChannelData(int channels, int aligned_frame, float* data); | 190 void BuildChannelData(int channels, int aligned_frame, float* data); |
134 | 191 |
| 192 static void CheckOverflow(int start_frame, int frames, int total_frames); |
| 193 |
| 194 template <class SourceSampleTypeTraits> |
| 195 static void CopyConvertFromInterleavedSourceToAudioBus( |
| 196 const typename SourceSampleTypeTraits::ValueType* source_buffer, |
| 197 int write_offset_in_frames, |
| 198 int num_frames_to_write, |
| 199 AudioBus* dest); |
| 200 |
| 201 template <class TargetSampleTypeTraits> |
| 202 static void CopyConvertFromAudioBusToInterleavedTarget( |
| 203 const AudioBus* source, |
| 204 int read_offset_in_frames, |
| 205 int num_frames_to_read, |
| 206 typename TargetSampleTypeTraits::ValueType* dest_buffer); |
| 207 |
135 // Contiguous block of channel memory. | 208 // Contiguous block of channel memory. |
136 std::unique_ptr<float, base::AlignedFreeDeleter> data_; | 209 std::unique_ptr<float, base::AlignedFreeDeleter> data_; |
137 | 210 |
| 211 // One float pointer per channel pointing to a contiguous block of memory for |
| 212 // that channel. If the memory is owned by this instance, this will |
| 213 // point to the memory in |data_|. Otherwise, it may point to memory provided |
| 214 // by the client. |
138 std::vector<float*> channel_data_; | 215 std::vector<float*> channel_data_; |
139 int frames_; | 216 int frames_; |
140 | 217 |
141 // Protect SetChannelData() and set_frames() for use by CreateWrapper(). | 218 // Protect SetChannelData() and set_frames() for use by CreateWrapper(). |
142 bool can_set_channel_data_; | 219 bool can_set_channel_data_; |
143 | 220 |
144 DISALLOW_COPY_AND_ASSIGN(AudioBus); | 221 DISALLOW_COPY_AND_ASSIGN(AudioBus); |
145 }; | 222 }; |
146 | 223 |
| 224 // Delegates to FromInterleavedPartial() |
| 225 template <class SourceSampleTypeTraits> |
| 226 void AudioBus::FromInterleaved( |
| 227 const typename SourceSampleTypeTraits::ValueType* source_buffer, |
| 228 int num_frames_to_write) { |
| 229 FromInterleavedPartial<SourceSampleTypeTraits>(source_buffer, 0, |
| 230 num_frames_to_write); |
| 231 // Zero any remaining frames. |
| 232 ZeroFramesPartial(num_frames_to_write, frames_ - num_frames_to_write); |
| 233 } |
| 234 |
| 235 template <class SourceSampleTypeTraits> |
| 236 void AudioBus::FromInterleavedPartial( |
| 237 const typename SourceSampleTypeTraits::ValueType* source_buffer, |
| 238 int write_offset_in_frames, |
| 239 int num_frames_to_write) { |
| 240 CheckOverflow(write_offset_in_frames, num_frames_to_write, frames_); |
| 241 CopyConvertFromInterleavedSourceToAudioBus<SourceSampleTypeTraits>( |
| 242 source_buffer, write_offset_in_frames, num_frames_to_write, this); |
| 243 } |
| 244 |
| 245 // Delegates to ToInterleavedPartial() |
| 246 template <class TargetSampleTypeTraits> |
| 247 void AudioBus::ToInterleaved( |
| 248 int num_frames_to_read, |
| 249 typename TargetSampleTypeTraits::ValueType* dest_buffer) const { |
| 250 ToInterleavedPartial<TargetSampleTypeTraits>(0, num_frames_to_read, |
| 251 dest_buffer); |
| 252 } |
| 253 |
| 254 // TODO(dalecurtis): See if intrinsic optimizations help any here (for each |
| 255 // sample type) |
| 256 template <class TargetSampleTypeTraits> |
| 257 void AudioBus::ToInterleavedPartial( |
| 258 int read_offset_in_frames, |
| 259 int num_frames_to_read, |
| 260 typename TargetSampleTypeTraits::ValueType* dest) const { |
| 261 CheckOverflow(read_offset_in_frames, num_frames_to_read, frames_); |
| 262 CopyConvertFromAudioBusToInterleavedTarget<TargetSampleTypeTraits>( |
| 263 this, read_offset_in_frames, num_frames_to_read, dest); |
| 264 } |
| 265 |
| 266 template <class SourceSampleTypeTraits> |
| 267 void AudioBus::CopyConvertFromInterleavedSourceToAudioBus( |
| 268 const typename SourceSampleTypeTraits::ValueType* source_buffer, |
| 269 int write_offset_in_frames, |
| 270 int num_frames_to_write, |
| 271 AudioBus* dest) { |
| 272 const int channels = dest->channels(); |
| 273 for (int ch = 0; ch < channels; ++ch) { |
| 274 float* channel_data = dest->channel(ch); |
| 275 for (int target_frame_index = write_offset_in_frames, |
| 276 read_pos_in_source = ch; |
| 277 target_frame_index < write_offset_in_frames + num_frames_to_write; |
| 278 ++target_frame_index, read_pos_in_source += channels) { |
| 279 auto source_value = source_buffer[read_pos_in_source]; |
| 280 channel_data[target_frame_index] = |
| 281 SourceSampleTypeTraits::convert_to_float32(source_value); |
| 282 } |
| 283 } |
| 284 } |
| 285 |
| 286 template <class TargetSampleTypeTraits> |
| 287 void AudioBus::CopyConvertFromAudioBusToInterleavedTarget( |
| 288 const AudioBus* source, |
| 289 int read_offset_in_frames, |
| 290 int num_frames_to_read, |
| 291 typename TargetSampleTypeTraits::ValueType* dest_buffer) { |
| 292 const int channels = source->channels(); |
| 293 for (int ch = 0; ch < channels; ++ch) { |
| 294 const float* channel_data = source->channel(ch); |
| 295 for (int source_frame_index = read_offset_in_frames, write_pos_in_dest = ch; |
| 296 source_frame_index < read_offset_in_frames + num_frames_to_read; |
| 297 ++source_frame_index, write_pos_in_dest += channels) { |
| 298 float sourceSampleValue = channel_data[source_frame_index]; |
| 299 dest_buffer[write_pos_in_dest] = |
| 300 TargetSampleTypeTraits::convert_from_float32(sourceSampleValue); |
| 301 } |
| 302 } |
| 303 } |
| 304 |
147 // RefCounted version of AudioBus. This is not meant for general use. Only use | 305 // RefCounted version of AudioBus. This is not meant for general use. Only use |
148 // this when your lifetime requirements make it impossible to use an | 306 // this when your lifetime requirements make it impossible to use an |
149 // AudioBus scoped_ptr. | 307 // AudioBus scoped_ptr. |
150 class MEDIA_EXPORT AudioBusRefCounted | 308 class MEDIA_EXPORT AudioBusRefCounted |
151 : public media::AudioBus, | 309 : public media::AudioBus, |
152 public base::RefCountedThreadSafe<AudioBusRefCounted> { | 310 public base::RefCountedThreadSafe<AudioBusRefCounted> { |
153 public: | 311 public: |
154 static scoped_refptr<AudioBusRefCounted> Create(int channels, int frames); | 312 static scoped_refptr<AudioBusRefCounted> Create(int channels, int frames); |
155 | 313 |
156 private: | 314 private: |
157 friend class base::RefCountedThreadSafe<AudioBusRefCounted>; | 315 friend class base::RefCountedThreadSafe<AudioBusRefCounted>; |
158 | 316 |
159 AudioBusRefCounted(int channels, int frames); | 317 AudioBusRefCounted(int channels, int frames); |
160 ~AudioBusRefCounted() override; | 318 ~AudioBusRefCounted() override; |
161 | 319 |
162 DISALLOW_COPY_AND_ASSIGN(AudioBusRefCounted); | 320 DISALLOW_COPY_AND_ASSIGN(AudioBusRefCounted); |
163 }; | 321 }; |
164 | 322 |
165 } // namespace media | 323 } // namespace media |
166 | 324 |
167 #endif // MEDIA_BASE_AUDIO_BUS_H_ | 325 #endif // MEDIA_BASE_AUDIO_BUS_H_ |
OLD | NEW |