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 27static 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 */ 36static void calc_ptr_alignment(AudioData *a) 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 51int ff_audio_data_set_channels(AudioData *a, int channels) 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 60 calc_ptr_alignment(a); 61 62 return 0; 63} 64 65int 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 104 calc_ptr_alignment(a); 105 a->samples_align = plane_size / a->stride; 106 107 return 0; 108} 109 110AudioData *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 { 148 calc_ptr_alignment(a); 149 return a; 150 } 151} 152 153int 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 202 calc_ptr_alignment(a); 203 a->samples_align = plane_size / a->stride; 204 205 return 0; 206} 207 208void ff_audio_data_free(AudioData **a) 209{ 210 if (!*a) 211 return; 212 av_free((*a)->buffer); 213 av_freep(a); 214} 215 216int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map) 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 269int 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 325void 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 342int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, 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 357int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples) 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} 373