]> git.sesse.net Git - ffmpeg/blob - libavresample/audio_data.c
Replace lena.pnm
[ffmpeg] / 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 #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 **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
118 AudioData *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
161 int 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
216 void ff_audio_data_free(AudioData **a)
217 {
218     if (!*a)
219         return;
220     av_free((*a)->buffer);
221     av_freep(a);
222 }
223
224 int 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
277 int 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
333 void 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
350 int 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
365 int 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 }