• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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