yading@11: /* yading@11: * Audio FIFO 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: /** yading@11: * @file yading@11: * Audio FIFO yading@11: */ yading@11: yading@11: #include "avutil.h" yading@11: #include "audio_fifo.h" yading@11: #include "common.h" yading@11: #include "fifo.h" yading@11: #include "mem.h" yading@11: #include "samplefmt.h" yading@11: yading@11: struct AVAudioFifo { yading@11: AVFifoBuffer **buf; /**< single buffer for interleaved, per-channel buffers for planar */ yading@11: int nb_buffers; /**< number of buffers */ yading@11: int nb_samples; /**< number of samples currently in the FIFO */ yading@11: int allocated_samples; /**< current allocated size, in samples */ yading@11: yading@11: int channels; /**< number of channels */ yading@11: enum AVSampleFormat sample_fmt; /**< sample format */ yading@11: int sample_size; /**< size, in bytes, of one sample in a buffer */ yading@11: }; yading@11: yading@11: void av_audio_fifo_free(AVAudioFifo *af) yading@11: { yading@11: if (af) { yading@11: if (af->buf) { yading@11: int i; yading@11: for (i = 0; i < af->nb_buffers; i++) { yading@11: if (af->buf[i]) yading@11: av_fifo_free(af->buf[i]); yading@11: } yading@11: av_free(af->buf); yading@11: } yading@11: av_free(af); yading@11: } yading@11: } yading@11: yading@11: AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, yading@11: int nb_samples) yading@11: { yading@11: AVAudioFifo *af; yading@11: int buf_size, i; yading@11: yading@11: /* get channel buffer size (also validates parameters) */ yading@11: if (av_samples_get_buffer_size(&buf_size, channels, nb_samples, sample_fmt, 1) < 0) yading@11: return NULL; yading@11: yading@11: af = av_mallocz(sizeof(*af)); yading@11: if (!af) yading@11: return NULL; yading@11: yading@11: af->channels = channels; yading@11: af->sample_fmt = sample_fmt; yading@11: af->sample_size = buf_size / nb_samples; yading@11: af->nb_buffers = av_sample_fmt_is_planar(sample_fmt) ? channels : 1; yading@11: yading@11: af->buf = av_mallocz(af->nb_buffers * sizeof(*af->buf)); yading@11: if (!af->buf) yading@11: goto error; yading@11: yading@11: for (i = 0; i < af->nb_buffers; i++) { yading@11: af->buf[i] = av_fifo_alloc(buf_size); yading@11: if (!af->buf[i]) yading@11: goto error; yading@11: } yading@11: af->allocated_samples = nb_samples; yading@11: yading@11: return af; yading@11: yading@11: error: yading@11: av_audio_fifo_free(af); yading@11: return NULL; yading@11: } yading@11: yading@11: int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples) yading@11: { yading@11: int i, ret, buf_size; yading@11: yading@11: if ((ret = av_samples_get_buffer_size(&buf_size, af->channels, nb_samples, yading@11: af->sample_fmt, 1)) < 0) yading@11: return ret; yading@11: yading@11: for (i = 0; i < af->nb_buffers; i++) { yading@11: if ((ret = av_fifo_realloc2(af->buf[i], buf_size)) < 0) yading@11: return ret; yading@11: } yading@11: af->allocated_samples = nb_samples; yading@11: return 0; yading@11: } yading@11: yading@11: int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples) yading@11: { yading@11: int i, ret, size; yading@11: yading@11: /* automatically reallocate buffers if needed */ yading@11: if (av_audio_fifo_space(af) < nb_samples) { yading@11: int current_size = av_audio_fifo_size(af); yading@11: /* check for integer overflow in new size calculation */ yading@11: if (INT_MAX / 2 - current_size < nb_samples) yading@11: return AVERROR(EINVAL); yading@11: /* reallocate buffers */ yading@11: if ((ret = av_audio_fifo_realloc(af, 2 * (current_size + nb_samples))) < 0) yading@11: return ret; yading@11: } yading@11: yading@11: size = nb_samples * af->sample_size; yading@11: for (i = 0; i < af->nb_buffers; i++) { yading@11: ret = av_fifo_generic_write(af->buf[i], data[i], size, NULL); yading@11: if (ret != size) yading@11: return AVERROR_BUG; yading@11: } yading@11: af->nb_samples += nb_samples; yading@11: yading@11: return nb_samples; yading@11: } yading@11: yading@11: int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples) yading@11: { yading@11: int i, ret, size; yading@11: yading@11: if (nb_samples < 0) yading@11: return AVERROR(EINVAL); yading@11: nb_samples = FFMIN(nb_samples, af->nb_samples); yading@11: if (!nb_samples) yading@11: return 0; yading@11: yading@11: size = nb_samples * af->sample_size; yading@11: for (i = 0; i < af->nb_buffers; i++) { yading@11: if ((ret = av_fifo_generic_read(af->buf[i], data[i], size, NULL)) < 0) yading@11: return AVERROR_BUG; yading@11: } yading@11: af->nb_samples -= nb_samples; yading@11: yading@11: return nb_samples; yading@11: } yading@11: yading@11: int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples) yading@11: { yading@11: int i, size; yading@11: yading@11: if (nb_samples < 0) yading@11: return AVERROR(EINVAL); yading@11: nb_samples = FFMIN(nb_samples, af->nb_samples); yading@11: yading@11: if (nb_samples) { yading@11: size = nb_samples * af->sample_size; yading@11: for (i = 0; i < af->nb_buffers; i++) yading@11: av_fifo_drain(af->buf[i], size); yading@11: af->nb_samples -= nb_samples; yading@11: } yading@11: return 0; yading@11: } yading@11: yading@11: void av_audio_fifo_reset(AVAudioFifo *af) yading@11: { yading@11: int i; yading@11: yading@11: for (i = 0; i < af->nb_buffers; i++) yading@11: av_fifo_reset(af->buf[i]); yading@11: yading@11: af->nb_samples = 0; yading@11: } yading@11: yading@11: int av_audio_fifo_size(AVAudioFifo *af) yading@11: { yading@11: return af->nb_samples; yading@11: } yading@11: yading@11: int av_audio_fifo_space(AVAudioFifo *af) yading@11: { yading@11: return af->allocated_samples - af->nb_samples; yading@11: }