1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
media / base / audio_buffer.h [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_AUDIO_BUFFER_H_
#define MEDIA_BASE_AUDIO_BUFFER_H_
#include <stddef.h>
#include <stdint.h>
#include <list>
#include <memory>
#include <utility>
#include <vector>
#include "base/containers/span.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/raw_span.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "base/time/time.h"
#include "media/base/audio_bus.h"
#include "media/base/channel_layout.h"
#include "media/base/media_export.h"
#include "media/base/sample_format.h"
namespace mojo {
template <typename T, typename U>
struct TypeConverter;
template <typename T>
class StructPtr;
} // namespace mojo
namespace media {
class AudioBufferMemoryPool;
namespace mojom {
class AudioBuffer;
}
// An audio buffer that takes a copy of the data passed to it, holds it, and
// copies it into an AudioBus when needed. Also supports an end of stream
// marker.
class MEDIA_EXPORT AudioBuffer
: public base::RefCountedThreadSafe<AudioBuffer> {
public:
struct MEDIA_EXPORT ExternalMemory {
public:
explicit ExternalMemory(base::span<uint8_t> span);
virtual ~ExternalMemory();
ExternalMemory(const ExternalMemory&);
ExternalMemory(ExternalMemory&&);
base::span<uint8_t> span() { return span_; }
protected:
ExternalMemory();
base::raw_span<uint8_t, DanglingUntriaged> span_;
};
// Create an AudioBuffer whose channel data is copied from |data|. For
// interleaved data, only the first buffer is used. For planar data, the
// number of buffers must be equal to |channel_count|. |frame_count| is the
// number of frames in each buffer. |data| must not be null and |frame_count|
// must be >= 0. For optimal efficiency when many buffers are being created, a
// AudioBufferMemoryPool can be provided to avoid thrashing memory.
static scoped_refptr<AudioBuffer> CopyFrom(
SampleFormat sample_format,
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
const uint8_t* const* data,
const base::TimeDelta timestamp,
scoped_refptr<AudioBufferMemoryPool> pool = nullptr);
// Create an AudioBuffer from a copy of the data in |audio_bus| and a given
// |channel_layout|. For optimal efficiency when many buffers are being
// created, a AudioBufferMemoryPool can be provided to avoid thrashing memory.
static scoped_refptr<AudioBuffer> CopyFrom(
ChannelLayout channel_layout,
int sample_rate,
const base::TimeDelta timestamp,
const AudioBus* audio_bus,
scoped_refptr<AudioBufferMemoryPool> pool = nullptr);
// Create an AudioBuffer from a copy of the data in |audio_bus|.
// For optimal efficiency when many buffers are being created, a
// AudioBufferMemoryPool can be provided to avoid thrashing memory.
static scoped_refptr<AudioBuffer> CopyFrom(
int sample_rate,
const base::TimeDelta timestamp,
const AudioBus* audio_bus,
scoped_refptr<AudioBufferMemoryPool> pool = nullptr);
// Create an AudioBuffer for compressed bitstream. Its channel data is copied
// from |data|, and the size is |data_size|. |data| must not be null and
// |frame_count| must be >= 0.
static scoped_refptr<AudioBuffer> CopyBitstreamFrom(
SampleFormat sample_format,
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
const uint8_t* const* data,
const size_t data_size,
const base::TimeDelta timestamp,
scoped_refptr<AudioBufferMemoryPool> pool = nullptr);
// Create an AudioBuffer with |frame_count| frames. Buffer is allocated, but
// not initialized. Timestamp and duration are set to kNoTimestamp. For
// optimal efficiency when many buffers are being created, a
// AudioBufferMemoryPool can be provided to avoid thrashing memory.
static scoped_refptr<AudioBuffer> CreateBuffer(
SampleFormat sample_format,
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
scoped_refptr<AudioBufferMemoryPool> pool = nullptr);
// Create an AudioBuffer for compressed bitstream. Buffer is allocated, but
// not initialized. Timestamp and duration are set to kNoTimestamp.
static scoped_refptr<AudioBuffer> CreateBitstreamBuffer(
SampleFormat sample_format,
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
size_t data_size,
scoped_refptr<AudioBufferMemoryPool> pool = nullptr);
// Create an empty AudioBuffer with |frame_count| frames.
static scoped_refptr<AudioBuffer> CreateEmptyBuffer(
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
const base::TimeDelta timestamp);
// Creates a AudioBuffer with ExternalMemory.
// `external_memory` is owned by AudioBuffer until it is destroyed.
// This method CHECK() fails
// 1. `external_memory` isn't large enough to fit all the data described
// by `frame_count` and `channel_count`.
// 2. `external_memory` is not aligned to `sample_format` requirements.
static scoped_refptr<AudioBuffer> CreateFromExternalMemory(
SampleFormat sample_format,
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
const base::TimeDelta timestamp,
std::unique_ptr<ExternalMemory> external_memory);
// Helper function that creates a new AudioBus which wraps |audio_buffer| and
// takes a reference on it, if the memory layout (e.g. |sample_format_|) is
// compatible with wrapping. Otherwise, this copies |audio_buffer| to a new
// AudioBus, using ReadFrames().
static std::unique_ptr<AudioBus> WrapOrCopyToAudioBus(
scoped_refptr<AudioBuffer> audio_buffer);
// Create an AudioBuffer indicating we've reached end of stream.
// Calling any method other than end_of_stream() on the resulting buffer
// is disallowed.
static scoped_refptr<AudioBuffer> CreateEOSBuffer();
AudioBuffer() = delete;
AudioBuffer(const AudioBuffer&) = delete;
AudioBuffer& operator=(const AudioBuffer&) = delete;
// Update sample rate and computed duration.
// TODO(chcunningham): Remove this upon patching FFmpeg's AAC decoder to
// provide the correct sample rate at the boundary of an implicit config
// change.
void AdjustSampleRate(int sample_rate);
// Copy frames into |dest|. |frames_to_copy| is the number of frames to copy.
// |source_frame_offset| specifies how many frames in the buffer to skip
// first. |dest_frame_offset| is the frame offset in |dest|. The frames are
// converted and clipped from their source format into planar float32 data
// (which is all that AudioBus handles).
void ReadFrames(int frames_to_copy,
int source_frame_offset,
int dest_frame_offset,
AudioBus* dest) const;
// Trim an AudioBuffer by removing |frames_to_trim| frames from the start.
// Timestamp and duration are adjusted to reflect the fewer frames.
// Note that repeated calls to TrimStart() may result in timestamp() and
// duration() being off by a few microseconds due to rounding issues.
void TrimStart(int frames_to_trim);
// Trim an AudioBuffer by removing |frames_to_trim| frames from the end.
// Duration is adjusted to reflect the fewer frames.
void TrimEnd(int frames_to_trim);
// Trim an AudioBuffer by removing |end - start| frames from [|start|, |end|).
// Even if |start| is zero, timestamp() is not adjusted, only duration().
void TrimRange(int start, int end);
// Return true if the buffer contains compressed bitstream.
bool IsBitstreamFormat() const;
// Return the number of channels.
int channel_count() const { return channel_count_; }
// Return the number of frames held.
int frame_count() const { return adjusted_frame_count_; }
// Return the sample rate.
int sample_rate() const { return sample_rate_; }
// Return the sample format of the internal buffer, not that of what is
// returned by ReadFrames().
SampleFormat sample_format() const { return sample_format_; }
// Return the channel layout.
ChannelLayout channel_layout() const { return channel_layout_; }
base::TimeDelta timestamp() const { return timestamp_; }
base::TimeDelta duration() const { return duration_; }
void set_timestamp(base::TimeDelta timestamp) { timestamp_ = timestamp; }
// If there's no data in this buffer, it represents end of stream.
bool end_of_stream() const { return end_of_stream_; }
// Access to the raw buffer for ffmpeg and Android MediaCodec decoders to
// write directly to. For planar formats the vector elements correspond to
// the channels. For interleaved formats the resulting vector has exactly
// one element which contains the buffer pointer.
const std::vector<uint8_t*>& channel_data() const { return channel_data_; }
// The size of allocated data memory block. For planar formats channels go
// sequentially in this block.
size_t data_size() const { return data_size_; }
private:
friend class base::RefCountedThreadSafe<AudioBuffer>;
// mojo::TypeConverter added as a friend so that AudioBuffer can be
// transferred across a mojo connection.
friend struct mojo::TypeConverter<mojo::StructPtr<mojom::AudioBuffer>,
AudioBuffer>;
// Allocates aligned contiguous buffer to hold all channel data (1 block for
// interleaved data, |channel_count| blocks for planar data), copies
// [data,data+data_size) to the allocated buffer(s). If |data| is null, no
// data is copied. If |create_buffer| is false, no data buffer is created (or
// copied to).
AudioBuffer(SampleFormat sample_format,
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
bool create_buffer,
const uint8_t* const* data,
const size_t data_size,
const base::TimeDelta timestamp,
scoped_refptr<AudioBufferMemoryPool> pool);
// Takes ownership over a contiguous buffer to hold all channel data
// (1 block for interleaved data, |channel_count| blocks for planar data).
AudioBuffer(SampleFormat sample_format,
ChannelLayout channel_layout,
int channel_count,
int sample_rate,
int frame_count,
const base::TimeDelta timestamp,
std::unique_ptr<ExternalMemory> external_memory);
virtual ~AudioBuffer();
const SampleFormat sample_format_;
const ChannelLayout channel_layout_;
const int channel_count_;
int sample_rate_;
int adjusted_frame_count_;
const bool end_of_stream_;
base::TimeDelta timestamp_;
base::TimeDelta duration_;
// Contiguous block of channel data.
size_t data_size_ = 0;
std::unique_ptr<ExternalMemory> data_;
// For planar data, points to each channels data.
std::vector<uint8_t*> channel_data_;
// Allows recycling of memory data to avoid repeated allocations.
scoped_refptr<AudioBufferMemoryPool> pool_;
};
// Basic memory pool for reusing AudioBuffer internal memory to avoid thrashing.
//
// The pool is managed in a last-in-first-out manner, returned buffers are put
// at the back of the queue. When a new buffer is requested by AudioBuffer, we
// will scan from the front to find a matching buffer. All non-matching buffers
// are dropped. The assumption is that when we reach steady-state all buffers
// will have the same sized allocation. At most the pool will be equal in size
// to the maximum number of concurrent AudioBuffer instances.
//
// Each AudioBuffer instance created with an AudioBufferMemoryPool will take a
// ref on the pool instance so that it may return buffers in the future.
class MEDIA_EXPORT AudioBufferMemoryPool
: public base::RefCountedThreadSafe<AudioBufferMemoryPool> {
public:
explicit AudioBufferMemoryPool(int alignment = AudioBus::kChannelAlignment);
AudioBufferMemoryPool(const AudioBufferMemoryPool&) = delete;
AudioBufferMemoryPool& operator=(const AudioBufferMemoryPool&) = delete;
size_t GetPoolSizeForTesting();
int GetChannelAlignment() { return alignment_; }
struct ExternalMemoryFromPool : public AudioBuffer::ExternalMemory {
public:
ExternalMemoryFromPool(
scoped_refptr<AudioBufferMemoryPool> pool,
std::unique_ptr<uint8_t, base::AlignedFreeDeleter> memory,
size_t size);
ExternalMemoryFromPool(ExternalMemoryFromPool&&);
~ExternalMemoryFromPool() override;
std::unique_ptr<uint8_t, base::AlignedFreeDeleter> memory_;
scoped_refptr<AudioBufferMemoryPool> pool_;
};
private:
friend class AudioBuffer;
friend class base::RefCountedThreadSafe<AudioBufferMemoryPool>;
~AudioBufferMemoryPool();
std::unique_ptr<ExternalMemoryFromPool> CreateBuffer(size_t size);
void ReturnBuffer(ExternalMemoryFromPool memory);
const int alignment_;
base::Lock entry_lock_;
std::list<ExternalMemoryFromPool> entries_ GUARDED_BY(entry_lock_);
};
} // namespace media
#endif // MEDIA_BASE_AUDIO_BUFFER_H_