From 0c0d1bce7c582b82e49843acaa7d0fb4b1774b21 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Fri, 23 Mar 2012 17:45:48 -0400 Subject: avutil: add audio fifo buffer The functions operate on the sample level rather than the byte level and work with all audio sample formats. --- doc/APIchanges | 12 +++ libavutil/Makefile | 2 + libavutil/audio_fifo.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ libavutil/audio_fifo.h | 146 +++++++++++++++++++++++++++++++++++++ libavutil/avutil.h | 4 +- 5 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 libavutil/audio_fifo.c create mode 100644 libavutil/audio_fifo.h diff --git a/doc/APIchanges b/doc/APIchanges index 5114e14191..fed77b0eb5 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -12,6 +12,18 @@ libavutil: 2011-04-18 API changes, most recent first: +2012-xx-xx - xxxxxxx - lavu 51.28.0 - audio_fifo.h + Add audio FIFO functions: + av_audio_fifo_free() + av_audio_fifo_alloc() + av_audio_fifo_realloc() + av_audio_fifo_write() + av_audio_fifo_read() + av_audio_fifo_drain() + av_audio_fifo_reset() + av_audio_fifo_size() + av_audio_fifo_space() + 2012-xx-xx - xxxxxxx - lavfi 2.16.0 - avfiltergraph.h Add avfilter_graph_parse2(), avfilter_inout_alloc() and avfilter_inout_free() functions. diff --git a/libavutil/Makefile b/libavutil/Makefile index 820abb1429..69f2acd72e 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -3,6 +3,7 @@ NAME = avutil HEADERS = adler32.h \ aes.h \ attributes.h \ + audio_fifo.h \ audioconvert.h \ avassert.h \ avstring.h \ @@ -40,6 +41,7 @@ BUILT_HEADERS = avconfig.h OBJS = adler32.o \ aes.o \ + audio_fifo.o \ audioconvert.o \ avstring.o \ base64.o \ diff --git a/libavutil/audio_fifo.c b/libavutil/audio_fifo.c new file mode 100644 index 0000000000..97c51a72c1 --- /dev/null +++ b/libavutil/audio_fifo.c @@ -0,0 +1,193 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO + */ + +#include "avutil.h" +#include "audio_fifo.h" +#include "fifo.h" +#include "mem.h" +#include "samplefmt.h" + +struct AVAudioFifo { + AVFifoBuffer **buf; /**< single buffer for interleaved, per-channel buffers for planar */ + int nb_buffers; /**< number of buffers */ + int nb_samples; /**< number of samples currently in the FIFO */ + int allocated_samples; /**< current allocated size, in samples */ + + int channels; /**< number of channels */ + enum AVSampleFormat sample_fmt; /**< sample format */ + int sample_size; /**< size, in bytes, of one sample in a buffer */ +}; + +void av_audio_fifo_free(AVAudioFifo *af) +{ + if (af) { + if (af->buf) { + int i; + for (i = 0; i < af->nb_buffers; i++) { + if (af->buf[i]) + av_fifo_free(af->buf[i]); + } + av_free(af->buf); + } + av_free(af); + } +} + +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples) +{ + AVAudioFifo *af; + int buf_size, i; + + /* get channel buffer size (also validates parameters) */ + if (av_samples_get_buffer_size(&buf_size, channels, nb_samples, sample_fmt, 1) < 0) + return NULL; + + af = av_mallocz(sizeof(*af)); + if (!af) + return NULL; + + af->channels = channels; + af->sample_fmt = sample_fmt; + af->sample_size = buf_size / nb_samples; + af->nb_buffers = av_sample_fmt_is_planar(sample_fmt) ? channels : 1; + + af->buf = av_mallocz(af->nb_buffers * sizeof(*af->buf)); + if (!af->buf) + goto error; + + for (i = 0; i < af->nb_buffers; i++) { + af->buf[i] = av_fifo_alloc(buf_size); + if (!af->buf[i]) + goto error; + } + af->allocated_samples = nb_samples; + + return af; + +error: + av_audio_fifo_free(af); + return NULL; +} + +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples) +{ + int i, ret, buf_size; + + if ((ret = av_samples_get_buffer_size(&buf_size, af->channels, nb_samples, + af->sample_fmt, 1)) < 0) + return ret; + + for (i = 0; i < af->nb_buffers; i++) { + if ((ret = av_fifo_realloc2(af->buf[i], buf_size)) < 0) + return ret; + } + af->allocated_samples = nb_samples; + return 0; +} + +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples) +{ + int i, ret, size; + + /* automatically reallocate buffers if needed */ + if (av_audio_fifo_space(af) < nb_samples) { + int current_size = av_audio_fifo_size(af); + /* check for integer overflow in new size calculation */ + if (INT_MAX / 2 - current_size < nb_samples) + return AVERROR(EINVAL); + /* reallocate buffers */ + if ((ret = av_audio_fifo_realloc(af, 2 * (current_size + nb_samples))) < 0) + return ret; + } + + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + ret = av_fifo_generic_write(af->buf[i], data[i], size, NULL); + if (ret != size) + return AVERROR_BUG; + } + af->nb_samples += nb_samples; + + return nb_samples; +} + +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples) +{ + int i, ret, size; + + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + if (!nb_samples) + return 0; + + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + if ((ret = av_fifo_generic_read(af->buf[i], data[i], size, NULL)) < 0) + return AVERROR_BUG; + } + af->nb_samples -= nb_samples; + + return nb_samples; +} + +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples) +{ + int i, size; + + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + + if (nb_samples) { + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) + av_fifo_drain(af->buf[i], size); + af->nb_samples -= nb_samples; + } + return 0; +} + +void av_audio_fifo_reset(AVAudioFifo *af) +{ + int i; + + for (i = 0; i < af->nb_buffers; i++) + av_fifo_reset(af->buf[i]); + + af->nb_samples = 0; +} + +int av_audio_fifo_size(AVAudioFifo *af) +{ + return af->nb_samples; +} + +int av_audio_fifo_space(AVAudioFifo *af) +{ + return af->allocated_samples - af->nb_samples; +} diff --git a/libavutil/audio_fifo.h b/libavutil/audio_fifo.h new file mode 100644 index 0000000000..8c76388255 --- /dev/null +++ b/libavutil/audio_fifo.h @@ -0,0 +1,146 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "avutil.h" +#include "fifo.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. + */ +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. + */ +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ diff --git a/libavutil/avutil.h b/libavutil/avutil.h index 7319c22bfa..6673f0f53b 100644 --- a/libavutil/avutil.h +++ b/libavutil/avutil.h @@ -152,8 +152,8 @@ */ #define LIBAVUTIL_VERSION_MAJOR 51 -#define LIBAVUTIL_VERSION_MINOR 27 -#define LIBAVUTIL_VERSION_MICRO 2 +#define LIBAVUTIL_VERSION_MINOR 28 +#define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ LIBAVUTIL_VERSION_MINOR, \ -- cgit v1.2.3