yading@11: /* yading@11: * Copyright (c) 2012 Justin Ruggles yading@11: * yading@11: * This file is part of Libav. yading@11: * yading@11: * Libav is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * Libav is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with Libav; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: #include yading@11: #include yading@11: yading@11: #include "libavutil/mem.h" yading@11: #include "audio_data.h" yading@11: yading@11: static const AVClass audio_data_class = { yading@11: .class_name = "AudioData", yading@11: .item_name = av_default_item_name, yading@11: .version = LIBAVUTIL_VERSION_INT, yading@11: }; yading@11: yading@11: /* yading@11: * Calculate alignment for data pointers. yading@11: */ yading@11: static void calc_ptr_alignment(AudioData *a) yading@11: { yading@11: int p; yading@11: int min_align = 128; yading@11: yading@11: for (p = 0; p < a->planes; p++) { yading@11: int cur_align = 128; yading@11: while ((intptr_t)a->data[p] % cur_align) yading@11: cur_align >>= 1; yading@11: if (cur_align < min_align) yading@11: min_align = cur_align; yading@11: } yading@11: a->ptr_align = min_align; yading@11: } yading@11: yading@11: int ff_audio_data_set_channels(AudioData *a, int channels) yading@11: { yading@11: if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS || yading@11: channels > a->allocated_channels) yading@11: return AVERROR(EINVAL); yading@11: yading@11: a->channels = channels; yading@11: a->planes = a->is_planar ? channels : 1; yading@11: yading@11: calc_ptr_alignment(a); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: int ff_audio_data_init(AudioData *a, uint8_t **src, int plane_size, int channels, yading@11: int nb_samples, enum AVSampleFormat sample_fmt, yading@11: int read_only, const char *name) yading@11: { yading@11: int p; yading@11: yading@11: memset(a, 0, sizeof(*a)); yading@11: a->class = &audio_data_class; yading@11: yading@11: if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) { yading@11: av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: yading@11: a->sample_size = av_get_bytes_per_sample(sample_fmt); yading@11: if (!a->sample_size) { yading@11: av_log(a, AV_LOG_ERROR, "invalid sample format\n"); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: a->is_planar = av_sample_fmt_is_planar(sample_fmt); yading@11: a->planes = a->is_planar ? channels : 1; yading@11: a->stride = a->sample_size * (a->is_planar ? 1 : channels); yading@11: yading@11: for (p = 0; p < (a->is_planar ? channels : 1); p++) { yading@11: if (!src[p]) { yading@11: av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: a->data[p] = src[p]; yading@11: } yading@11: a->allocated_samples = nb_samples * !read_only; yading@11: a->nb_samples = nb_samples; yading@11: a->sample_fmt = sample_fmt; yading@11: a->channels = channels; yading@11: a->allocated_channels = channels; yading@11: a->read_only = read_only; yading@11: a->allow_realloc = 0; yading@11: a->name = name ? name : "{no name}"; yading@11: yading@11: calc_ptr_alignment(a); yading@11: a->samples_align = plane_size / a->stride; yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: AudioData *ff_audio_data_alloc(int channels, int nb_samples, yading@11: enum AVSampleFormat sample_fmt, const char *name) yading@11: { yading@11: AudioData *a; yading@11: int ret; yading@11: yading@11: if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) yading@11: return NULL; yading@11: yading@11: a = av_mallocz(sizeof(*a)); yading@11: if (!a) yading@11: return NULL; yading@11: yading@11: a->sample_size = av_get_bytes_per_sample(sample_fmt); yading@11: if (!a->sample_size) { yading@11: av_free(a); yading@11: return NULL; yading@11: } yading@11: a->is_planar = av_sample_fmt_is_planar(sample_fmt); yading@11: a->planes = a->is_planar ? channels : 1; yading@11: a->stride = a->sample_size * (a->is_planar ? 1 : channels); yading@11: yading@11: a->class = &audio_data_class; yading@11: a->sample_fmt = sample_fmt; yading@11: a->channels = channels; yading@11: a->allocated_channels = channels; yading@11: a->read_only = 0; yading@11: a->allow_realloc = 1; yading@11: a->name = name ? name : "{no name}"; yading@11: yading@11: if (nb_samples > 0) { yading@11: ret = ff_audio_data_realloc(a, nb_samples); yading@11: if (ret < 0) { yading@11: av_free(a); yading@11: return NULL; yading@11: } yading@11: return a; yading@11: } else { yading@11: calc_ptr_alignment(a); yading@11: return a; yading@11: } yading@11: } yading@11: yading@11: int ff_audio_data_realloc(AudioData *a, int nb_samples) yading@11: { yading@11: int ret, new_buf_size, plane_size, p; yading@11: yading@11: /* check if buffer is already large enough */ yading@11: if (a->allocated_samples >= nb_samples) yading@11: return 0; yading@11: yading@11: /* validate that the output is not read-only and realloc is allowed */ yading@11: if (a->read_only || !a->allow_realloc) yading@11: return AVERROR(EINVAL); yading@11: yading@11: new_buf_size = av_samples_get_buffer_size(&plane_size, yading@11: a->allocated_channels, nb_samples, yading@11: a->sample_fmt, 0); yading@11: if (new_buf_size < 0) yading@11: return new_buf_size; yading@11: yading@11: /* if there is already data in the buffer and the sample format is planar, yading@11: allocate a new buffer and copy the data, otherwise just realloc the yading@11: internal buffer and set new data pointers */ yading@11: if (a->nb_samples > 0 && a->is_planar) { yading@11: uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL }; yading@11: yading@11: ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels, yading@11: nb_samples, a->sample_fmt, 0); yading@11: if (ret < 0) yading@11: return ret; yading@11: yading@11: for (p = 0; p < a->planes; p++) yading@11: memcpy(new_data[p], a->data[p], a->nb_samples * a->stride); yading@11: yading@11: av_freep(&a->buffer); yading@11: memcpy(a->data, new_data, sizeof(new_data)); yading@11: a->buffer = a->data[0]; yading@11: } else { yading@11: av_freep(&a->buffer); yading@11: a->buffer = av_malloc(new_buf_size); yading@11: if (!a->buffer) yading@11: return AVERROR(ENOMEM); yading@11: ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer, yading@11: a->allocated_channels, nb_samples, yading@11: a->sample_fmt, 0); yading@11: if (ret < 0) yading@11: return ret; yading@11: } yading@11: a->buffer_size = new_buf_size; yading@11: a->allocated_samples = nb_samples; yading@11: yading@11: calc_ptr_alignment(a); yading@11: a->samples_align = plane_size / a->stride; yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: void ff_audio_data_free(AudioData **a) yading@11: { yading@11: if (!*a) yading@11: return; yading@11: av_free((*a)->buffer); yading@11: av_freep(a); yading@11: } yading@11: yading@11: int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map) yading@11: { yading@11: int ret, p; yading@11: yading@11: /* validate input/output compatibility */ yading@11: if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels) yading@11: return AVERROR(EINVAL); yading@11: yading@11: if (map && !src->is_planar) { yading@11: av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n"); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: yading@11: /* if the input is empty, just empty the output */ yading@11: if (!src->nb_samples) { yading@11: dst->nb_samples = 0; yading@11: return 0; yading@11: } yading@11: yading@11: /* reallocate output if necessary */ yading@11: ret = ff_audio_data_realloc(dst, src->nb_samples); yading@11: if (ret < 0) yading@11: return ret; yading@11: yading@11: /* copy data */ yading@11: if (map) { yading@11: if (map->do_remap) { yading@11: for (p = 0; p < src->planes; p++) { yading@11: if (map->channel_map[p] >= 0) yading@11: memcpy(dst->data[p], src->data[map->channel_map[p]], yading@11: src->nb_samples * src->stride); yading@11: } yading@11: } yading@11: if (map->do_copy || map->do_zero) { yading@11: for (p = 0; p < src->planes; p++) { yading@11: if (map->channel_copy[p]) yading@11: memcpy(dst->data[p], dst->data[map->channel_copy[p]], yading@11: src->nb_samples * src->stride); yading@11: else if (map->channel_zero[p]) yading@11: av_samples_set_silence(&dst->data[p], 0, src->nb_samples, yading@11: 1, dst->sample_fmt); yading@11: } yading@11: } yading@11: } else { yading@11: for (p = 0; p < src->planes; p++) yading@11: memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride); yading@11: } yading@11: yading@11: dst->nb_samples = src->nb_samples; yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src, yading@11: int src_offset, int nb_samples) yading@11: { yading@11: int ret, p, dst_offset2, dst_move_size; yading@11: yading@11: /* validate input/output compatibility */ yading@11: if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) { yading@11: av_log(src, AV_LOG_ERROR, "sample format mismatch\n"); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: yading@11: /* validate offsets are within the buffer bounds */ yading@11: if (dst_offset < 0 || dst_offset > dst->nb_samples || yading@11: src_offset < 0 || src_offset > src->nb_samples) { yading@11: av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n", yading@11: src_offset, dst_offset); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: yading@11: /* check offsets and sizes to see if we can just do nothing and return */ yading@11: if (nb_samples > src->nb_samples - src_offset) yading@11: nb_samples = src->nb_samples - src_offset; yading@11: if (nb_samples <= 0) yading@11: return 0; yading@11: yading@11: /* validate that the output is not read-only */ yading@11: if (dst->read_only) { yading@11: av_log(dst, AV_LOG_ERROR, "dst is read-only\n"); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: yading@11: /* reallocate output if necessary */ yading@11: ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples); yading@11: if (ret < 0) { yading@11: av_log(dst, AV_LOG_ERROR, "error reallocating dst\n"); yading@11: return ret; yading@11: } yading@11: yading@11: dst_offset2 = dst_offset + nb_samples; yading@11: dst_move_size = dst->nb_samples - dst_offset; yading@11: yading@11: for (p = 0; p < src->planes; p++) { yading@11: if (dst_move_size > 0) { yading@11: memmove(dst->data[p] + dst_offset2 * dst->stride, yading@11: dst->data[p] + dst_offset * dst->stride, yading@11: dst_move_size * dst->stride); yading@11: } yading@11: memcpy(dst->data[p] + dst_offset * dst->stride, yading@11: src->data[p] + src_offset * src->stride, yading@11: nb_samples * src->stride); yading@11: } yading@11: dst->nb_samples += nb_samples; yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: void ff_audio_data_drain(AudioData *a, int nb_samples) yading@11: { yading@11: if (a->nb_samples <= nb_samples) { yading@11: /* drain the whole buffer */ yading@11: a->nb_samples = 0; yading@11: } else { yading@11: int p; yading@11: int move_offset = a->stride * nb_samples; yading@11: int move_size = a->stride * (a->nb_samples - nb_samples); yading@11: yading@11: for (p = 0; p < a->planes; p++) yading@11: memmove(a->data[p], a->data[p] + move_offset, move_size); yading@11: yading@11: a->nb_samples -= nb_samples; yading@11: } yading@11: } yading@11: yading@11: int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, yading@11: int nb_samples) yading@11: { yading@11: uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS]; yading@11: int offset_size, p; yading@11: yading@11: if (offset >= a->nb_samples) yading@11: return 0; yading@11: offset_size = offset * a->stride; yading@11: for (p = 0; p < a->planes; p++) yading@11: offset_data[p] = a->data[p] + offset_size; yading@11: yading@11: return av_audio_fifo_write(af, (void **)offset_data, nb_samples); yading@11: } yading@11: yading@11: int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples) yading@11: { yading@11: int ret; yading@11: yading@11: if (a->read_only) yading@11: return AVERROR(EINVAL); yading@11: yading@11: ret = ff_audio_data_realloc(a, nb_samples); yading@11: if (ret < 0) yading@11: return ret; yading@11: yading@11: ret = av_audio_fifo_read(af, (void **)a->data, nb_samples); yading@11: if (ret >= 0) yading@11: a->nb_samples = ret; yading@11: return ret; yading@11: }