Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52868 views
1
/*
2
* Copyright (c) 2012 Justin Ruggles <[email protected]>
3
*
4
* This file is part of FFmpeg.
5
*
6
* FFmpeg is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* FFmpeg is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with FFmpeg; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
#include <stdint.h>
22
#include <string.h>
23
24
#include "libavutil/mem.h"
25
#include "audio_data.h"
26
27
static const AVClass audio_data_class = {
28
.class_name = "AudioData",
29
.item_name = av_default_item_name,
30
.version = LIBAVUTIL_VERSION_INT,
31
};
32
33
/*
34
* Calculate alignment for data pointers.
35
*/
36
static void calc_ptr_alignment(AudioData *a)
37
{
38
int p;
39
int min_align = 128;
40
41
for (p = 0; p < a->planes; p++) {
42
int cur_align = 128;
43
while ((intptr_t)a->data[p] % cur_align)
44
cur_align >>= 1;
45
if (cur_align < min_align)
46
min_align = cur_align;
47
}
48
a->ptr_align = min_align;
49
}
50
51
int ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt, int channels)
52
{
53
if (channels == 1)
54
return 1;
55
else
56
return av_sample_fmt_is_planar(sample_fmt);
57
}
58
59
int ff_audio_data_set_channels(AudioData *a, int channels)
60
{
61
if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS ||
62
channels > a->allocated_channels)
63
return AVERROR(EINVAL);
64
65
a->channels = channels;
66
a->planes = a->is_planar ? channels : 1;
67
68
calc_ptr_alignment(a);
69
70
return 0;
71
}
72
73
int ff_audio_data_init(AudioData *a, uint8_t * const *src, int plane_size,
74
int channels, int nb_samples,
75
enum AVSampleFormat sample_fmt, int read_only,
76
const char *name)
77
{
78
int p;
79
80
memset(a, 0, sizeof(*a));
81
a->class = &audio_data_class;
82
83
if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) {
84
av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels);
85
return AVERROR(EINVAL);
86
}
87
88
a->sample_size = av_get_bytes_per_sample(sample_fmt);
89
if (!a->sample_size) {
90
av_log(a, AV_LOG_ERROR, "invalid sample format\n");
91
return AVERROR(EINVAL);
92
}
93
a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
94
a->planes = a->is_planar ? channels : 1;
95
a->stride = a->sample_size * (a->is_planar ? 1 : channels);
96
97
for (p = 0; p < (a->is_planar ? channels : 1); p++) {
98
if (!src[p]) {
99
av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p);
100
return AVERROR(EINVAL);
101
}
102
a->data[p] = src[p];
103
}
104
a->allocated_samples = nb_samples * !read_only;
105
a->nb_samples = nb_samples;
106
a->sample_fmt = sample_fmt;
107
a->channels = channels;
108
a->allocated_channels = channels;
109
a->read_only = read_only;
110
a->allow_realloc = 0;
111
a->name = name ? name : "{no name}";
112
113
calc_ptr_alignment(a);
114
a->samples_align = plane_size / a->stride;
115
116
return 0;
117
}
118
119
AudioData *ff_audio_data_alloc(int channels, int nb_samples,
120
enum AVSampleFormat sample_fmt, const char *name)
121
{
122
AudioData *a;
123
int ret;
124
125
if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS)
126
return NULL;
127
128
a = av_mallocz(sizeof(*a));
129
if (!a)
130
return NULL;
131
132
a->sample_size = av_get_bytes_per_sample(sample_fmt);
133
if (!a->sample_size) {
134
av_free(a);
135
return NULL;
136
}
137
a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
138
a->planes = a->is_planar ? channels : 1;
139
a->stride = a->sample_size * (a->is_planar ? 1 : channels);
140
141
a->class = &audio_data_class;
142
a->sample_fmt = sample_fmt;
143
a->channels = channels;
144
a->allocated_channels = channels;
145
a->read_only = 0;
146
a->allow_realloc = 1;
147
a->name = name ? name : "{no name}";
148
149
if (nb_samples > 0) {
150
ret = ff_audio_data_realloc(a, nb_samples);
151
if (ret < 0) {
152
av_free(a);
153
return NULL;
154
}
155
return a;
156
} else {
157
calc_ptr_alignment(a);
158
return a;
159
}
160
}
161
162
int ff_audio_data_realloc(AudioData *a, int nb_samples)
163
{
164
int ret, new_buf_size, plane_size, p;
165
166
/* check if buffer is already large enough */
167
if (a->allocated_samples >= nb_samples)
168
return 0;
169
170
/* validate that the output is not read-only and realloc is allowed */
171
if (a->read_only || !a->allow_realloc)
172
return AVERROR(EINVAL);
173
174
new_buf_size = av_samples_get_buffer_size(&plane_size,
175
a->allocated_channels, nb_samples,
176
a->sample_fmt, 0);
177
if (new_buf_size < 0)
178
return new_buf_size;
179
180
/* if there is already data in the buffer and the sample format is planar,
181
allocate a new buffer and copy the data, otherwise just realloc the
182
internal buffer and set new data pointers */
183
if (a->nb_samples > 0 && a->is_planar) {
184
uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL };
185
186
ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels,
187
nb_samples, a->sample_fmt, 0);
188
if (ret < 0)
189
return ret;
190
191
for (p = 0; p < a->planes; p++)
192
memcpy(new_data[p], a->data[p], a->nb_samples * a->stride);
193
194
av_freep(&a->buffer);
195
memcpy(a->data, new_data, sizeof(new_data));
196
a->buffer = a->data[0];
197
} else {
198
av_freep(&a->buffer);
199
a->buffer = av_malloc(new_buf_size);
200
if (!a->buffer)
201
return AVERROR(ENOMEM);
202
ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer,
203
a->allocated_channels, nb_samples,
204
a->sample_fmt, 0);
205
if (ret < 0)
206
return ret;
207
}
208
a->buffer_size = new_buf_size;
209
a->allocated_samples = nb_samples;
210
211
calc_ptr_alignment(a);
212
a->samples_align = plane_size / a->stride;
213
214
return 0;
215
}
216
217
void ff_audio_data_free(AudioData **a)
218
{
219
if (!*a)
220
return;
221
av_free((*a)->buffer);
222
av_freep(a);
223
}
224
225
int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
226
{
227
int ret, p;
228
229
/* validate input/output compatibility */
230
if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
231
return AVERROR(EINVAL);
232
233
if (map && !src->is_planar) {
234
av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
235
return AVERROR(EINVAL);
236
}
237
238
/* if the input is empty, just empty the output */
239
if (!src->nb_samples) {
240
dst->nb_samples = 0;
241
return 0;
242
}
243
244
/* reallocate output if necessary */
245
ret = ff_audio_data_realloc(dst, src->nb_samples);
246
if (ret < 0)
247
return ret;
248
249
/* copy data */
250
if (map) {
251
if (map->do_remap) {
252
for (p = 0; p < src->planes; p++) {
253
if (map->channel_map[p] >= 0)
254
memcpy(dst->data[p], src->data[map->channel_map[p]],
255
src->nb_samples * src->stride);
256
}
257
}
258
if (map->do_copy || map->do_zero) {
259
for (p = 0; p < src->planes; p++) {
260
if (map->channel_copy[p])
261
memcpy(dst->data[p], dst->data[map->channel_copy[p]],
262
src->nb_samples * src->stride);
263
else if (map->channel_zero[p])
264
av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
265
1, dst->sample_fmt);
266
}
267
}
268
} else {
269
for (p = 0; p < src->planes; p++)
270
memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
271
}
272
273
dst->nb_samples = src->nb_samples;
274
275
return 0;
276
}
277
278
int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
279
int src_offset, int nb_samples)
280
{
281
int ret, p, dst_offset2, dst_move_size;
282
283
/* validate input/output compatibility */
284
if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
285
av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
286
return AVERROR(EINVAL);
287
}
288
289
/* validate offsets are within the buffer bounds */
290
if (dst_offset < 0 || dst_offset > dst->nb_samples ||
291
src_offset < 0 || src_offset > src->nb_samples) {
292
av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
293
src_offset, dst_offset);
294
return AVERROR(EINVAL);
295
}
296
297
/* check offsets and sizes to see if we can just do nothing and return */
298
if (nb_samples > src->nb_samples - src_offset)
299
nb_samples = src->nb_samples - src_offset;
300
if (nb_samples <= 0)
301
return 0;
302
303
/* validate that the output is not read-only */
304
if (dst->read_only) {
305
av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
306
return AVERROR(EINVAL);
307
}
308
309
/* reallocate output if necessary */
310
ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
311
if (ret < 0) {
312
av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
313
return ret;
314
}
315
316
dst_offset2 = dst_offset + nb_samples;
317
dst_move_size = dst->nb_samples - dst_offset;
318
319
for (p = 0; p < src->planes; p++) {
320
if (dst_move_size > 0) {
321
memmove(dst->data[p] + dst_offset2 * dst->stride,
322
dst->data[p] + dst_offset * dst->stride,
323
dst_move_size * dst->stride);
324
}
325
memcpy(dst->data[p] + dst_offset * dst->stride,
326
src->data[p] + src_offset * src->stride,
327
nb_samples * src->stride);
328
}
329
dst->nb_samples += nb_samples;
330
331
return 0;
332
}
333
334
void ff_audio_data_drain(AudioData *a, int nb_samples)
335
{
336
if (a->nb_samples <= nb_samples) {
337
/* drain the whole buffer */
338
a->nb_samples = 0;
339
} else {
340
int p;
341
int move_offset = a->stride * nb_samples;
342
int move_size = a->stride * (a->nb_samples - nb_samples);
343
344
for (p = 0; p < a->planes; p++)
345
memmove(a->data[p], a->data[p] + move_offset, move_size);
346
347
a->nb_samples -= nb_samples;
348
}
349
}
350
351
int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
352
int nb_samples)
353
{
354
uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
355
int offset_size, p;
356
357
if (offset >= a->nb_samples)
358
return 0;
359
offset_size = offset * a->stride;
360
for (p = 0; p < a->planes; p++)
361
offset_data[p] = a->data[p] + offset_size;
362
363
return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
364
}
365
366
int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples)
367
{
368
int ret;
369
370
if (a->read_only)
371
return AVERROR(EINVAL);
372
373
ret = ff_audio_data_realloc(a, nb_samples);
374
if (ret < 0)
375
return ret;
376
377
ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
378
if (ret >= 0)
379
a->nb_samples = ret;
380
return ret;
381
}
382
383