Add libavresample
[libav.git] / libavresample / audio_data.c
1 /*
2 * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
3 *
4 * This file is part of Libav.
5 *
6 * Libav 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 * Libav 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 Libav; 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
23 #include "libavutil/mem.h"
24 #include "audio_data.h"
25
26 static const AVClass audio_data_class = {
27 .class_name = "AudioData",
28 .item_name = av_default_item_name,
29 .version = LIBAVUTIL_VERSION_INT,
30 };
31
32 /*
33 * Calculate alignment for data pointers.
34 */
35 static void calc_ptr_alignment(AudioData *a)
36 {
37 int p;
38 int min_align = 128;
39
40 for (p = 0; p < a->planes; p++) {
41 int cur_align = 128;
42 while ((intptr_t)a->data[p] % cur_align)
43 cur_align >>= 1;
44 if (cur_align < min_align)
45 min_align = cur_align;
46 }
47 a->ptr_align = min_align;
48 }
49
50 int ff_audio_data_set_channels(AudioData *a, int channels)
51 {
52 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS ||
53 channels > a->allocated_channels)
54 return AVERROR(EINVAL);
55
56 a->channels = channels;
57 a->planes = a->is_planar ? channels : 1;
58
59 calc_ptr_alignment(a);
60
61 return 0;
62 }
63
64 int ff_audio_data_init(AudioData *a, void **src, int plane_size, int channels,
65 int nb_samples, enum AVSampleFormat sample_fmt,
66 int read_only, const char *name)
67 {
68 int p;
69
70 memset(a, 0, sizeof(*a));
71 a->class = &audio_data_class;
72
73 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) {
74 av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels);
75 return AVERROR(EINVAL);
76 }
77
78 a->sample_size = av_get_bytes_per_sample(sample_fmt);
79 if (!a->sample_size) {
80 av_log(a, AV_LOG_ERROR, "invalid sample format\n");
81 return AVERROR(EINVAL);
82 }
83 a->is_planar = av_sample_fmt_is_planar(sample_fmt);
84 a->planes = a->is_planar ? channels : 1;
85 a->stride = a->sample_size * (a->is_planar ? 1 : channels);
86
87 for (p = 0; p < (a->is_planar ? channels : 1); p++) {
88 if (!src[p]) {
89 av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p);
90 return AVERROR(EINVAL);
91 }
92 a->data[p] = src[p];
93 }
94 a->allocated_samples = nb_samples * !read_only;
95 a->nb_samples = nb_samples;
96 a->sample_fmt = sample_fmt;
97 a->channels = channels;
98 a->allocated_channels = channels;
99 a->read_only = read_only;
100 a->allow_realloc = 0;
101 a->name = name ? name : "{no name}";
102
103 calc_ptr_alignment(a);
104 a->samples_align = plane_size / a->stride;
105
106 return 0;
107 }
108
109 AudioData *ff_audio_data_alloc(int channels, int nb_samples,
110 enum AVSampleFormat sample_fmt, const char *name)
111 {
112 AudioData *a;
113 int ret;
114
115 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS)
116 return NULL;
117
118 a = av_mallocz(sizeof(*a));
119 if (!a)
120 return NULL;
121
122 a->sample_size = av_get_bytes_per_sample(sample_fmt);
123 if (!a->sample_size) {
124 av_free(a);
125 return NULL;
126 }
127 a->is_planar = av_sample_fmt_is_planar(sample_fmt);
128 a->planes = a->is_planar ? channels : 1;
129 a->stride = a->sample_size * (a->is_planar ? 1 : channels);
130
131 a->class = &audio_data_class;
132 a->sample_fmt = sample_fmt;
133 a->channels = channels;
134 a->allocated_channels = channels;
135 a->read_only = 0;
136 a->allow_realloc = 1;
137 a->name = name ? name : "{no name}";
138
139 if (nb_samples > 0) {
140 ret = ff_audio_data_realloc(a, nb_samples);
141 if (ret < 0) {
142 av_free(a);
143 return NULL;
144 }
145 return a;
146 } else {
147 calc_ptr_alignment(a);
148 return a;
149 }
150 }
151
152 int ff_audio_data_realloc(AudioData *a, int nb_samples)
153 {
154 int ret, new_buf_size, plane_size, p;
155
156 /* check if buffer is already large enough */
157 if (a->allocated_samples >= nb_samples)
158 return 0;
159
160 /* validate that the output is not read-only and realloc is allowed */
161 if (a->read_only || !a->allow_realloc)
162 return AVERROR(EINVAL);
163
164 new_buf_size = av_samples_get_buffer_size(&plane_size,
165 a->allocated_channels, nb_samples,
166 a->sample_fmt, 0);
167 if (new_buf_size < 0)
168 return new_buf_size;
169
170 /* if there is already data in the buffer and the sample format is planar,
171 allocate a new buffer and copy the data, otherwise just realloc the
172 internal buffer and set new data pointers */
173 if (a->nb_samples > 0 && a->is_planar) {
174 uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL };
175
176 ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels,
177 nb_samples, a->sample_fmt, 0);
178 if (ret < 0)
179 return ret;
180
181 for (p = 0; p < a->planes; p++)
182 memcpy(new_data[p], a->data[p], a->nb_samples * a->stride);
183
184 av_freep(&a->buffer);
185 memcpy(a->data, new_data, sizeof(new_data));
186 a->buffer = a->data[0];
187 } else {
188 av_freep(&a->buffer);
189 a->buffer = av_malloc(new_buf_size);
190 if (!a->buffer)
191 return AVERROR(ENOMEM);
192 ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer,
193 a->allocated_channels, nb_samples,
194 a->sample_fmt, 0);
195 if (ret < 0)
196 return ret;
197 }
198 a->buffer_size = new_buf_size;
199 a->allocated_samples = nb_samples;
200
201 calc_ptr_alignment(a);
202 a->samples_align = plane_size / a->stride;
203
204 return 0;
205 }
206
207 void ff_audio_data_free(AudioData **a)
208 {
209 if (!*a)
210 return;
211 av_free((*a)->buffer);
212 av_freep(a);
213 }
214
215 int ff_audio_data_copy(AudioData *dst, AudioData *src)
216 {
217 int ret, p;
218
219 /* validate input/output compatibility */
220 if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
221 return AVERROR(EINVAL);
222
223 /* if the input is empty, just empty the output */
224 if (!src->nb_samples) {
225 dst->nb_samples = 0;
226 return 0;
227 }
228
229 /* reallocate output if necessary */
230 ret = ff_audio_data_realloc(dst, src->nb_samples);
231 if (ret < 0)
232 return ret;
233
234 /* copy data */
235 for (p = 0; p < src->planes; p++)
236 memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
237 dst->nb_samples = src->nb_samples;
238
239 return 0;
240 }
241
242 int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
243 int src_offset, int nb_samples)
244 {
245 int ret, p, dst_offset2, dst_move_size;
246
247 /* validate input/output compatibility */
248 if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
249 av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
250 return AVERROR(EINVAL);
251 }
252
253 /* validate offsets are within the buffer bounds */
254 if (dst_offset < 0 || dst_offset > dst->nb_samples ||
255 src_offset < 0 || src_offset > src->nb_samples) {
256 av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
257 src_offset, dst_offset);
258 return AVERROR(EINVAL);
259 }
260
261 /* check offsets and sizes to see if we can just do nothing and return */
262 if (nb_samples > src->nb_samples - src_offset)
263 nb_samples = src->nb_samples - src_offset;
264 if (nb_samples <= 0)
265 return 0;
266
267 /* validate that the output is not read-only */
268 if (dst->read_only) {
269 av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
270 return AVERROR(EINVAL);
271 }
272
273 /* reallocate output if necessary */
274 ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
275 if (ret < 0) {
276 av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
277 return ret;
278 }
279
280 dst_offset2 = dst_offset + nb_samples;
281 dst_move_size = dst->nb_samples - dst_offset;
282
283 for (p = 0; p < src->planes; p++) {
284 if (dst_move_size > 0) {
285 memmove(dst->data[p] + dst_offset2 * dst->stride,
286 dst->data[p] + dst_offset * dst->stride,
287 dst_move_size * dst->stride);
288 }
289 memcpy(dst->data[p] + dst_offset * dst->stride,
290 src->data[p] + src_offset * src->stride,
291 nb_samples * src->stride);
292 }
293 dst->nb_samples += nb_samples;
294
295 return 0;
296 }
297
298 void ff_audio_data_drain(AudioData *a, int nb_samples)
299 {
300 if (a->nb_samples <= nb_samples) {
301 /* drain the whole buffer */
302 a->nb_samples = 0;
303 } else {
304 int p;
305 int move_offset = a->stride * nb_samples;
306 int move_size = a->stride * (a->nb_samples - nb_samples);
307
308 for (p = 0; p < a->planes; p++)
309 memmove(a->data[p], a->data[p] + move_offset, move_size);
310
311 a->nb_samples -= nb_samples;
312 }
313 }
314
315 int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
316 int nb_samples)
317 {
318 uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
319 int offset_size, p;
320
321 if (offset >= a->nb_samples)
322 return 0;
323 offset_size = offset * a->stride;
324 for (p = 0; p < a->planes; p++)
325 offset_data[p] = a->data[p] + offset_size;
326
327 return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
328 }
329
330 int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples)
331 {
332 int ret;
333
334 if (a->read_only)
335 return AVERROR(EINVAL);
336
337 ret = ff_audio_data_realloc(a, nb_samples);
338 if (ret < 0)
339 return ret;
340
341 ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
342 if (ret >= 0)
343 a->nb_samples = ret;
344 return ret;
345 }