Imported Debian version 2.4.3~trusty1
[deb_ffmpeg.git] / ffmpeg / libavresample / audio_data.c
CommitLineData
2ba45a60
DM
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
27static 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 */
36static 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
51int 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
59int 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
73int ff_audio_data_init(AudioData *a, uint8_t **src, int plane_size, int channels,
74 int nb_samples, enum AVSampleFormat sample_fmt,
75 int read_only, const char *name)
76{
77 int p;
78
79 memset(a, 0, sizeof(*a));
80 a->class = &audio_data_class;
81
82 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) {
83 av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels);
84 return AVERROR(EINVAL);
85 }
86
87 a->sample_size = av_get_bytes_per_sample(sample_fmt);
88 if (!a->sample_size) {
89 av_log(a, AV_LOG_ERROR, "invalid sample format\n");
90 return AVERROR(EINVAL);
91 }
92 a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
93 a->planes = a->is_planar ? channels : 1;
94 a->stride = a->sample_size * (a->is_planar ? 1 : channels);
95
96 for (p = 0; p < (a->is_planar ? channels : 1); p++) {
97 if (!src[p]) {
98 av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p);
99 return AVERROR(EINVAL);
100 }
101 a->data[p] = src[p];
102 }
103 a->allocated_samples = nb_samples * !read_only;
104 a->nb_samples = nb_samples;
105 a->sample_fmt = sample_fmt;
106 a->channels = channels;
107 a->allocated_channels = channels;
108 a->read_only = read_only;
109 a->allow_realloc = 0;
110 a->name = name ? name : "{no name}";
111
112 calc_ptr_alignment(a);
113 a->samples_align = plane_size / a->stride;
114
115 return 0;
116}
117
118AudioData *ff_audio_data_alloc(int channels, int nb_samples,
119 enum AVSampleFormat sample_fmt, const char *name)
120{
121 AudioData *a;
122 int ret;
123
124 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS)
125 return NULL;
126
127 a = av_mallocz(sizeof(*a));
128 if (!a)
129 return NULL;
130
131 a->sample_size = av_get_bytes_per_sample(sample_fmt);
132 if (!a->sample_size) {
133 av_free(a);
134 return NULL;
135 }
136 a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
137 a->planes = a->is_planar ? channels : 1;
138 a->stride = a->sample_size * (a->is_planar ? 1 : channels);
139
140 a->class = &audio_data_class;
141 a->sample_fmt = sample_fmt;
142 a->channels = channels;
143 a->allocated_channels = channels;
144 a->read_only = 0;
145 a->allow_realloc = 1;
146 a->name = name ? name : "{no name}";
147
148 if (nb_samples > 0) {
149 ret = ff_audio_data_realloc(a, nb_samples);
150 if (ret < 0) {
151 av_free(a);
152 return NULL;
153 }
154 return a;
155 } else {
156 calc_ptr_alignment(a);
157 return a;
158 }
159}
160
161int ff_audio_data_realloc(AudioData *a, int nb_samples)
162{
163 int ret, new_buf_size, plane_size, p;
164
165 /* check if buffer is already large enough */
166 if (a->allocated_samples >= nb_samples)
167 return 0;
168
169 /* validate that the output is not read-only and realloc is allowed */
170 if (a->read_only || !a->allow_realloc)
171 return AVERROR(EINVAL);
172
173 new_buf_size = av_samples_get_buffer_size(&plane_size,
174 a->allocated_channels, nb_samples,
175 a->sample_fmt, 0);
176 if (new_buf_size < 0)
177 return new_buf_size;
178
179 /* if there is already data in the buffer and the sample format is planar,
180 allocate a new buffer and copy the data, otherwise just realloc the
181 internal buffer and set new data pointers */
182 if (a->nb_samples > 0 && a->is_planar) {
183 uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL };
184
185 ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels,
186 nb_samples, a->sample_fmt, 0);
187 if (ret < 0)
188 return ret;
189
190 for (p = 0; p < a->planes; p++)
191 memcpy(new_data[p], a->data[p], a->nb_samples * a->stride);
192
193 av_freep(&a->buffer);
194 memcpy(a->data, new_data, sizeof(new_data));
195 a->buffer = a->data[0];
196 } else {
197 av_freep(&a->buffer);
198 a->buffer = av_malloc(new_buf_size);
199 if (!a->buffer)
200 return AVERROR(ENOMEM);
201 ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer,
202 a->allocated_channels, nb_samples,
203 a->sample_fmt, 0);
204 if (ret < 0)
205 return ret;
206 }
207 a->buffer_size = new_buf_size;
208 a->allocated_samples = nb_samples;
209
210 calc_ptr_alignment(a);
211 a->samples_align = plane_size / a->stride;
212
213 return 0;
214}
215
216void ff_audio_data_free(AudioData **a)
217{
218 if (!*a)
219 return;
220 av_free((*a)->buffer);
221 av_freep(a);
222}
223
224int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
225{
226 int ret, p;
227
228 /* validate input/output compatibility */
229 if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
230 return AVERROR(EINVAL);
231
232 if (map && !src->is_planar) {
233 av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
234 return AVERROR(EINVAL);
235 }
236
237 /* if the input is empty, just empty the output */
238 if (!src->nb_samples) {
239 dst->nb_samples = 0;
240 return 0;
241 }
242
243 /* reallocate output if necessary */
244 ret = ff_audio_data_realloc(dst, src->nb_samples);
245 if (ret < 0)
246 return ret;
247
248 /* copy data */
249 if (map) {
250 if (map->do_remap) {
251 for (p = 0; p < src->planes; p++) {
252 if (map->channel_map[p] >= 0)
253 memcpy(dst->data[p], src->data[map->channel_map[p]],
254 src->nb_samples * src->stride);
255 }
256 }
257 if (map->do_copy || map->do_zero) {
258 for (p = 0; p < src->planes; p++) {
259 if (map->channel_copy[p])
260 memcpy(dst->data[p], dst->data[map->channel_copy[p]],
261 src->nb_samples * src->stride);
262 else if (map->channel_zero[p])
263 av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
264 1, dst->sample_fmt);
265 }
266 }
267 } else {
268 for (p = 0; p < src->planes; p++)
269 memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
270 }
271
272 dst->nb_samples = src->nb_samples;
273
274 return 0;
275}
276
277int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
278 int src_offset, int nb_samples)
279{
280 int ret, p, dst_offset2, dst_move_size;
281
282 /* validate input/output compatibility */
283 if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
284 av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
285 return AVERROR(EINVAL);
286 }
287
288 /* validate offsets are within the buffer bounds */
289 if (dst_offset < 0 || dst_offset > dst->nb_samples ||
290 src_offset < 0 || src_offset > src->nb_samples) {
291 av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
292 src_offset, dst_offset);
293 return AVERROR(EINVAL);
294 }
295
296 /* check offsets and sizes to see if we can just do nothing and return */
297 if (nb_samples > src->nb_samples - src_offset)
298 nb_samples = src->nb_samples - src_offset;
299 if (nb_samples <= 0)
300 return 0;
301
302 /* validate that the output is not read-only */
303 if (dst->read_only) {
304 av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
305 return AVERROR(EINVAL);
306 }
307
308 /* reallocate output if necessary */
309 ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
310 if (ret < 0) {
311 av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
312 return ret;
313 }
314
315 dst_offset2 = dst_offset + nb_samples;
316 dst_move_size = dst->nb_samples - dst_offset;
317
318 for (p = 0; p < src->planes; p++) {
319 if (dst_move_size > 0) {
320 memmove(dst->data[p] + dst_offset2 * dst->stride,
321 dst->data[p] + dst_offset * dst->stride,
322 dst_move_size * dst->stride);
323 }
324 memcpy(dst->data[p] + dst_offset * dst->stride,
325 src->data[p] + src_offset * src->stride,
326 nb_samples * src->stride);
327 }
328 dst->nb_samples += nb_samples;
329
330 return 0;
331}
332
333void ff_audio_data_drain(AudioData *a, int nb_samples)
334{
335 if (a->nb_samples <= nb_samples) {
336 /* drain the whole buffer */
337 a->nb_samples = 0;
338 } else {
339 int p;
340 int move_offset = a->stride * nb_samples;
341 int move_size = a->stride * (a->nb_samples - nb_samples);
342
343 for (p = 0; p < a->planes; p++)
344 memmove(a->data[p], a->data[p] + move_offset, move_size);
345
346 a->nb_samples -= nb_samples;
347 }
348}
349
350int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
351 int nb_samples)
352{
353 uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
354 int offset_size, p;
355
356 if (offset >= a->nb_samples)
357 return 0;
358 offset_size = offset * a->stride;
359 for (p = 0; p < a->planes; p++)
360 offset_data[p] = a->data[p] + offset_size;
361
362 return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
363}
364
365int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples)
366{
367 int ret;
368
369 if (a->read_only)
370 return AVERROR(EINVAL);
371
372 ret = ff_audio_data_realloc(a, nb_samples);
373 if (ret < 0)
374 return ret;
375
376 ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
377 if (ret >= 0)
378 a->nb_samples = ret;
379 return ret;
380}