yading@11
|
1 /*
|
yading@11
|
2 * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
|
yading@11
|
3 *
|
yading@11
|
4 * This file is part of Libav.
|
yading@11
|
5 *
|
yading@11
|
6 * Libav is free software; you can redistribute it and/or
|
yading@11
|
7 * modify it under the terms of the GNU Lesser General Public
|
yading@11
|
8 * License as published by the Free Software Foundation; either
|
yading@11
|
9 * version 2.1 of the License, or (at your option) any later version.
|
yading@11
|
10 *
|
yading@11
|
11 * Libav is distributed in the hope that it will be useful,
|
yading@11
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@11
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@11
|
14 * Lesser General Public License for more details.
|
yading@11
|
15 *
|
yading@11
|
16 * You should have received a copy of the GNU Lesser General Public
|
yading@11
|
17 * License along with Libav; if not, write to the Free Software
|
yading@11
|
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@11
|
19 */
|
yading@11
|
20
|
yading@11
|
21 #include <stdint.h>
|
yading@11
|
22 #include <string.h>
|
yading@11
|
23
|
yading@11
|
24 #include "libavutil/mem.h"
|
yading@11
|
25 #include "audio_data.h"
|
yading@11
|
26
|
yading@11
|
27 static const AVClass audio_data_class = {
|
yading@11
|
28 .class_name = "AudioData",
|
yading@11
|
29 .item_name = av_default_item_name,
|
yading@11
|
30 .version = LIBAVUTIL_VERSION_INT,
|
yading@11
|
31 };
|
yading@11
|
32
|
yading@11
|
33 /*
|
yading@11
|
34 * Calculate alignment for data pointers.
|
yading@11
|
35 */
|
yading@11
|
36 static void calc_ptr_alignment(AudioData *a)
|
yading@11
|
37 {
|
yading@11
|
38 int p;
|
yading@11
|
39 int min_align = 128;
|
yading@11
|
40
|
yading@11
|
41 for (p = 0; p < a->planes; p++) {
|
yading@11
|
42 int cur_align = 128;
|
yading@11
|
43 while ((intptr_t)a->data[p] % cur_align)
|
yading@11
|
44 cur_align >>= 1;
|
yading@11
|
45 if (cur_align < min_align)
|
yading@11
|
46 min_align = cur_align;
|
yading@11
|
47 }
|
yading@11
|
48 a->ptr_align = min_align;
|
yading@11
|
49 }
|
yading@11
|
50
|
yading@11
|
51 int ff_audio_data_set_channels(AudioData *a, int channels)
|
yading@11
|
52 {
|
yading@11
|
53 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS ||
|
yading@11
|
54 channels > a->allocated_channels)
|
yading@11
|
55 return AVERROR(EINVAL);
|
yading@11
|
56
|
yading@11
|
57 a->channels = channels;
|
yading@11
|
58 a->planes = a->is_planar ? channels : 1;
|
yading@11
|
59
|
yading@11
|
60 calc_ptr_alignment(a);
|
yading@11
|
61
|
yading@11
|
62 return 0;
|
yading@11
|
63 }
|
yading@11
|
64
|
yading@11
|
65 int ff_audio_data_init(AudioData *a, uint8_t **src, int plane_size, int channels,
|
yading@11
|
66 int nb_samples, enum AVSampleFormat sample_fmt,
|
yading@11
|
67 int read_only, const char *name)
|
yading@11
|
68 {
|
yading@11
|
69 int p;
|
yading@11
|
70
|
yading@11
|
71 memset(a, 0, sizeof(*a));
|
yading@11
|
72 a->class = &audio_data_class;
|
yading@11
|
73
|
yading@11
|
74 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) {
|
yading@11
|
75 av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels);
|
yading@11
|
76 return AVERROR(EINVAL);
|
yading@11
|
77 }
|
yading@11
|
78
|
yading@11
|
79 a->sample_size = av_get_bytes_per_sample(sample_fmt);
|
yading@11
|
80 if (!a->sample_size) {
|
yading@11
|
81 av_log(a, AV_LOG_ERROR, "invalid sample format\n");
|
yading@11
|
82 return AVERROR(EINVAL);
|
yading@11
|
83 }
|
yading@11
|
84 a->is_planar = av_sample_fmt_is_planar(sample_fmt);
|
yading@11
|
85 a->planes = a->is_planar ? channels : 1;
|
yading@11
|
86 a->stride = a->sample_size * (a->is_planar ? 1 : channels);
|
yading@11
|
87
|
yading@11
|
88 for (p = 0; p < (a->is_planar ? channels : 1); p++) {
|
yading@11
|
89 if (!src[p]) {
|
yading@11
|
90 av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p);
|
yading@11
|
91 return AVERROR(EINVAL);
|
yading@11
|
92 }
|
yading@11
|
93 a->data[p] = src[p];
|
yading@11
|
94 }
|
yading@11
|
95 a->allocated_samples = nb_samples * !read_only;
|
yading@11
|
96 a->nb_samples = nb_samples;
|
yading@11
|
97 a->sample_fmt = sample_fmt;
|
yading@11
|
98 a->channels = channels;
|
yading@11
|
99 a->allocated_channels = channels;
|
yading@11
|
100 a->read_only = read_only;
|
yading@11
|
101 a->allow_realloc = 0;
|
yading@11
|
102 a->name = name ? name : "{no name}";
|
yading@11
|
103
|
yading@11
|
104 calc_ptr_alignment(a);
|
yading@11
|
105 a->samples_align = plane_size / a->stride;
|
yading@11
|
106
|
yading@11
|
107 return 0;
|
yading@11
|
108 }
|
yading@11
|
109
|
yading@11
|
110 AudioData *ff_audio_data_alloc(int channels, int nb_samples,
|
yading@11
|
111 enum AVSampleFormat sample_fmt, const char *name)
|
yading@11
|
112 {
|
yading@11
|
113 AudioData *a;
|
yading@11
|
114 int ret;
|
yading@11
|
115
|
yading@11
|
116 if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS)
|
yading@11
|
117 return NULL;
|
yading@11
|
118
|
yading@11
|
119 a = av_mallocz(sizeof(*a));
|
yading@11
|
120 if (!a)
|
yading@11
|
121 return NULL;
|
yading@11
|
122
|
yading@11
|
123 a->sample_size = av_get_bytes_per_sample(sample_fmt);
|
yading@11
|
124 if (!a->sample_size) {
|
yading@11
|
125 av_free(a);
|
yading@11
|
126 return NULL;
|
yading@11
|
127 }
|
yading@11
|
128 a->is_planar = av_sample_fmt_is_planar(sample_fmt);
|
yading@11
|
129 a->planes = a->is_planar ? channels : 1;
|
yading@11
|
130 a->stride = a->sample_size * (a->is_planar ? 1 : channels);
|
yading@11
|
131
|
yading@11
|
132 a->class = &audio_data_class;
|
yading@11
|
133 a->sample_fmt = sample_fmt;
|
yading@11
|
134 a->channels = channels;
|
yading@11
|
135 a->allocated_channels = channels;
|
yading@11
|
136 a->read_only = 0;
|
yading@11
|
137 a->allow_realloc = 1;
|
yading@11
|
138 a->name = name ? name : "{no name}";
|
yading@11
|
139
|
yading@11
|
140 if (nb_samples > 0) {
|
yading@11
|
141 ret = ff_audio_data_realloc(a, nb_samples);
|
yading@11
|
142 if (ret < 0) {
|
yading@11
|
143 av_free(a);
|
yading@11
|
144 return NULL;
|
yading@11
|
145 }
|
yading@11
|
146 return a;
|
yading@11
|
147 } else {
|
yading@11
|
148 calc_ptr_alignment(a);
|
yading@11
|
149 return a;
|
yading@11
|
150 }
|
yading@11
|
151 }
|
yading@11
|
152
|
yading@11
|
153 int ff_audio_data_realloc(AudioData *a, int nb_samples)
|
yading@11
|
154 {
|
yading@11
|
155 int ret, new_buf_size, plane_size, p;
|
yading@11
|
156
|
yading@11
|
157 /* check if buffer is already large enough */
|
yading@11
|
158 if (a->allocated_samples >= nb_samples)
|
yading@11
|
159 return 0;
|
yading@11
|
160
|
yading@11
|
161 /* validate that the output is not read-only and realloc is allowed */
|
yading@11
|
162 if (a->read_only || !a->allow_realloc)
|
yading@11
|
163 return AVERROR(EINVAL);
|
yading@11
|
164
|
yading@11
|
165 new_buf_size = av_samples_get_buffer_size(&plane_size,
|
yading@11
|
166 a->allocated_channels, nb_samples,
|
yading@11
|
167 a->sample_fmt, 0);
|
yading@11
|
168 if (new_buf_size < 0)
|
yading@11
|
169 return new_buf_size;
|
yading@11
|
170
|
yading@11
|
171 /* if there is already data in the buffer and the sample format is planar,
|
yading@11
|
172 allocate a new buffer and copy the data, otherwise just realloc the
|
yading@11
|
173 internal buffer and set new data pointers */
|
yading@11
|
174 if (a->nb_samples > 0 && a->is_planar) {
|
yading@11
|
175 uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL };
|
yading@11
|
176
|
yading@11
|
177 ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels,
|
yading@11
|
178 nb_samples, a->sample_fmt, 0);
|
yading@11
|
179 if (ret < 0)
|
yading@11
|
180 return ret;
|
yading@11
|
181
|
yading@11
|
182 for (p = 0; p < a->planes; p++)
|
yading@11
|
183 memcpy(new_data[p], a->data[p], a->nb_samples * a->stride);
|
yading@11
|
184
|
yading@11
|
185 av_freep(&a->buffer);
|
yading@11
|
186 memcpy(a->data, new_data, sizeof(new_data));
|
yading@11
|
187 a->buffer = a->data[0];
|
yading@11
|
188 } else {
|
yading@11
|
189 av_freep(&a->buffer);
|
yading@11
|
190 a->buffer = av_malloc(new_buf_size);
|
yading@11
|
191 if (!a->buffer)
|
yading@11
|
192 return AVERROR(ENOMEM);
|
yading@11
|
193 ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer,
|
yading@11
|
194 a->allocated_channels, nb_samples,
|
yading@11
|
195 a->sample_fmt, 0);
|
yading@11
|
196 if (ret < 0)
|
yading@11
|
197 return ret;
|
yading@11
|
198 }
|
yading@11
|
199 a->buffer_size = new_buf_size;
|
yading@11
|
200 a->allocated_samples = nb_samples;
|
yading@11
|
201
|
yading@11
|
202 calc_ptr_alignment(a);
|
yading@11
|
203 a->samples_align = plane_size / a->stride;
|
yading@11
|
204
|
yading@11
|
205 return 0;
|
yading@11
|
206 }
|
yading@11
|
207
|
yading@11
|
208 void ff_audio_data_free(AudioData **a)
|
yading@11
|
209 {
|
yading@11
|
210 if (!*a)
|
yading@11
|
211 return;
|
yading@11
|
212 av_free((*a)->buffer);
|
yading@11
|
213 av_freep(a);
|
yading@11
|
214 }
|
yading@11
|
215
|
yading@11
|
216 int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
|
yading@11
|
217 {
|
yading@11
|
218 int ret, p;
|
yading@11
|
219
|
yading@11
|
220 /* validate input/output compatibility */
|
yading@11
|
221 if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
|
yading@11
|
222 return AVERROR(EINVAL);
|
yading@11
|
223
|
yading@11
|
224 if (map && !src->is_planar) {
|
yading@11
|
225 av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
|
yading@11
|
226 return AVERROR(EINVAL);
|
yading@11
|
227 }
|
yading@11
|
228
|
yading@11
|
229 /* if the input is empty, just empty the output */
|
yading@11
|
230 if (!src->nb_samples) {
|
yading@11
|
231 dst->nb_samples = 0;
|
yading@11
|
232 return 0;
|
yading@11
|
233 }
|
yading@11
|
234
|
yading@11
|
235 /* reallocate output if necessary */
|
yading@11
|
236 ret = ff_audio_data_realloc(dst, src->nb_samples);
|
yading@11
|
237 if (ret < 0)
|
yading@11
|
238 return ret;
|
yading@11
|
239
|
yading@11
|
240 /* copy data */
|
yading@11
|
241 if (map) {
|
yading@11
|
242 if (map->do_remap) {
|
yading@11
|
243 for (p = 0; p < src->planes; p++) {
|
yading@11
|
244 if (map->channel_map[p] >= 0)
|
yading@11
|
245 memcpy(dst->data[p], src->data[map->channel_map[p]],
|
yading@11
|
246 src->nb_samples * src->stride);
|
yading@11
|
247 }
|
yading@11
|
248 }
|
yading@11
|
249 if (map->do_copy || map->do_zero) {
|
yading@11
|
250 for (p = 0; p < src->planes; p++) {
|
yading@11
|
251 if (map->channel_copy[p])
|
yading@11
|
252 memcpy(dst->data[p], dst->data[map->channel_copy[p]],
|
yading@11
|
253 src->nb_samples * src->stride);
|
yading@11
|
254 else if (map->channel_zero[p])
|
yading@11
|
255 av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
|
yading@11
|
256 1, dst->sample_fmt);
|
yading@11
|
257 }
|
yading@11
|
258 }
|
yading@11
|
259 } else {
|
yading@11
|
260 for (p = 0; p < src->planes; p++)
|
yading@11
|
261 memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
|
yading@11
|
262 }
|
yading@11
|
263
|
yading@11
|
264 dst->nb_samples = src->nb_samples;
|
yading@11
|
265
|
yading@11
|
266 return 0;
|
yading@11
|
267 }
|
yading@11
|
268
|
yading@11
|
269 int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
|
yading@11
|
270 int src_offset, int nb_samples)
|
yading@11
|
271 {
|
yading@11
|
272 int ret, p, dst_offset2, dst_move_size;
|
yading@11
|
273
|
yading@11
|
274 /* validate input/output compatibility */
|
yading@11
|
275 if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
|
yading@11
|
276 av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
|
yading@11
|
277 return AVERROR(EINVAL);
|
yading@11
|
278 }
|
yading@11
|
279
|
yading@11
|
280 /* validate offsets are within the buffer bounds */
|
yading@11
|
281 if (dst_offset < 0 || dst_offset > dst->nb_samples ||
|
yading@11
|
282 src_offset < 0 || src_offset > src->nb_samples) {
|
yading@11
|
283 av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
|
yading@11
|
284 src_offset, dst_offset);
|
yading@11
|
285 return AVERROR(EINVAL);
|
yading@11
|
286 }
|
yading@11
|
287
|
yading@11
|
288 /* check offsets and sizes to see if we can just do nothing and return */
|
yading@11
|
289 if (nb_samples > src->nb_samples - src_offset)
|
yading@11
|
290 nb_samples = src->nb_samples - src_offset;
|
yading@11
|
291 if (nb_samples <= 0)
|
yading@11
|
292 return 0;
|
yading@11
|
293
|
yading@11
|
294 /* validate that the output is not read-only */
|
yading@11
|
295 if (dst->read_only) {
|
yading@11
|
296 av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
|
yading@11
|
297 return AVERROR(EINVAL);
|
yading@11
|
298 }
|
yading@11
|
299
|
yading@11
|
300 /* reallocate output if necessary */
|
yading@11
|
301 ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
|
yading@11
|
302 if (ret < 0) {
|
yading@11
|
303 av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
|
yading@11
|
304 return ret;
|
yading@11
|
305 }
|
yading@11
|
306
|
yading@11
|
307 dst_offset2 = dst_offset + nb_samples;
|
yading@11
|
308 dst_move_size = dst->nb_samples - dst_offset;
|
yading@11
|
309
|
yading@11
|
310 for (p = 0; p < src->planes; p++) {
|
yading@11
|
311 if (dst_move_size > 0) {
|
yading@11
|
312 memmove(dst->data[p] + dst_offset2 * dst->stride,
|
yading@11
|
313 dst->data[p] + dst_offset * dst->stride,
|
yading@11
|
314 dst_move_size * dst->stride);
|
yading@11
|
315 }
|
yading@11
|
316 memcpy(dst->data[p] + dst_offset * dst->stride,
|
yading@11
|
317 src->data[p] + src_offset * src->stride,
|
yading@11
|
318 nb_samples * src->stride);
|
yading@11
|
319 }
|
yading@11
|
320 dst->nb_samples += nb_samples;
|
yading@11
|
321
|
yading@11
|
322 return 0;
|
yading@11
|
323 }
|
yading@11
|
324
|
yading@11
|
325 void ff_audio_data_drain(AudioData *a, int nb_samples)
|
yading@11
|
326 {
|
yading@11
|
327 if (a->nb_samples <= nb_samples) {
|
yading@11
|
328 /* drain the whole buffer */
|
yading@11
|
329 a->nb_samples = 0;
|
yading@11
|
330 } else {
|
yading@11
|
331 int p;
|
yading@11
|
332 int move_offset = a->stride * nb_samples;
|
yading@11
|
333 int move_size = a->stride * (a->nb_samples - nb_samples);
|
yading@11
|
334
|
yading@11
|
335 for (p = 0; p < a->planes; p++)
|
yading@11
|
336 memmove(a->data[p], a->data[p] + move_offset, move_size);
|
yading@11
|
337
|
yading@11
|
338 a->nb_samples -= nb_samples;
|
yading@11
|
339 }
|
yading@11
|
340 }
|
yading@11
|
341
|
yading@11
|
342 int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
|
yading@11
|
343 int nb_samples)
|
yading@11
|
344 {
|
yading@11
|
345 uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
|
yading@11
|
346 int offset_size, p;
|
yading@11
|
347
|
yading@11
|
348 if (offset >= a->nb_samples)
|
yading@11
|
349 return 0;
|
yading@11
|
350 offset_size = offset * a->stride;
|
yading@11
|
351 for (p = 0; p < a->planes; p++)
|
yading@11
|
352 offset_data[p] = a->data[p] + offset_size;
|
yading@11
|
353
|
yading@11
|
354 return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
|
yading@11
|
355 }
|
yading@11
|
356
|
yading@11
|
357 int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples)
|
yading@11
|
358 {
|
yading@11
|
359 int ret;
|
yading@11
|
360
|
yading@11
|
361 if (a->read_only)
|
yading@11
|
362 return AVERROR(EINVAL);
|
yading@11
|
363
|
yading@11
|
364 ret = ff_audio_data_realloc(a, nb_samples);
|
yading@11
|
365 if (ret < 0)
|
yading@11
|
366 return ret;
|
yading@11
|
367
|
yading@11
|
368 ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
|
yading@11
|
369 if (ret >= 0)
|
yading@11
|
370 a->nb_samples = ret;
|
yading@11
|
371 return ret;
|
yading@11
|
372 }
|