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