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 
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 
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 
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 
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 {
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 
211  a->samples_align = plane_size / a->stride;
212 
213  return 0;
214 }
215 
217 {
218  if (!*a)
219  return;
220  av_free((*a)->buffer);
221  av_freep(a);
222 }
223 
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 
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 
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 }