FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
audio_data.c
Go to the documentation of this file.
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  */
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 
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 
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 
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 {
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 
203  a->samples_align = plane_size / a->stride;
204 
205  return 0;
206 }
207 
209 {
210  if (!*a)
211  return;
212  av_free((*a)->buffer);
213  av_freep(a);
214 }
215 
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 
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 
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 }