1 /*
2 * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
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 */
calc_ptr_alignment(AudioData * a)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
ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt,int channels)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
ff_audio_data_set_channels(AudioData * a,int channels)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
ff_audio_data_init(AudioData * a,uint8_t * const * src,int plane_size,int channels,int nb_samples,enum AVSampleFormat sample_fmt,int read_only,const char * name)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
ff_audio_data_alloc(int channels,int nb_samples,enum AVSampleFormat sample_fmt,const char * name)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
ff_audio_data_realloc(AudioData * a,int nb_samples)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
ff_audio_data_free(AudioData ** a)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
ff_audio_data_copy(AudioData * dst,AudioData * src,ChannelMapInfo * map)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
ff_audio_data_combine(AudioData * dst,int dst_offset,AudioData * src,int src_offset,int nb_samples)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
ff_audio_data_drain(AudioData * a,int nb_samples)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
ff_audio_data_add_to_fifo(AVAudioFifo * af,AudioData * a,int offset,int nb_samples)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
ff_audio_data_read_from_fifo(AVAudioFifo * af,AudioData * a,int nb_samples)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