2 * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
4 * This file is part of FFmpeg.
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.
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.
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
24 #include "libavutil/mem.h"
25 #include "audio_data.h"
27 static const AVClass audio_data_class
= {
28 .class_name
= "AudioData",
29 .item_name
= av_default_item_name
,
30 .version
= LIBAVUTIL_VERSION_INT
,
34 * Calculate alignment for data pointers.
36 static void calc_ptr_alignment(AudioData
*a
)
41 for (p
= 0; p
< a
->planes
; p
++) {
43 while ((intptr_t)a
->data
[p
] % cur_align
)
45 if (cur_align
< min_align
)
46 min_align
= cur_align
;
48 a
->ptr_align
= min_align
;
51 int ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt
, int channels
)
56 return av_sample_fmt_is_planar(sample_fmt
);
59 int ff_audio_data_set_channels(AudioData
*a
, int channels
)
61 if (channels
< 1 || channels
> AVRESAMPLE_MAX_CHANNELS
||
62 channels
> a
->allocated_channels
)
63 return AVERROR(EINVAL
);
65 a
->channels
= channels
;
66 a
->planes
= a
->is_planar
? channels
: 1;
68 calc_ptr_alignment(a
);
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
)
79 memset(a
, 0, sizeof(*a
));
80 a
->class = &audio_data_class
;
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
);
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
);
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
);
96 for (p
= 0; p
< (a
->is_planar
? channels
: 1); p
++) {
98 av_log(a
, AV_LOG_ERROR
, "invalid NULL pointer for src[%d]\n", p
);
99 return AVERROR(EINVAL
);
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}";
112 calc_ptr_alignment(a
);
113 a
->samples_align
= plane_size
/ a
->stride
;
118 AudioData
*ff_audio_data_alloc(int channels
, int nb_samples
,
119 enum AVSampleFormat sample_fmt
, const char *name
)
124 if (channels
< 1 || channels
> AVRESAMPLE_MAX_CHANNELS
)
127 a
= av_mallocz(sizeof(*a
));
131 a
->sample_size
= av_get_bytes_per_sample(sample_fmt
);
132 if (!a
->sample_size
) {
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
);
140 a
->class = &audio_data_class
;
141 a
->sample_fmt
= sample_fmt
;
142 a
->channels
= channels
;
143 a
->allocated_channels
= channels
;
145 a
->allow_realloc
= 1;
146 a
->name
= name
? name
: "{no name}";
148 if (nb_samples
> 0) {
149 ret
= ff_audio_data_realloc(a
, nb_samples
);
156 calc_ptr_alignment(a
);
161 int ff_audio_data_realloc(AudioData
*a
, int nb_samples
)
163 int ret
, new_buf_size
, plane_size
, p
;
165 /* check if buffer is already large enough */
166 if (a
->allocated_samples
>= nb_samples
)
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
);
173 new_buf_size
= av_samples_get_buffer_size(&plane_size
,
174 a
->allocated_channels
, nb_samples
,
176 if (new_buf_size
< 0)
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
};
185 ret
= av_samples_alloc(new_data
, &plane_size
, a
->allocated_channels
,
186 nb_samples
, a
->sample_fmt
, 0);
190 for (p
= 0; p
< a
->planes
; p
++)
191 memcpy(new_data
[p
], a
->data
[p
], a
->nb_samples
* a
->stride
);
193 av_freep(&a
->buffer
);
194 memcpy(a
->data
, new_data
, sizeof(new_data
));
195 a
->buffer
= a
->data
[0];
197 av_freep(&a
->buffer
);
198 a
->buffer
= av_malloc(new_buf_size
);
200 return AVERROR(ENOMEM
);
201 ret
= av_samples_fill_arrays(a
->data
, &plane_size
, a
->buffer
,
202 a
->allocated_channels
, nb_samples
,
207 a
->buffer_size
= new_buf_size
;
208 a
->allocated_samples
= nb_samples
;
210 calc_ptr_alignment(a
);
211 a
->samples_align
= plane_size
/ a
->stride
;
216 void ff_audio_data_free(AudioData
**a
)
220 av_free((*a
)->buffer
);
224 int ff_audio_data_copy(AudioData
*dst
, AudioData
*src
, ChannelMapInfo
*map
)
228 /* validate input/output compatibility */
229 if (dst
->sample_fmt
!= src
->sample_fmt
|| dst
->channels
< src
->channels
)
230 return AVERROR(EINVAL
);
232 if (map
&& !src
->is_planar
) {
233 av_log(src
, AV_LOG_ERROR
, "cannot remap packed format during copy\n");
234 return AVERROR(EINVAL
);
237 /* if the input is empty, just empty the output */
238 if (!src
->nb_samples
) {
243 /* reallocate output if necessary */
244 ret
= ff_audio_data_realloc(dst
, src
->nb_samples
);
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
);
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
,
268 for (p
= 0; p
< src
->planes
; p
++)
269 memcpy(dst
->data
[p
], src
->data
[p
], src
->nb_samples
* src
->stride
);
272 dst
->nb_samples
= src
->nb_samples
;
277 int ff_audio_data_combine(AudioData
*dst
, int dst_offset
, AudioData
*src
,
278 int src_offset
, int nb_samples
)
280 int ret
, p
, dst_offset2
, dst_move_size
;
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
);
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
);
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
;
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
);
308 /* reallocate output if necessary */
309 ret
= ff_audio_data_realloc(dst
, dst
->nb_samples
+ nb_samples
);
311 av_log(dst
, AV_LOG_ERROR
, "error reallocating dst\n");
315 dst_offset2
= dst_offset
+ nb_samples
;
316 dst_move_size
= dst
->nb_samples
- dst_offset
;
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
);
324 memcpy(dst
->data
[p
] + dst_offset
* dst
->stride
,
325 src
->data
[p
] + src_offset
* src
->stride
,
326 nb_samples
* src
->stride
);
328 dst
->nb_samples
+= nb_samples
;
333 void ff_audio_data_drain(AudioData
*a
, int nb_samples
)
335 if (a
->nb_samples
<= nb_samples
) {
336 /* drain the whole buffer */
340 int move_offset
= a
->stride
* nb_samples
;
341 int move_size
= a
->stride
* (a
->nb_samples
- nb_samples
);
343 for (p
= 0; p
< a
->planes
; p
++)
344 memmove(a
->data
[p
], a
->data
[p
] + move_offset
, move_size
);
346 a
->nb_samples
-= nb_samples
;
350 int ff_audio_data_add_to_fifo(AVAudioFifo
*af
, AudioData
*a
, int offset
,
353 uint8_t *offset_data
[AVRESAMPLE_MAX_CHANNELS
];
356 if (offset
>= a
->nb_samples
)
358 offset_size
= offset
* a
->stride
;
359 for (p
= 0; p
< a
->planes
; p
++)
360 offset_data
[p
] = a
->data
[p
] + offset_size
;
362 return av_audio_fifo_write(af
, (void **)offset_data
, nb_samples
);
365 int ff_audio_data_read_from_fifo(AVAudioFifo
*af
, AudioData
*a
, int nb_samples
)
370 return AVERROR(EINVAL
);
372 ret
= ff_audio_data_realloc(a
, nb_samples
);
376 ret
= av_audio_fifo_read(af
, (void **)a
->data
, nb_samples
);