FFmpeg
 All Data Structures 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 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  */
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;
97  a->sample_fmt = sample_fmt;
98  a->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 
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;
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 
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;
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 the input is empty, just empty the output */
225  if (!src->nb_samples) {
226  dst->nb_samples = 0;
227  return 0;
228  }
229 
230  /* reallocate output if necessary */
231  ret = ff_audio_data_realloc(dst, src->nb_samples);
232  if (ret < 0)
233  return ret;
234 
235  /* copy data */
236  for (p = 0; p < src->planes; p++)
237  memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
238  dst->nb_samples = src->nb_samples;
239 
240  return 0;
241 }
242 
243 int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
244  int src_offset, int nb_samples)
245 {
246  int ret, p, dst_offset2, dst_move_size;
247 
248  /* validate input/output compatibility */
249  if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
250  av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
251  return AVERROR(EINVAL);
252  }
253 
254  /* validate offsets are within the buffer bounds */
255  if (dst_offset < 0 || dst_offset > dst->nb_samples ||
256  src_offset < 0 || src_offset > src->nb_samples) {
257  av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
258  src_offset, dst_offset);
259  return AVERROR(EINVAL);
260  }
261 
262  /* check offsets and sizes to see if we can just do nothing and return */
263  if (nb_samples > src->nb_samples - src_offset)
264  nb_samples = src->nb_samples - src_offset;
265  if (nb_samples <= 0)
266  return 0;
267 
268  /* validate that the output is not read-only */
269  if (dst->read_only) {
270  av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
271  return AVERROR(EINVAL);
272  }
273 
274  /* reallocate output if necessary */
275  ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
276  if (ret < 0) {
277  av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
278  return ret;
279  }
280 
281  dst_offset2 = dst_offset + nb_samples;
282  dst_move_size = dst->nb_samples - dst_offset;
283 
284  for (p = 0; p < src->planes; p++) {
285  if (dst_move_size > 0) {
286  memmove(dst->data[p] + dst_offset2 * dst->stride,
287  dst->data[p] + dst_offset * dst->stride,
288  dst_move_size * dst->stride);
289  }
290  memcpy(dst->data[p] + dst_offset * dst->stride,
291  src->data[p] + src_offset * src->stride,
292  nb_samples * src->stride);
293  }
294  dst->nb_samples += nb_samples;
295 
296  return 0;
297 }
298 
300 {
301  if (a->nb_samples <= nb_samples) {
302  /* drain the whole buffer */
303  a->nb_samples = 0;
304  } else {
305  int p;
306  int move_offset = a->stride * nb_samples;
307  int move_size = a->stride * (a->nb_samples - nb_samples);
308 
309  for (p = 0; p < a->planes; p++)
310  memmove(a->data[p], a->data[p] + move_offset, move_size);
311 
312  a->nb_samples -= nb_samples;
313  }
314 }
315 
317  int nb_samples)
318 {
319  uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
320  int offset_size, p;
321 
322  if (offset >= a->nb_samples)
323  return 0;
324  offset_size = offset * a->stride;
325  for (p = 0; p < a->planes; p++)
326  offset_data[p] = a->data[p] + offset_size;
327 
328  return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
329 }
330 
332 {
333  int ret;
334 
335  if (a->read_only)
336  return AVERROR(EINVAL);
337 
338  ret = ff_audio_data_realloc(a, nb_samples);
339  if (ret < 0)
340  return ret;
341 
342  ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
343  if (ret >= 0)
344  a->nb_samples = ret;
345  return ret;
346 }